Compare commits
74 Commits
v8.2.0-rc2
...
tdx-qemu-u
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d20f93da31 | ||
|
|
18f152401f | ||
|
|
5c8d76a6e4 | ||
|
|
f226ab5a34 | ||
|
|
e954cd4b22 | ||
|
|
2dbde0df24 | ||
|
|
9faa2b03a9 | ||
|
|
d04ea558aa | ||
|
|
378e61b145 | ||
|
|
fdd53e1a81 | ||
|
|
e1ce29aa33 | ||
|
|
ffe9a6dccb | ||
|
|
7163da7797 | ||
|
|
a5368c6202 | ||
|
|
f597afe309 | ||
|
|
a23e29229e | ||
|
|
addb6b676d | ||
|
|
824f58fdba | ||
|
|
9955e91601 | ||
|
|
80417c539e | ||
|
|
511b09205f | ||
|
|
85a8152691 | ||
|
|
08c095f67a | ||
|
|
d8da77238e | ||
|
|
ab857b85a5 | ||
|
|
517fb00637 | ||
|
|
359be44b10 | ||
|
|
0222b6f05d | ||
|
|
8b7763f7ca | ||
|
|
33edcc8426 | ||
|
|
19195c88df | ||
|
|
954b9e7a42 | ||
|
|
5aad9329d2 | ||
|
|
583aae3302 | ||
|
|
80af3f2547 | ||
|
|
ef90193248 | ||
|
|
769b8158f6 | ||
|
|
d7db7d2ea1 | ||
|
|
004db71f60 | ||
|
|
bbe50409ce | ||
|
|
2ac24a3f82 | ||
|
|
7671a8d293 | ||
|
|
5bf04c14d8 | ||
|
|
f503878704 | ||
|
|
98f599ec0b | ||
|
|
a1b994d89a | ||
|
|
04fc588ea9 | ||
|
|
7e454d2ca4 | ||
|
|
b4a0470949 | ||
|
|
5fdefc08b3 | ||
|
|
d54122cefb | ||
|
|
ef64621235 | ||
|
|
575bfcd358 | ||
|
|
38b04243ce | ||
|
|
c64b4c4e28 | ||
|
|
871c9f21ee | ||
|
|
3770c1f6cb | ||
|
|
636758fe40 | ||
|
|
c9636b4bf5 | ||
|
|
d39ad1ccfd | ||
|
|
552a4e57a8 | ||
|
|
105fa48cab | ||
|
|
9824769418 | ||
|
|
02fda3dd28 | ||
|
|
609e0ca1d8 | ||
|
|
d21132fe6e | ||
|
|
902dc0c4a7 | ||
|
|
7bd3bf6642 | ||
|
|
843bbbd03b | ||
|
|
3091ad45a5 | ||
|
|
8d635c6681 | ||
|
|
f5fd218755 | ||
|
|
d5591ff440 | ||
|
|
605d572f9c |
@@ -70,7 +70,7 @@ build-system-debian:
|
||||
needs:
|
||||
job: amd64-debian-container
|
||||
variables:
|
||||
IMAGE: debian
|
||||
IMAGE: debian-amd64
|
||||
CONFIGURE_ARGS: --with-coroutine=sigaltstack
|
||||
TARGETS: arm-softmmu i386-softmmu riscv64-softmmu sh4eb-softmmu
|
||||
sparc-softmmu xtensa-softmmu
|
||||
@@ -82,7 +82,7 @@ check-system-debian:
|
||||
- job: build-system-debian
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: debian
|
||||
IMAGE: debian-amd64
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
avocado-system-debian:
|
||||
@@ -91,7 +91,7 @@ avocado-system-debian:
|
||||
- job: build-system-debian
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: debian
|
||||
IMAGE: debian-amd64
|
||||
MAKE_CHECK_ARGS: check-avocado
|
||||
AVOCADO_TAGS: arch:arm arch:i386 arch:riscv64 arch:sh4 arch:sparc arch:xtensa
|
||||
|
||||
@@ -101,7 +101,7 @@ crash-test-debian:
|
||||
- job: build-system-debian
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: debian
|
||||
IMAGE: debian-amd64
|
||||
script:
|
||||
- cd build
|
||||
- make NINJA=":" check-venv
|
||||
@@ -589,7 +589,7 @@ build-tools-and-docs-debian:
|
||||
# when running on 'master' we use pre-existing container
|
||||
optional: true
|
||||
variables:
|
||||
IMAGE: debian
|
||||
IMAGE: debian-amd64
|
||||
MAKE_CHECK_ARGS: check-unit ctags TAGS cscope
|
||||
CONFIGURE_ARGS: --disable-system --disable-user --enable-docs --enable-tools
|
||||
QEMU_JOB_PUBLISH: 1
|
||||
@@ -609,7 +609,7 @@ build-tools-and-docs-debian:
|
||||
# of what topic branch they're currently using
|
||||
pages:
|
||||
extends: .base_job_template
|
||||
image: $CI_REGISTRY_IMAGE/qemu/debian:$QEMU_CI_CONTAINER_TAG
|
||||
image: $CI_REGISTRY_IMAGE/qemu/debian-amd64:$QEMU_CI_CONTAINER_TAG
|
||||
stage: test
|
||||
needs:
|
||||
- job: build-tools-and-docs-debian
|
||||
|
||||
@@ -59,13 +59,13 @@ x64-freebsd-13-build:
|
||||
INSTALL_COMMAND: pkg install -y
|
||||
TEST_TARGETS: check
|
||||
|
||||
aarch64-macos-13-base-build:
|
||||
aarch64-macos-12-base-build:
|
||||
extends: .cirrus_build_job
|
||||
variables:
|
||||
NAME: macos-13
|
||||
NAME: macos-12
|
||||
CIRRUS_VM_INSTANCE_TYPE: macos_instance
|
||||
CIRRUS_VM_IMAGE_SELECTOR: image
|
||||
CIRRUS_VM_IMAGE_NAME: ghcr.io/cirruslabs/macos-ventura-base:latest
|
||||
CIRRUS_VM_IMAGE_NAME: ghcr.io/cirruslabs/macos-monterey-base:latest
|
||||
CIRRUS_VM_CPUS: 12
|
||||
CIRRUS_VM_RAM: 24G
|
||||
UPDATE_COMMAND: brew update
|
||||
@@ -74,22 +74,6 @@ aarch64-macos-13-base-build:
|
||||
PKG_CONFIG_PATH: /opt/homebrew/curl/lib/pkgconfig:/opt/homebrew/ncurses/lib/pkgconfig:/opt/homebrew/readline/lib/pkgconfig
|
||||
TEST_TARGETS: check-unit check-block check-qapi-schema check-softfloat check-qtest-x86_64
|
||||
|
||||
aarch64-macos-14-base-build:
|
||||
extends: .cirrus_build_job
|
||||
variables:
|
||||
NAME: macos-14
|
||||
CIRRUS_VM_INSTANCE_TYPE: macos_instance
|
||||
CIRRUS_VM_IMAGE_SELECTOR: image
|
||||
CIRRUS_VM_IMAGE_NAME: ghcr.io/cirruslabs/macos-sonoma-base:latest
|
||||
CIRRUS_VM_CPUS: 12
|
||||
CIRRUS_VM_RAM: 24G
|
||||
UPDATE_COMMAND: brew update
|
||||
INSTALL_COMMAND: brew install
|
||||
PATH_EXTRA: /opt/homebrew/ccache/libexec:/opt/homebrew/gettext/bin
|
||||
PKG_CONFIG_PATH: /opt/homebrew/curl/lib/pkgconfig:/opt/homebrew/ncurses/lib/pkgconfig:/opt/homebrew/readline/lib/pkgconfig
|
||||
TEST_TARGETS: check-unit check-block check-qapi-schema check-softfloat check-qtest-x86_64
|
||||
QEMU_JOB_OPTIONAL: 1
|
||||
|
||||
|
||||
# The following jobs run VM-based tests via KVM on a Linux-based Cirrus-CI job
|
||||
.cirrus_kvm_job:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# THIS FILE WAS AUTO-GENERATED
|
||||
#
|
||||
# $ lcitool variables macos-13 qemu
|
||||
# $ lcitool variables macos-12 qemu
|
||||
#
|
||||
# https://gitlab.com/libvirt/libvirt-ci
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
# THIS FILE WAS AUTO-GENERATED
|
||||
#
|
||||
# $ lcitool variables macos-14 qemu
|
||||
#
|
||||
# https://gitlab.com/libvirt/libvirt-ci
|
||||
|
||||
CCACHE='/opt/homebrew/bin/ccache'
|
||||
CPAN_PKGS=''
|
||||
CROSS_PKGS=''
|
||||
MAKE='/opt/homebrew/bin/gmake'
|
||||
NINJA='/opt/homebrew/bin/ninja'
|
||||
PACKAGING_COMMAND='brew'
|
||||
PIP3='/opt/homebrew/bin/pip3'
|
||||
PKGS='bash bc bison bzip2 capstone ccache cmocka ctags curl dbus diffutils dtc flex gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo json-c libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson mtools ncurses nettle ninja pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy socat sparse spice-protocol swtpm tesseract usbredir vde vte3 xorriso zlib zstd'
|
||||
PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme tomli'
|
||||
PYTHON='/opt/homebrew/bin/python3'
|
||||
@@ -46,12 +46,6 @@ loongarch-debian-cross-container:
|
||||
variables:
|
||||
NAME: debian-loongarch-cross
|
||||
|
||||
i686-debian-cross-container:
|
||||
extends: .container_job_template
|
||||
stage: containers
|
||||
variables:
|
||||
NAME: debian-i686-cross
|
||||
|
||||
mips64el-debian-cross-container:
|
||||
extends: .container_job_template
|
||||
stage: containers
|
||||
@@ -101,6 +95,11 @@ cris-fedora-cross-container:
|
||||
variables:
|
||||
NAME: fedora-cris-cross
|
||||
|
||||
i386-fedora-cross-container:
|
||||
extends: .container_job_template
|
||||
variables:
|
||||
NAME: fedora-i386-cross
|
||||
|
||||
win32-fedora-cross-container:
|
||||
extends: .container_job_template
|
||||
variables:
|
||||
|
||||
@@ -11,7 +11,7 @@ amd64-debian-container:
|
||||
extends: .container_job_template
|
||||
stage: containers
|
||||
variables:
|
||||
NAME: debian
|
||||
NAME: debian-amd64
|
||||
|
||||
amd64-ubuntu2204-container:
|
||||
extends: .container_job_template
|
||||
|
||||
@@ -37,25 +37,25 @@ cross-arm64-kvm-only:
|
||||
IMAGE: debian-arm64-cross
|
||||
EXTRA_CONFIGURE_OPTS: --disable-tcg --without-default-features
|
||||
|
||||
cross-i686-user:
|
||||
cross-i386-user:
|
||||
extends:
|
||||
- .cross_user_build_job
|
||||
- .cross_test_artifacts
|
||||
needs:
|
||||
job: i686-debian-cross-container
|
||||
job: i386-fedora-cross-container
|
||||
variables:
|
||||
IMAGE: debian-i686-cross
|
||||
IMAGE: fedora-i386-cross
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
cross-i686-tci:
|
||||
cross-i386-tci:
|
||||
extends:
|
||||
- .cross_accel_build_job
|
||||
- .cross_test_artifacts
|
||||
timeout: 60m
|
||||
needs:
|
||||
job: i686-debian-cross-container
|
||||
job: i386-fedora-cross-container
|
||||
variables:
|
||||
IMAGE: debian-i686-cross
|
||||
IMAGE: fedora-i386-cross
|
||||
ACCEL: tcg-interpreter
|
||||
EXTRA_CONFIGURE_OPTS: --target-list=i386-softmmu,i386-linux-user,aarch64-softmmu,aarch64-linux-user,ppc-softmmu,ppc-linux-user --disable-plugins
|
||||
MAKE_CHECK_ARGS: check check-tcg
|
||||
@@ -165,7 +165,7 @@ cross-win32-system:
|
||||
job: win32-fedora-cross-container
|
||||
variables:
|
||||
IMAGE: fedora-win32-cross
|
||||
EXTRA_CONFIGURE_OPTS: --enable-fdt=internal
|
||||
EXTRA_CONFIGURE_OPTS: --enable-fdt=internal --disable-plugins
|
||||
CROSS_SKIP_TARGETS: alpha-softmmu avr-softmmu hppa-softmmu m68k-softmmu
|
||||
microblazeel-softmmu mips64el-softmmu nios2-softmmu
|
||||
artifacts:
|
||||
|
||||
@@ -174,7 +174,6 @@ F: include/hw/core/tcg-cpu-ops.h
|
||||
F: host/include/*/host/cpuinfo.h
|
||||
F: util/cpuinfo-*.c
|
||||
F: include/tcg/
|
||||
F: tests/decode/
|
||||
|
||||
FPU emulation
|
||||
M: Aurelien Jarno <aurelien@aurel32.net>
|
||||
|
||||
@@ -101,6 +101,8 @@ bool kvm_msi_use_devid;
|
||||
bool kvm_has_guest_debug;
|
||||
static int kvm_sstep_flags;
|
||||
static bool kvm_immediate_exit;
|
||||
static bool kvm_guest_memfd_supported;
|
||||
static uint64_t kvm_supported_memory_attributes;
|
||||
static hwaddr kvm_max_slot_size = ~0;
|
||||
|
||||
static const KVMCapabilityInfo kvm_required_capabilites[] = {
|
||||
@@ -292,34 +294,69 @@ int kvm_physical_memory_addr_from_host(KVMState *s, void *ram,
|
||||
static int kvm_set_user_memory_region(KVMMemoryListener *kml, KVMSlot *slot, bool new)
|
||||
{
|
||||
KVMState *s = kvm_state;
|
||||
struct kvm_userspace_memory_region mem;
|
||||
struct kvm_userspace_memory_region2 mem;
|
||||
static int cap_user_memory2 = -1;
|
||||
int ret;
|
||||
|
||||
if (cap_user_memory2 == -1) {
|
||||
cap_user_memory2 = kvm_check_extension(s, KVM_CAP_USER_MEMORY2);
|
||||
}
|
||||
|
||||
if (!cap_user_memory2 && slot->guest_memfd >= 0) {
|
||||
error_report("%s, KVM doesn't support KVM_CAP_USER_MEMORY2,"
|
||||
" which is required by guest memfd!", __func__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
mem.slot = slot->slot | (kml->as_id << 16);
|
||||
mem.guest_phys_addr = slot->start_addr;
|
||||
mem.userspace_addr = (unsigned long)slot->ram;
|
||||
mem.flags = slot->flags;
|
||||
mem.guest_memfd = slot->guest_memfd;
|
||||
mem.guest_memfd_offset = slot->guest_memfd_offset;
|
||||
|
||||
if (slot->memory_size && !new && (mem.flags ^ slot->old_flags) & KVM_MEM_READONLY) {
|
||||
/* Set the slot size to 0 before setting the slot to the desired
|
||||
* value. This is needed based on KVM commit 75d61fbc. */
|
||||
mem.memory_size = 0;
|
||||
ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
|
||||
|
||||
if (cap_user_memory2) {
|
||||
ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION2, &mem);
|
||||
} else {
|
||||
ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
|
||||
}
|
||||
if (ret < 0) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
mem.memory_size = slot->memory_size;
|
||||
ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
|
||||
if (cap_user_memory2) {
|
||||
ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION2, &mem);
|
||||
} else {
|
||||
ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
|
||||
}
|
||||
slot->old_flags = mem.flags;
|
||||
err:
|
||||
trace_kvm_set_user_memory(mem.slot, mem.flags, mem.guest_phys_addr,
|
||||
mem.memory_size, mem.userspace_addr, ret);
|
||||
trace_kvm_set_user_memory(mem.slot >> 16, (uint16_t)mem.slot, mem.flags,
|
||||
mem.guest_phys_addr, mem.memory_size,
|
||||
mem.userspace_addr, mem.guest_memfd,
|
||||
mem.guest_memfd_offset, ret);
|
||||
if (ret < 0) {
|
||||
error_report("%s: KVM_SET_USER_MEMORY_REGION failed, slot=%d,"
|
||||
" start=0x%" PRIx64 ", size=0x%" PRIx64 ": %s",
|
||||
__func__, mem.slot, slot->start_addr,
|
||||
(uint64_t)mem.memory_size, strerror(errno));
|
||||
if (cap_user_memory2) {
|
||||
error_report("%s: KVM_SET_USER_MEMORY_REGION2 failed, slot=%d,"
|
||||
" start=0x%" PRIx64 ", size=0x%" PRIx64 ","
|
||||
" flags=0x%" PRIx32 ", guest_memfd=%" PRId32 ","
|
||||
" guest_memfd_offset=0x%" PRIx64 ": %s",
|
||||
__func__, mem.slot, slot->start_addr,
|
||||
(uint64_t)mem.memory_size, mem.flags,
|
||||
mem.guest_memfd, (uint64_t)mem.guest_memfd_offset,
|
||||
strerror(errno));
|
||||
} else {
|
||||
error_report("%s: KVM_SET_USER_MEMORY_REGION failed, slot=%d,"
|
||||
" start=0x%" PRIx64 ", size=0x%" PRIx64 ": %s",
|
||||
__func__, mem.slot, slot->start_addr,
|
||||
(uint64_t)mem.memory_size, strerror(errno));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -391,6 +428,11 @@ static int kvm_get_vcpu(KVMState *s, unsigned long vcpu_id)
|
||||
return kvm_vm_ioctl(s, KVM_CREATE_VCPU, (void *)vcpu_id);
|
||||
}
|
||||
|
||||
int __attribute__ ((weak)) kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_init_vcpu(CPUState *cpu, Error **errp)
|
||||
{
|
||||
KVMState *s = kvm_state;
|
||||
@@ -399,15 +441,27 @@ int kvm_init_vcpu(CPUState *cpu, Error **errp)
|
||||
|
||||
trace_kvm_init_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu));
|
||||
|
||||
/*
|
||||
* tdx_pre_create_vcpu() may call cpu_x86_cpuid(). It in turn may call
|
||||
* kvm_vm_ioctl(). Set cpu->kvm_state in advance to avoid NULL pointer
|
||||
* dereference.
|
||||
*/
|
||||
cpu->kvm_state = s;
|
||||
ret = kvm_arch_pre_create_vcpu(cpu, errp);
|
||||
if (ret < 0) {
|
||||
cpu->kvm_state = NULL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = kvm_get_vcpu(s, kvm_arch_vcpu_id(cpu));
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "kvm_init_vcpu: kvm_get_vcpu failed (%lu)",
|
||||
kvm_arch_vcpu_id(cpu));
|
||||
cpu->kvm_state = NULL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
cpu->kvm_fd = ret;
|
||||
cpu->kvm_state = s;
|
||||
cpu->vcpu_dirty = true;
|
||||
cpu->dirty_pages = 0;
|
||||
cpu->throttle_us_per_full = 0;
|
||||
@@ -475,6 +529,9 @@ static int kvm_mem_flags(MemoryRegion *mr)
|
||||
if (readonly && kvm_readonly_mem_allowed) {
|
||||
flags |= KVM_MEM_READONLY;
|
||||
}
|
||||
if (memory_region_has_guest_memfd(mr)) {
|
||||
flags |= KVM_MEM_PRIVATE;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
@@ -1266,6 +1323,44 @@ void kvm_set_max_memslot_size(hwaddr max_slot_size)
|
||||
kvm_max_slot_size = max_slot_size;
|
||||
}
|
||||
|
||||
static int kvm_set_memory_attributes(hwaddr start, hwaddr size, uint64_t attr)
|
||||
{
|
||||
struct kvm_memory_attributes attrs;
|
||||
int r;
|
||||
|
||||
attrs.attributes = attr;
|
||||
attrs.address = start;
|
||||
attrs.size = size;
|
||||
attrs.flags = 0;
|
||||
|
||||
r = kvm_vm_ioctl(kvm_state, KVM_SET_MEMORY_ATTRIBUTES, &attrs);
|
||||
if (r) {
|
||||
warn_report("%s: failed to set memory (0x%lx+%#zx) with attr 0x%lx error '%s'",
|
||||
__func__, start, size, attr, strerror(errno));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int kvm_set_memory_attributes_private(hwaddr start, hwaddr size)
|
||||
{
|
||||
if (!(kvm_supported_memory_attributes & KVM_MEMORY_ATTRIBUTE_PRIVATE)) {
|
||||
error_report("KVM doesn't support PRIVATE memory attribute\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return kvm_set_memory_attributes(start, size, KVM_MEMORY_ATTRIBUTE_PRIVATE);
|
||||
}
|
||||
|
||||
int kvm_set_memory_attributes_shared(hwaddr start, hwaddr size)
|
||||
{
|
||||
if (!(kvm_supported_memory_attributes & KVM_MEMORY_ATTRIBUTE_PRIVATE)) {
|
||||
error_report("KVM doesn't support PRIVATE memory attribute\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return kvm_set_memory_attributes(start, size, 0);
|
||||
}
|
||||
|
||||
/* Called with KVMMemoryListener.slots_lock held */
|
||||
static void kvm_set_phys_mem(KVMMemoryListener *kml,
|
||||
MemoryRegionSection *section, bool add)
|
||||
@@ -1362,6 +1457,9 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
|
||||
mem->ram_start_offset = ram_start_offset;
|
||||
mem->ram = ram;
|
||||
mem->flags = kvm_mem_flags(mr);
|
||||
mem->guest_memfd = mr->ram_block->guest_memfd;
|
||||
mem->guest_memfd_offset = (uint8_t*)ram - mr->ram_block->host;
|
||||
|
||||
kvm_slot_init_dirty_bitmap(mem);
|
||||
err = kvm_set_user_memory_region(kml, mem, true);
|
||||
if (err) {
|
||||
@@ -1369,6 +1467,16 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
|
||||
strerror(-err));
|
||||
abort();
|
||||
}
|
||||
|
||||
if (memory_region_is_default_private(mr)) {
|
||||
err = kvm_set_memory_attributes_private(start_addr, slot_size);
|
||||
if (err) {
|
||||
error_report("%s: failed to set memory attribute private: %s\n",
|
||||
__func__, strerror(-err));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
start_addr += slot_size;
|
||||
ram_start_offset += slot_size;
|
||||
ram += slot_size;
|
||||
@@ -2396,6 +2504,11 @@ static int kvm_init(MachineState *ms)
|
||||
}
|
||||
s->as = g_new0(struct KVMAs, s->nr_as);
|
||||
|
||||
kvm_guest_memfd_supported = kvm_check_extension(s, KVM_CAP_GUEST_MEMFD);
|
||||
|
||||
ret = kvm_check_extension(s, KVM_CAP_MEMORY_ATTRIBUTES);
|
||||
kvm_supported_memory_attributes = ret > 0 ? ret : 0;
|
||||
|
||||
if (object_property_find(OBJECT(current_machine), "kvm-type")) {
|
||||
g_autofree char *kvm_type = object_property_get_str(OBJECT(current_machine),
|
||||
"kvm-type",
|
||||
@@ -2816,6 +2929,78 @@ static void kvm_eat_signals(CPUState *cpu)
|
||||
} while (sigismember(&chkset, SIG_IPI));
|
||||
}
|
||||
|
||||
int kvm_convert_memory(hwaddr start, hwaddr size, bool to_private)
|
||||
{
|
||||
MemoryRegionSection section;
|
||||
ram_addr_t offset;
|
||||
MemoryRegion *mr;
|
||||
RAMBlock *rb;
|
||||
void *addr;
|
||||
int ret = -1;
|
||||
|
||||
trace_kvm_convert_memory(start, size, to_private ? "shared_to_private" : "private_to_shared");
|
||||
section = memory_region_find(get_system_memory(), start, size);
|
||||
mr = section.mr;
|
||||
if (!mr) {
|
||||
/*
|
||||
* Ignore converting non-assigned region to shared.
|
||||
*
|
||||
* TDX requires vMMIO region to be shared to inject #VE to guest.
|
||||
* OVMF issues conservatively MapGPA(shared) on 32bit PCI MMIO region,
|
||||
* and vIO-APIC 0xFEC00000 4K page.
|
||||
* OVMF assigns 32bit PCI MMIO region to
|
||||
* [top of low memory: typically 2GB=0xC000000, 0xFC00000)
|
||||
*/
|
||||
if (!to_private) {
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (memory_region_has_guest_memfd(mr)) {
|
||||
if (to_private) {
|
||||
ret = kvm_set_memory_attributes_private(start, size);
|
||||
} else {
|
||||
ret = kvm_set_memory_attributes_shared(start, size);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
memory_region_unref(section.mr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
addr = memory_region_get_ram_ptr(section.mr) +
|
||||
section.offset_within_region;
|
||||
rb = qemu_ram_block_from_host(addr, false, &offset);
|
||||
/*
|
||||
* With KVM_SET_MEMORY_ATTRIBUTES by kvm_set_memory_attributes(),
|
||||
* operation on underlying file descriptor is only for releasing
|
||||
* unnecessary pages.
|
||||
*/
|
||||
ram_block_convert_range(rb, offset, size, to_private);
|
||||
} else {
|
||||
/*
|
||||
* Because vMMIO region must be shared, guest TD may convert vMMIO
|
||||
* region to shared explicitly. Don't complain such case. See
|
||||
* memory_region_type() for checking if the region is MMIO region.
|
||||
*/
|
||||
if (!to_private &&
|
||||
!memory_region_is_ram(mr) &&
|
||||
!memory_region_is_ram_device(mr) &&
|
||||
!memory_region_is_rom(mr) &&
|
||||
!memory_region_is_romd(mr)) {
|
||||
ret = 0;
|
||||
} else {
|
||||
warn_report("Convert non guest_memfd backed memory region "
|
||||
"(0x%"HWADDR_PRIx" ,+ 0x%"HWADDR_PRIx") to %s",
|
||||
start, size, to_private ? "private" : "shared");
|
||||
}
|
||||
}
|
||||
|
||||
memory_region_unref(section.mr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int kvm_cpu_exec(CPUState *cpu)
|
||||
{
|
||||
struct kvm_run *run = cpu->kvm_run;
|
||||
@@ -2883,18 +3068,20 @@ int kvm_cpu_exec(CPUState *cpu)
|
||||
ret = EXCP_INTERRUPT;
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, "error: kvm run failed %s\n",
|
||||
strerror(-run_ret));
|
||||
if (!(run_ret == -EFAULT && run->exit_reason == KVM_EXIT_MEMORY_FAULT)) {
|
||||
fprintf(stderr, "error: kvm run failed %s\n",
|
||||
strerror(-run_ret));
|
||||
#ifdef TARGET_PPC
|
||||
if (run_ret == -EBUSY) {
|
||||
fprintf(stderr,
|
||||
"This is probably because your SMT is enabled.\n"
|
||||
"VCPU can only run on primary threads with all "
|
||||
"secondary threads offline.\n");
|
||||
}
|
||||
if (run_ret == -EBUSY) {
|
||||
fprintf(stderr,
|
||||
"This is probably because your SMT is enabled.\n"
|
||||
"VCPU can only run on primary threads with all "
|
||||
"secondary threads offline.\n");
|
||||
}
|
||||
#endif
|
||||
ret = -1;
|
||||
break;
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
trace_kvm_run_exit(cpu->cpu_index, run->exit_reason);
|
||||
@@ -2981,6 +3168,16 @@ int kvm_cpu_exec(CPUState *cpu)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case KVM_EXIT_MEMORY_FAULT:
|
||||
if (run->memory_fault.flags & ~KVM_MEMORY_EXIT_FLAG_PRIVATE) {
|
||||
error_report("KVM_EXIT_MEMORY_FAULT: Unknown flag 0x%" PRIx64,
|
||||
(uint64_t)run->memory_fault.flags);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
ret = kvm_convert_memory(run->memory_fault.gpa, run->memory_fault.size,
|
||||
run->memory_fault.flags & KVM_MEMORY_EXIT_FLAG_PRIVATE);
|
||||
break;
|
||||
default:
|
||||
DPRINTF("kvm_arch_handle_exit\n");
|
||||
ret = kvm_arch_handle_exit(cpu, run);
|
||||
@@ -4077,3 +4274,24 @@ void query_stats_schemas_cb(StatsSchemaList **result, Error **errp)
|
||||
query_stats_schema_vcpu(first_cpu, &stats_args);
|
||||
}
|
||||
}
|
||||
|
||||
int kvm_create_guest_memfd(uint64_t size, uint64_t flags, Error **errp)
|
||||
{
|
||||
int fd;
|
||||
struct kvm_create_guest_memfd guest_memfd = {
|
||||
.size = size,
|
||||
.flags = flags,
|
||||
};
|
||||
|
||||
if (!kvm_guest_memfd_supported) {
|
||||
error_setg(errp, "KVM doesn't support guest memfd\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
fd = kvm_vm_ioctl(kvm_state, KVM_CREATE_GUEST_MEMFD, &guest_memfd);
|
||||
if (fd < 0) {
|
||||
error_setg_errno(errp, errno, "%s: error creating kvm guest memfd\n", __func__);
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ kvm_irqchip_update_msi_route(int virq) "Updating MSI route virq=%d"
|
||||
kvm_irqchip_release_virq(int virq) "virq %d"
|
||||
kvm_set_ioeventfd_mmio(int fd, uint64_t addr, uint32_t val, bool assign, uint32_t size, bool datamatch) "fd: %d @0x%" PRIx64 " val=0x%x assign: %d size: %d match: %d"
|
||||
kvm_set_ioeventfd_pio(int fd, uint16_t addr, uint32_t val, bool assign, uint32_t size, bool datamatch) "fd: %d @0x%x val=0x%x assign: %d size: %d match: %d"
|
||||
kvm_set_user_memory(uint32_t slot, uint32_t flags, uint64_t guest_phys_addr, uint64_t memory_size, uint64_t userspace_addr, int ret) "Slot#%d flags=0x%x gpa=0x%"PRIx64 " size=0x%"PRIx64 " ua=0x%"PRIx64 " ret=%d"
|
||||
kvm_set_user_memory(uint16_t as, uint16_t slot, uint32_t flags, uint64_t guest_phys_addr, uint64_t memory_size, uint64_t userspace_addr, uint32_t fd, uint64_t fd_offset, int ret) "AddrSpace#%d Slot#%d flags=0x%x gpa=0x%"PRIx64 " size=0x%"PRIx64 " ua=0x%"PRIx64 " guest_memfd=%d" " guest_memfd_offset=0x%" PRIx64 " ret=%d"
|
||||
kvm_clear_dirty_log(uint32_t slot, uint64_t start, uint32_t size) "slot#%"PRId32" start 0x%"PRIx64" size 0x%"PRIx32
|
||||
kvm_resample_fd_notify(int gsi) "gsi %d"
|
||||
kvm_dirty_ring_full(int id) "vcpu %d"
|
||||
@@ -25,4 +25,4 @@ kvm_dirty_ring_reaper(const char *s) "%s"
|
||||
kvm_dirty_ring_reap(uint64_t count, int64_t t) "reaped %"PRIu64" pages (took %"PRIi64" us)"
|
||||
kvm_dirty_ring_reaper_kick(const char *reason) "%s"
|
||||
kvm_dirty_ring_flush(int finished) "%d"
|
||||
|
||||
kvm_convert_memory(uint64_t start, uint64_t size, const char *msg) "start 0x%" PRIx64 " size 0x%" PRIx64 " %s"
|
||||
|
||||
@@ -721,7 +721,7 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
|
||||
&& cpu->neg.icount_decr.u16.low + cpu->icount_extra == 0) {
|
||||
/* Execute just one insn to trigger exception pending in the log */
|
||||
cpu->cflags_next_tb = (curr_cflags(cpu) & ~CF_USE_ICOUNT)
|
||||
| CF_NOIRQ | 1;
|
||||
| CF_LAST_IO | CF_NOIRQ | 1;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
|
||||
@@ -1479,8 +1479,7 @@ int probe_access_full(CPUArchState *env, vaddr addr, int size,
|
||||
|
||||
/* Handle clean RAM pages. */
|
||||
if (unlikely(flags & TLB_NOTDIRTY)) {
|
||||
int dirtysize = size == 0 ? 1 : size;
|
||||
notdirty_write(env_cpu(env), addr, dirtysize, *pfull, retaddr);
|
||||
notdirty_write(env_cpu(env), addr, 1, *pfull, retaddr);
|
||||
flags &= ~TLB_NOTDIRTY;
|
||||
}
|
||||
|
||||
@@ -1503,8 +1502,7 @@ int probe_access_full_mmu(CPUArchState *env, vaddr addr, int size,
|
||||
|
||||
/* Handle clean RAM pages. */
|
||||
if (unlikely(flags & TLB_NOTDIRTY)) {
|
||||
int dirtysize = size == 0 ? 1 : size;
|
||||
notdirty_write(env_cpu(env), addr, dirtysize, *pfull, 0);
|
||||
notdirty_write(env_cpu(env), addr, 1, *pfull, 0);
|
||||
flags &= ~TLB_NOTDIRTY;
|
||||
}
|
||||
|
||||
@@ -1526,8 +1524,7 @@ int probe_access_flags(CPUArchState *env, vaddr addr, int size,
|
||||
|
||||
/* Handle clean RAM pages. */
|
||||
if (unlikely(flags & TLB_NOTDIRTY)) {
|
||||
int dirtysize = size == 0 ? 1 : size;
|
||||
notdirty_write(env_cpu(env), addr, dirtysize, full, retaddr);
|
||||
notdirty_write(env_cpu(env), addr, 1, full, retaddr);
|
||||
flags &= ~TLB_NOTDIRTY;
|
||||
}
|
||||
|
||||
@@ -1563,7 +1560,7 @@ void *probe_access(CPUArchState *env, vaddr addr, int size,
|
||||
|
||||
/* Handle clean RAM pages. */
|
||||
if (flags & TLB_NOTDIRTY) {
|
||||
notdirty_write(env_cpu(env), addr, size, full, retaddr);
|
||||
notdirty_write(env_cpu(env), addr, 1, full, retaddr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1083,7 +1083,8 @@ bool tb_invalidate_phys_page_unwind(tb_page_addr_t addr, uintptr_t pc)
|
||||
if (current_tb_modified) {
|
||||
/* Force execution of one insn next time. */
|
||||
CPUState *cpu = current_cpu;
|
||||
cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(current_cpu);
|
||||
cpu->cflags_next_tb =
|
||||
1 | CF_LAST_IO | CF_NOIRQ | curr_cflags(current_cpu);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1153,7 +1154,8 @@ tb_invalidate_phys_page_range__locked(struct page_collection *pages,
|
||||
if (current_tb_modified) {
|
||||
page_collection_unlock(pages);
|
||||
/* Force execution of one insn next time. */
|
||||
current_cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(current_cpu);
|
||||
current_cpu->cflags_next_tb =
|
||||
1 | CF_LAST_IO | CF_NOIRQ | curr_cflags(current_cpu);
|
||||
mmap_unlock();
|
||||
cpu_loop_exit_noexc(current_cpu);
|
||||
}
|
||||
|
||||
@@ -304,7 +304,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
|
||||
if (phys_pc == -1) {
|
||||
/* Generate a one-shot TB with 1 insn in it */
|
||||
cflags = (cflags & ~CF_COUNT_MASK) | 1;
|
||||
cflags = (cflags & ~CF_COUNT_MASK) | CF_LAST_IO | 1;
|
||||
}
|
||||
|
||||
max_insns = cflags & CF_COUNT_MASK;
|
||||
@@ -632,7 +632,7 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
|
||||
* operations only (which execute after completion) so we don't
|
||||
* double instrument the instruction.
|
||||
*/
|
||||
cpu->cflags_next_tb = curr_cflags(cpu) | CF_MEMI_ONLY | n;
|
||||
cpu->cflags_next_tb = curr_cflags(cpu) | CF_MEMI_ONLY | CF_LAST_IO | n;
|
||||
|
||||
if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
|
||||
vaddr pc = log_pc(cpu, tb);
|
||||
|
||||
@@ -89,7 +89,7 @@ static TCGOp *gen_tb_start(DisasContextBase *db, uint32_t cflags)
|
||||
* each translation block. The cost is minimal, plus it would be
|
||||
* very easy to forget doing it in the translator.
|
||||
*/
|
||||
set_can_do_io(db, db->max_insns == 1);
|
||||
set_can_do_io(db, db->max_insns == 1 && (cflags & CF_LAST_IO));
|
||||
|
||||
return icount_start_insn;
|
||||
}
|
||||
@@ -151,7 +151,13 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
||||
ops->tb_start(db, cpu);
|
||||
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
|
||||
|
||||
plugin_enabled = plugin_gen_tb_start(cpu, db, cflags & CF_MEMI_ONLY);
|
||||
if (cflags & CF_MEMI_ONLY) {
|
||||
/* We should only see CF_MEMI_ONLY for io_recompile. */
|
||||
assert(cflags & CF_LAST_IO);
|
||||
plugin_enabled = plugin_gen_tb_start(cpu, db, true);
|
||||
} else {
|
||||
plugin_enabled = plugin_gen_tb_start(cpu, db, false);
|
||||
}
|
||||
db->plugin_enabled = plugin_enabled;
|
||||
|
||||
while (true) {
|
||||
@@ -163,13 +169,11 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
||||
plugin_gen_insn_start(cpu, db);
|
||||
}
|
||||
|
||||
/*
|
||||
* Disassemble one instruction. The translate_insn hook should
|
||||
* update db->pc_next and db->is_jmp to indicate what should be
|
||||
* done next -- either exiting this loop or locate the start of
|
||||
* the next instruction.
|
||||
*/
|
||||
if (db->num_insns == db->max_insns) {
|
||||
/* Disassemble one instruction. The translate_insn hook should
|
||||
update db->pc_next and db->is_jmp to indicate what should be
|
||||
done next -- either exiting this loop or locate the start of
|
||||
the next instruction. */
|
||||
if (db->num_insns == db->max_insns && (cflags & CF_LAST_IO)) {
|
||||
/* Accept I/O on the last instruction. */
|
||||
set_can_do_io(db, true);
|
||||
}
|
||||
|
||||
@@ -1758,15 +1758,12 @@ static AudioState *audio_init(Audiodev *dev, Error **errp)
|
||||
goto out;
|
||||
}
|
||||
s->dev = dev = e->dev;
|
||||
QSIMPLEQ_REMOVE_HEAD(&default_audiodevs, next);
|
||||
g_free(e);
|
||||
drvname = AudiodevDriver_str(dev->driver);
|
||||
driver = audio_driver_lookup(drvname);
|
||||
if (!audio_driver_init(s, driver, dev, NULL)) {
|
||||
break;
|
||||
}
|
||||
qapi_free_Audiodev(dev);
|
||||
s->dev = NULL;
|
||||
QSIMPLEQ_REMOVE_HEAD(&default_audiodevs, next);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -84,6 +84,7 @@ file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
|
||||
ram_flags |= fb->readonly ? RAM_READONLY_FD : 0;
|
||||
ram_flags |= fb->rom == ON_OFF_AUTO_ON ? RAM_READONLY : 0;
|
||||
ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
|
||||
ram_flags |= backend->require_guest_memfd ? RAM_GUEST_MEMFD : 0;
|
||||
ram_flags |= fb->is_pmem ? RAM_PMEM : 0;
|
||||
ram_flags |= RAM_NAMED_FILE;
|
||||
memory_region_init_ram_from_file(&backend->mr, OBJECT(backend), name,
|
||||
|
||||
@@ -55,6 +55,7 @@ memfd_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
|
||||
name = host_memory_backend_get_name(backend);
|
||||
ram_flags = backend->share ? RAM_SHARED : 0;
|
||||
ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
|
||||
ram_flags |= backend->require_guest_memfd ? RAM_GUEST_MEMFD : 0;
|
||||
memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend), name,
|
||||
backend->size, ram_flags, fd, 0, errp);
|
||||
g_free(name);
|
||||
|
||||
@@ -30,6 +30,7 @@ ram_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
|
||||
name = host_memory_backend_get_name(backend);
|
||||
ram_flags = backend->share ? RAM_SHARED : 0;
|
||||
ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
|
||||
ram_flags |= backend->require_guest_memfd ? RAM_GUEST_MEMFD : 0;
|
||||
memory_region_init_ram_flags_nomigrate(&backend->mr, OBJECT(backend), name,
|
||||
backend->size, ram_flags, errp);
|
||||
g_free(name);
|
||||
|
||||
@@ -279,6 +279,7 @@ static void host_memory_backend_init(Object *obj)
|
||||
/* TODO: convert access to globals to compat properties */
|
||||
backend->merge = machine_mem_merge(machine);
|
||||
backend->dump = machine_dump_guest_core(machine);
|
||||
backend->require_guest_memfd = machine_require_guest_memfd(machine);
|
||||
backend->reserve = true;
|
||||
backend->prealloc_threads = machine->smp.cpus;
|
||||
}
|
||||
|
||||
39
block.c
39
block.c
@@ -1713,7 +1713,7 @@ open_failed:
|
||||
bdrv_unref_child(bs, bs->file);
|
||||
assert(!bs->file);
|
||||
}
|
||||
bdrv_graph_wrunlock(NULL);
|
||||
bdrv_graph_wrunlock();
|
||||
|
||||
g_free(bs->opaque);
|
||||
bs->opaque = NULL;
|
||||
@@ -3577,7 +3577,7 @@ int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
|
||||
bdrv_drained_begin(drain_bs);
|
||||
bdrv_graph_wrlock(backing_hd);
|
||||
ret = bdrv_set_backing_hd_drained(bs, backing_hd, errp);
|
||||
bdrv_graph_wrunlock(backing_hd);
|
||||
bdrv_graph_wrunlock();
|
||||
bdrv_drained_end(drain_bs);
|
||||
bdrv_unref(drain_bs);
|
||||
|
||||
@@ -3796,7 +3796,7 @@ BdrvChild *bdrv_open_child(const char *filename,
|
||||
child = bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
|
||||
errp);
|
||||
aio_context_release(ctx);
|
||||
bdrv_graph_wrunlock(NULL);
|
||||
bdrv_graph_wrunlock();
|
||||
|
||||
return child;
|
||||
}
|
||||
@@ -4652,7 +4652,7 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
|
||||
|
||||
bdrv_graph_wrlock(NULL);
|
||||
tran_commit(tran);
|
||||
bdrv_graph_wrunlock(NULL);
|
||||
bdrv_graph_wrunlock();
|
||||
|
||||
QTAILQ_FOREACH_REVERSE(bs_entry, bs_queue, entry) {
|
||||
BlockDriverState *bs = bs_entry->state.bs;
|
||||
@@ -4671,7 +4671,7 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
|
||||
abort:
|
||||
bdrv_graph_wrlock(NULL);
|
||||
tran_abort(tran);
|
||||
bdrv_graph_wrunlock(NULL);
|
||||
bdrv_graph_wrunlock();
|
||||
|
||||
QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
|
||||
if (bs_entry->prepared) {
|
||||
@@ -4857,7 +4857,7 @@ bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
|
||||
ret = bdrv_set_file_or_backing_noperm(bs, new_child_bs, is_backing,
|
||||
tran, errp);
|
||||
|
||||
bdrv_graph_wrunlock_ctx(ctx);
|
||||
bdrv_graph_wrunlock();
|
||||
|
||||
if (old_ctx != ctx) {
|
||||
aio_context_release(ctx);
|
||||
@@ -5216,7 +5216,7 @@ static void bdrv_close(BlockDriverState *bs)
|
||||
|
||||
assert(!bs->backing);
|
||||
assert(!bs->file);
|
||||
bdrv_graph_wrunlock(bs);
|
||||
bdrv_graph_wrunlock();
|
||||
|
||||
g_free(bs->opaque);
|
||||
bs->opaque = NULL;
|
||||
@@ -5511,7 +5511,7 @@ int bdrv_drop_filter(BlockDriverState *bs, Error **errp)
|
||||
bdrv_drained_begin(child_bs);
|
||||
bdrv_graph_wrlock(bs);
|
||||
ret = bdrv_replace_node_common(bs, child_bs, true, true, errp);
|
||||
bdrv_graph_wrunlock(bs);
|
||||
bdrv_graph_wrunlock();
|
||||
bdrv_drained_end(child_bs);
|
||||
|
||||
return ret;
|
||||
@@ -5593,7 +5593,7 @@ out:
|
||||
tran_finalize(tran, ret);
|
||||
|
||||
bdrv_refresh_limits(bs_top, NULL, NULL);
|
||||
bdrv_graph_wrunlock(bs_top);
|
||||
bdrv_graph_wrunlock();
|
||||
|
||||
bdrv_drained_end(bs_top);
|
||||
bdrv_drained_end(bs_new);
|
||||
@@ -5631,7 +5631,7 @@ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs,
|
||||
|
||||
tran_finalize(tran, ret);
|
||||
|
||||
bdrv_graph_wrunlock(new_bs);
|
||||
bdrv_graph_wrunlock();
|
||||
bdrv_drained_end(old_bs);
|
||||
bdrv_drained_end(new_bs);
|
||||
bdrv_unref(old_bs);
|
||||
@@ -5720,7 +5720,7 @@ BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *options,
|
||||
bdrv_drained_begin(new_node_bs);
|
||||
bdrv_graph_wrlock(new_node_bs);
|
||||
ret = bdrv_replace_node(bs, new_node_bs, errp);
|
||||
bdrv_graph_wrunlock(new_node_bs);
|
||||
bdrv_graph_wrunlock();
|
||||
bdrv_drained_end(new_node_bs);
|
||||
bdrv_drained_end(bs);
|
||||
bdrv_unref(bs);
|
||||
@@ -6015,7 +6015,7 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
|
||||
* That's a FIXME.
|
||||
*/
|
||||
bdrv_replace_node_common(top, base, false, false, &local_err);
|
||||
bdrv_graph_wrunlock(base);
|
||||
bdrv_graph_wrunlock();
|
||||
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
@@ -6052,7 +6052,7 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
|
||||
goto exit;
|
||||
|
||||
exit_wrlock:
|
||||
bdrv_graph_wrunlock(base);
|
||||
bdrv_graph_wrunlock();
|
||||
exit:
|
||||
bdrv_drained_end(base);
|
||||
bdrv_unref(top);
|
||||
@@ -7254,16 +7254,6 @@ void bdrv_unref(BlockDriverState *bs)
|
||||
}
|
||||
}
|
||||
|
||||
static void bdrv_schedule_unref_bh(void *opaque)
|
||||
{
|
||||
BlockDriverState *bs = opaque;
|
||||
AioContext *ctx = bdrv_get_aio_context(bs);
|
||||
|
||||
aio_context_acquire(ctx);
|
||||
bdrv_unref(bs);
|
||||
aio_context_release(ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Release a BlockDriverState reference while holding the graph write lock.
|
||||
*
|
||||
@@ -7277,7 +7267,8 @@ void bdrv_schedule_unref(BlockDriverState *bs)
|
||||
if (!bs) {
|
||||
return;
|
||||
}
|
||||
aio_bh_schedule_oneshot(qemu_get_aio_context(), bdrv_schedule_unref_bh, bs);
|
||||
aio_bh_schedule_oneshot(qemu_get_aio_context(),
|
||||
(QEMUBHFunc *) bdrv_unref, bs);
|
||||
}
|
||||
|
||||
struct BdrvOpBlocker {
|
||||
|
||||
@@ -499,7 +499,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
bdrv_graph_wrlock(target);
|
||||
block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
|
||||
&error_abort);
|
||||
bdrv_graph_wrunlock(target);
|
||||
bdrv_graph_wrunlock();
|
||||
|
||||
return &job->common;
|
||||
|
||||
|
||||
@@ -253,7 +253,7 @@ fail_log:
|
||||
if (ret < 0) {
|
||||
bdrv_graph_wrlock(NULL);
|
||||
bdrv_unref_child(bs, s->log_file);
|
||||
bdrv_graph_wrunlock(NULL);
|
||||
bdrv_graph_wrunlock();
|
||||
s->log_file = NULL;
|
||||
}
|
||||
fail:
|
||||
@@ -268,7 +268,7 @@ static void blk_log_writes_close(BlockDriverState *bs)
|
||||
bdrv_graph_wrlock(NULL);
|
||||
bdrv_unref_child(bs, s->log_file);
|
||||
s->log_file = NULL;
|
||||
bdrv_graph_wrunlock(NULL);
|
||||
bdrv_graph_wrunlock();
|
||||
}
|
||||
|
||||
static int64_t coroutine_fn GRAPH_RDLOCK
|
||||
|
||||
@@ -154,7 +154,7 @@ static void blkverify_close(BlockDriverState *bs)
|
||||
bdrv_graph_wrlock(NULL);
|
||||
bdrv_unref_child(bs, s->test_file);
|
||||
s->test_file = NULL;
|
||||
bdrv_graph_wrunlock(NULL);
|
||||
bdrv_graph_wrunlock();
|
||||
}
|
||||
|
||||
static int64_t coroutine_fn GRAPH_RDLOCK
|
||||
|
||||
@@ -882,14 +882,11 @@ BlockBackend *blk_by_public(BlockBackendPublic *public)
|
||||
|
||||
/*
|
||||
* Disassociates the currently associated BlockDriverState from @blk.
|
||||
*
|
||||
* The caller must hold the AioContext lock for the BlockBackend.
|
||||
*/
|
||||
void blk_remove_bs(BlockBackend *blk)
|
||||
{
|
||||
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
|
||||
BdrvChild *root;
|
||||
AioContext *ctx;
|
||||
|
||||
GLOBAL_STATE_CODE();
|
||||
|
||||
@@ -919,10 +916,9 @@ void blk_remove_bs(BlockBackend *blk)
|
||||
root = blk->root;
|
||||
blk->root = NULL;
|
||||
|
||||
ctx = bdrv_get_aio_context(root->bs);
|
||||
bdrv_graph_wrlock(root->bs);
|
||||
bdrv_graph_wrlock(NULL);
|
||||
bdrv_root_unref_child(root);
|
||||
bdrv_graph_wrunlock_ctx(ctx);
|
||||
bdrv_graph_wrunlock();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -933,8 +929,6 @@ void blk_remove_bs(BlockBackend *blk)
|
||||
int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
|
||||
{
|
||||
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
|
||||
AioContext *ctx = bdrv_get_aio_context(bs);
|
||||
|
||||
GLOBAL_STATE_CODE();
|
||||
bdrv_ref(bs);
|
||||
bdrv_graph_wrlock(bs);
|
||||
@@ -942,7 +936,7 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
|
||||
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
|
||||
blk->perm, blk->shared_perm,
|
||||
blk, errp);
|
||||
bdrv_graph_wrunlock_ctx(ctx);
|
||||
bdrv_graph_wrunlock();
|
||||
if (blk->root == NULL) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ static void commit_abort(Job *job)
|
||||
bdrv_drained_begin(commit_top_backing_bs);
|
||||
bdrv_graph_wrlock(commit_top_backing_bs);
|
||||
bdrv_replace_node(s->commit_top_bs, commit_top_backing_bs, &error_abort);
|
||||
bdrv_graph_wrunlock(commit_top_backing_bs);
|
||||
bdrv_graph_wrunlock();
|
||||
bdrv_drained_end(commit_top_backing_bs);
|
||||
|
||||
bdrv_unref(s->commit_top_bs);
|
||||
@@ -370,19 +370,19 @@ void commit_start(const char *job_id, BlockDriverState *bs,
|
||||
ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
|
||||
iter_shared_perms, errp);
|
||||
if (ret < 0) {
|
||||
bdrv_graph_wrunlock(top);
|
||||
bdrv_graph_wrunlock();
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (bdrv_freeze_backing_chain(commit_top_bs, base, errp) < 0) {
|
||||
bdrv_graph_wrunlock(top);
|
||||
bdrv_graph_wrunlock();
|
||||
goto fail;
|
||||
}
|
||||
s->chain_frozen = true;
|
||||
|
||||
ret = block_job_add_bdrv(&s->common, "base", base, 0, BLK_PERM_ALL, errp);
|
||||
bdrv_graph_wrunlock(top);
|
||||
bdrv_graph_wrunlock();
|
||||
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
@@ -436,7 +436,7 @@ fail:
|
||||
bdrv_drained_begin(top);
|
||||
bdrv_graph_wrlock(top);
|
||||
bdrv_replace_node(commit_top_bs, top, &error_abort);
|
||||
bdrv_graph_wrunlock(top);
|
||||
bdrv_graph_wrunlock();
|
||||
bdrv_drained_end(top);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,7 +283,6 @@ static void vu_blk_drained_begin(void *opaque)
|
||||
{
|
||||
VuBlkExport *vexp = opaque;
|
||||
|
||||
vexp->vu_server.quiescing = true;
|
||||
vhost_user_server_detach_aio_context(&vexp->vu_server);
|
||||
}
|
||||
|
||||
@@ -292,23 +291,19 @@ static void vu_blk_drained_end(void *opaque)
|
||||
{
|
||||
VuBlkExport *vexp = opaque;
|
||||
|
||||
vexp->vu_server.quiescing = false;
|
||||
vhost_user_server_attach_aio_context(&vexp->vu_server, vexp->export.ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensures that bdrv_drained_begin() waits until in-flight requests complete
|
||||
* and the server->co_trip coroutine has terminated. It will be restarted in
|
||||
* vhost_user_server_attach_aio_context().
|
||||
* Ensures that bdrv_drained_begin() waits until in-flight requests complete.
|
||||
*
|
||||
* Called with vexp->export.ctx acquired.
|
||||
*/
|
||||
static bool vu_blk_drained_poll(void *opaque)
|
||||
{
|
||||
VuBlkExport *vexp = opaque;
|
||||
VuServer *server = &vexp->vu_server;
|
||||
|
||||
return server->co_trip || vhost_user_server_has_in_flight(server);
|
||||
return vhost_user_server_has_in_flight(&vexp->vu_server);
|
||||
}
|
||||
|
||||
static const BlockDevOps vu_blk_dev_ops = {
|
||||
|
||||
@@ -161,21 +161,11 @@ void no_coroutine_fn bdrv_graph_wrlock(BlockDriverState *bs)
|
||||
}
|
||||
}
|
||||
|
||||
void no_coroutine_fn bdrv_graph_wrunlock_ctx(AioContext *ctx)
|
||||
void bdrv_graph_wrunlock(void)
|
||||
{
|
||||
GLOBAL_STATE_CODE();
|
||||
assert(qatomic_read(&has_writer));
|
||||
|
||||
/*
|
||||
* Release only non-mainloop AioContext. The mainloop often relies on the
|
||||
* BQL and doesn't lock the main AioContext before doing things.
|
||||
*/
|
||||
if (ctx && ctx != qemu_get_aio_context()) {
|
||||
aio_context_release(ctx);
|
||||
} else {
|
||||
ctx = NULL;
|
||||
}
|
||||
|
||||
WITH_QEMU_LOCK_GUARD(&aio_context_list_lock) {
|
||||
/*
|
||||
* No need for memory barriers, this works in pair with
|
||||
@@ -197,17 +187,6 @@ void no_coroutine_fn bdrv_graph_wrunlock_ctx(AioContext *ctx)
|
||||
* progress.
|
||||
*/
|
||||
aio_bh_poll(qemu_get_aio_context());
|
||||
|
||||
if (ctx) {
|
||||
aio_context_acquire(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
void no_coroutine_fn bdrv_graph_wrunlock(BlockDriverState *bs)
|
||||
{
|
||||
AioContext *ctx = bs ? bdrv_get_aio_context(bs) : NULL;
|
||||
|
||||
bdrv_graph_wrunlock_ctx(ctx);
|
||||
}
|
||||
|
||||
void coroutine_fn bdrv_graph_co_rdlock(void)
|
||||
|
||||
@@ -773,7 +773,7 @@ static int mirror_exit_common(Job *job)
|
||||
"would not lead to an abrupt change of visible data",
|
||||
to_replace->node_name, target_bs->node_name);
|
||||
}
|
||||
bdrv_graph_wrunlock(target_bs);
|
||||
bdrv_graph_wrunlock();
|
||||
bdrv_drained_end(to_replace);
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
@@ -798,7 +798,7 @@ static int mirror_exit_common(Job *job)
|
||||
block_job_remove_all_bdrv(bjob);
|
||||
bdrv_graph_wrlock(mirror_top_bs);
|
||||
bdrv_replace_node(mirror_top_bs, mirror_top_bs->backing->bs, &error_abort);
|
||||
bdrv_graph_wrunlock(mirror_top_bs);
|
||||
bdrv_graph_wrunlock();
|
||||
|
||||
bdrv_drained_end(target_bs);
|
||||
bdrv_unref(target_bs);
|
||||
@@ -1920,7 +1920,7 @@ static BlockJob *mirror_start_job(
|
||||
BLK_PERM_CONSISTENT_READ,
|
||||
errp);
|
||||
if (ret < 0) {
|
||||
bdrv_graph_wrunlock(bs);
|
||||
bdrv_graph_wrunlock();
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -1965,17 +1965,17 @@ static BlockJob *mirror_start_job(
|
||||
ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
|
||||
iter_shared_perms, errp);
|
||||
if (ret < 0) {
|
||||
bdrv_graph_wrunlock(bs);
|
||||
bdrv_graph_wrunlock();
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (bdrv_freeze_backing_chain(mirror_top_bs, target, errp) < 0) {
|
||||
bdrv_graph_wrunlock(bs);
|
||||
bdrv_graph_wrunlock();
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
bdrv_graph_wrunlock(bs);
|
||||
bdrv_graph_wrunlock();
|
||||
|
||||
QTAILQ_INIT(&s->ops_in_flight);
|
||||
|
||||
@@ -2006,7 +2006,7 @@ fail:
|
||||
bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing,
|
||||
&error_abort);
|
||||
bdrv_replace_node(mirror_top_bs, bs, &error_abort);
|
||||
bdrv_graph_wrunlock(bs);
|
||||
bdrv_graph_wrunlock();
|
||||
bdrv_drained_end(bs);
|
||||
|
||||
bdrv_unref(mirror_top_bs);
|
||||
|
||||
@@ -2809,7 +2809,7 @@ qcow2_do_close(BlockDriverState *bs, bool close_data_file)
|
||||
bdrv_graph_rdunlock_main_loop();
|
||||
bdrv_graph_wrlock(NULL);
|
||||
bdrv_unref_child(bs, s->data_file);
|
||||
bdrv_graph_wrunlock(NULL);
|
||||
bdrv_graph_wrunlock();
|
||||
s->data_file = NULL;
|
||||
bdrv_graph_rdlock_main_loop();
|
||||
}
|
||||
|
||||
@@ -1044,7 +1044,7 @@ close_exit:
|
||||
}
|
||||
bdrv_unref_child(bs, s->children[i]);
|
||||
}
|
||||
bdrv_graph_wrunlock(NULL);
|
||||
bdrv_graph_wrunlock();
|
||||
g_free(s->children);
|
||||
g_free(opened);
|
||||
exit:
|
||||
@@ -1061,7 +1061,7 @@ static void quorum_close(BlockDriverState *bs)
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
bdrv_unref_child(bs, s->children[i]);
|
||||
}
|
||||
bdrv_graph_wrunlock(NULL);
|
||||
bdrv_graph_wrunlock();
|
||||
|
||||
g_free(s->children);
|
||||
}
|
||||
|
||||
@@ -568,7 +568,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
bdrv_graph_wrunlock(bs);
|
||||
bdrv_graph_wrunlock();
|
||||
aio_context_release(aio_context);
|
||||
return;
|
||||
}
|
||||
@@ -579,7 +579,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
|
||||
BDRV_CHILD_DATA, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
bdrv_graph_wrunlock(bs);
|
||||
bdrv_graph_wrunlock();
|
||||
aio_context_release(aio_context);
|
||||
return;
|
||||
}
|
||||
@@ -592,7 +592,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
|
||||
if (!top_bs || !bdrv_is_root_node(top_bs) ||
|
||||
!check_top_bs(top_bs, bs)) {
|
||||
error_setg(errp, "No top_bs or it is invalid");
|
||||
bdrv_graph_wrunlock(bs);
|
||||
bdrv_graph_wrunlock();
|
||||
reopen_backing_file(bs, false, NULL);
|
||||
aio_context_release(aio_context);
|
||||
return;
|
||||
@@ -600,7 +600,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
|
||||
bdrv_op_block_all(top_bs, s->blocker);
|
||||
bdrv_op_unblock(top_bs, BLOCK_OP_TYPE_DATAPLANE, s->blocker);
|
||||
|
||||
bdrv_graph_wrunlock(bs);
|
||||
bdrv_graph_wrunlock();
|
||||
|
||||
s->backup_job = backup_job_create(
|
||||
NULL, s->secondary_disk->bs, s->hidden_disk->bs,
|
||||
@@ -696,7 +696,7 @@ static void replication_done(void *opaque, int ret)
|
||||
s->secondary_disk = NULL;
|
||||
bdrv_unref_child(bs, s->hidden_disk);
|
||||
s->hidden_disk = NULL;
|
||||
bdrv_graph_wrunlock(NULL);
|
||||
bdrv_graph_wrunlock();
|
||||
|
||||
s->error = 0;
|
||||
} else {
|
||||
|
||||
@@ -292,7 +292,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
|
||||
/* .bdrv_open() will re-attach it */
|
||||
bdrv_graph_wrlock(NULL);
|
||||
bdrv_unref_child(bs, fallback);
|
||||
bdrv_graph_wrunlock(NULL);
|
||||
bdrv_graph_wrunlock();
|
||||
|
||||
ret = bdrv_snapshot_goto(fallback_bs, snapshot_id, errp);
|
||||
open_ret = drv->bdrv_open(bs, options, bs->open_flags, &local_err);
|
||||
|
||||
@@ -99,9 +99,9 @@ static int stream_prepare(Job *job)
|
||||
}
|
||||
}
|
||||
|
||||
bdrv_graph_wrlock(s->target_bs);
|
||||
bdrv_graph_wrlock(base);
|
||||
bdrv_set_backing_hd_drained(unfiltered_bs, base, &local_err);
|
||||
bdrv_graph_wrunlock(s->target_bs);
|
||||
bdrv_graph_wrunlock();
|
||||
|
||||
/*
|
||||
* This call will do I/O, so the graph can change again from here on.
|
||||
@@ -369,7 +369,7 @@ void stream_start(const char *job_id, BlockDriverState *bs,
|
||||
bdrv_graph_wrlock(bs);
|
||||
if (block_job_add_bdrv(&s->common, "active node", bs, 0,
|
||||
basic_flags | BLK_PERM_WRITE, errp)) {
|
||||
bdrv_graph_wrunlock(bs);
|
||||
bdrv_graph_wrunlock();
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -389,11 +389,11 @@ void stream_start(const char *job_id, BlockDriverState *bs,
|
||||
ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
|
||||
basic_flags, errp);
|
||||
if (ret < 0) {
|
||||
bdrv_graph_wrunlock(bs);
|
||||
bdrv_graph_wrunlock();
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
bdrv_graph_wrunlock(bs);
|
||||
bdrv_graph_wrunlock();
|
||||
|
||||
s->base_overlay = base_overlay;
|
||||
s->above_base = above_base;
|
||||
|
||||
38
block/vmdk.c
38
block/vmdk.c
@@ -283,7 +283,7 @@ static void vmdk_free_extents(BlockDriverState *bs)
|
||||
bdrv_unref_child(bs, e->file);
|
||||
}
|
||||
}
|
||||
bdrv_graph_wrunlock(NULL);
|
||||
bdrv_graph_wrunlock();
|
||||
|
||||
g_free(s->extents);
|
||||
}
|
||||
@@ -351,41 +351,29 @@ vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
int ret = 0;
|
||||
|
||||
size_t desc_buf_size;
|
||||
|
||||
if (s->desc_offset == 0) {
|
||||
desc_buf_size = bdrv_getlength(bs->file->bs);
|
||||
if (desc_buf_size > 16ULL << 20) {
|
||||
error_report("VMDK description file too big");
|
||||
return -EFBIG;
|
||||
}
|
||||
} else {
|
||||
desc_buf_size = DESC_SIZE;
|
||||
}
|
||||
|
||||
desc = g_malloc0(desc_buf_size);
|
||||
tmp_desc = g_malloc0(desc_buf_size);
|
||||
ret = bdrv_co_pread(bs->file, s->desc_offset, desc_buf_size, desc, 0);
|
||||
desc = g_malloc0(DESC_SIZE);
|
||||
tmp_desc = g_malloc0(DESC_SIZE);
|
||||
ret = bdrv_co_pread(bs->file, s->desc_offset, DESC_SIZE, desc, 0);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
desc[desc_buf_size - 1] = '\0';
|
||||
desc[DESC_SIZE - 1] = '\0';
|
||||
tmp_str = strstr(desc, "parentCID");
|
||||
if (tmp_str == NULL) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
pstrcpy(tmp_desc, desc_buf_size, tmp_str);
|
||||
pstrcpy(tmp_desc, DESC_SIZE, tmp_str);
|
||||
p_name = strstr(desc, "CID");
|
||||
if (p_name != NULL) {
|
||||
p_name += sizeof("CID");
|
||||
snprintf(p_name, desc_buf_size - (p_name - desc), "%" PRIx32 "\n", cid);
|
||||
pstrcat(desc, desc_buf_size, tmp_desc);
|
||||
snprintf(p_name, DESC_SIZE - (p_name - desc), "%" PRIx32 "\n", cid);
|
||||
pstrcat(desc, DESC_SIZE, tmp_desc);
|
||||
}
|
||||
|
||||
ret = bdrv_co_pwrite_sync(bs->file, s->desc_offset, desc_buf_size, desc, 0);
|
||||
ret = bdrv_co_pwrite_sync(bs->file, s->desc_offset, DESC_SIZE, desc, 0);
|
||||
|
||||
out:
|
||||
g_free(desc);
|
||||
@@ -1249,7 +1237,7 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
|
||||
bdrv_graph_rdunlock_main_loop();
|
||||
bdrv_graph_wrlock(NULL);
|
||||
bdrv_unref_child(bs, extent_file);
|
||||
bdrv_graph_wrunlock(NULL);
|
||||
bdrv_graph_wrunlock();
|
||||
bdrv_graph_rdlock_main_loop();
|
||||
goto out;
|
||||
}
|
||||
@@ -1268,7 +1256,7 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
|
||||
bdrv_graph_rdunlock_main_loop();
|
||||
bdrv_graph_wrlock(NULL);
|
||||
bdrv_unref_child(bs, extent_file);
|
||||
bdrv_graph_wrunlock(NULL);
|
||||
bdrv_graph_wrunlock();
|
||||
bdrv_graph_rdlock_main_loop();
|
||||
goto out;
|
||||
}
|
||||
@@ -1279,7 +1267,7 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
|
||||
bdrv_graph_rdunlock_main_loop();
|
||||
bdrv_graph_wrlock(NULL);
|
||||
bdrv_unref_child(bs, extent_file);
|
||||
bdrv_graph_wrunlock(NULL);
|
||||
bdrv_graph_wrunlock();
|
||||
bdrv_graph_rdlock_main_loop();
|
||||
goto out;
|
||||
}
|
||||
@@ -1289,7 +1277,7 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
|
||||
bdrv_graph_rdunlock_main_loop();
|
||||
bdrv_graph_wrlock(NULL);
|
||||
bdrv_unref_child(bs, extent_file);
|
||||
bdrv_graph_wrunlock(NULL);
|
||||
bdrv_graph_wrunlock();
|
||||
bdrv_graph_rdlock_main_loop();
|
||||
ret = -ENOTSUP;
|
||||
goto out;
|
||||
|
||||
@@ -1613,7 +1613,7 @@ static void external_snapshot_abort(void *opaque)
|
||||
bdrv_drained_begin(state->new_bs);
|
||||
bdrv_graph_wrlock(state->old_bs);
|
||||
bdrv_replace_node(state->new_bs, state->old_bs, &error_abort);
|
||||
bdrv_graph_wrunlock(state->old_bs);
|
||||
bdrv_graph_wrunlock();
|
||||
bdrv_drained_end(state->new_bs);
|
||||
|
||||
bdrv_unref(state->old_bs); /* bdrv_replace_node() ref'ed old_bs */
|
||||
@@ -3692,7 +3692,7 @@ void qmp_x_blockdev_change(const char *parent, const char *child,
|
||||
}
|
||||
|
||||
out:
|
||||
bdrv_graph_wrunlock(NULL);
|
||||
bdrv_graph_wrunlock();
|
||||
}
|
||||
|
||||
BlockJobInfoList *qmp_query_block_jobs(Error **errp)
|
||||
|
||||
@@ -212,7 +212,7 @@ void block_job_remove_all_bdrv(BlockJob *job)
|
||||
|
||||
g_slist_free_1(l);
|
||||
}
|
||||
bdrv_graph_wrunlock_ctx(job->job.aio_context);
|
||||
bdrv_graph_wrunlock();
|
||||
}
|
||||
|
||||
bool block_job_has_bdrv(BlockJob *job, BlockDriverState *bs)
|
||||
@@ -523,7 +523,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
|
||||
job = job_create(job_id, &driver->job_driver, txn, bdrv_get_aio_context(bs),
|
||||
flags, cb, opaque, errp);
|
||||
if (job == NULL) {
|
||||
bdrv_graph_wrunlock(bs);
|
||||
bdrv_graph_wrunlock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -563,11 +563,11 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bdrv_graph_wrunlock(bs);
|
||||
bdrv_graph_wrunlock();
|
||||
return job;
|
||||
|
||||
fail:
|
||||
bdrv_graph_wrunlock(bs);
|
||||
bdrv_graph_wrunlock();
|
||||
job_early_fail(&job->job);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -235,7 +235,7 @@ static inline abi_long do_obreak(abi_ulong brk_val)
|
||||
return target_brk;
|
||||
}
|
||||
|
||||
/* Release heap if necessary */
|
||||
/* Release heap if necesary */
|
||||
if (new_brk < old_brk) {
|
||||
target_munmap(new_brk, old_brk - new_brk);
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
|
||||
}
|
||||
|
||||
qarg0 = argp = g_new0(char *, argc + 9);
|
||||
/* save the first argument for the emulator */
|
||||
/* save the first agrument for the emulator */
|
||||
*argp++ = (char *)getprogname();
|
||||
qargp = argp;
|
||||
*argp++ = (char *)getprogname();
|
||||
|
||||
@@ -146,7 +146,7 @@ static inline abi_long do_freebsd_fstatat(abi_long arg1, abi_long arg2,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* undocumented nstat(char *path, struct nstat *ub) syscall */
|
||||
/* undocummented nstat(char *path, struct nstat *ub) syscall */
|
||||
static abi_long do_freebsd11_nstat(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
@@ -162,7 +162,7 @@ static abi_long do_freebsd11_nstat(abi_long arg1, abi_long arg2)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* undocumented nfstat(int fd, struct nstat *sb) syscall */
|
||||
/* undocummented nfstat(int fd, struct nstat *sb) syscall */
|
||||
static abi_long do_freebsd11_nfstat(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
@@ -175,7 +175,7 @@ static abi_long do_freebsd11_nfstat(abi_long arg1, abi_long arg2)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* undocumented nlstat(char *path, struct nstat *ub) syscall */
|
||||
/* undocummented nlstat(char *path, struct nstat *ub) syscall */
|
||||
static abi_long do_freebsd11_nlstat(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#CONFIG_QXL=n
|
||||
#CONFIG_SEV=n
|
||||
#CONFIG_SGA=n
|
||||
#CONFIG_TDX=n
|
||||
#CONFIG_TEST_DEVICES=n
|
||||
#CONFIG_TPM_CRB=n
|
||||
#CONFIG_TPM_TIS_ISA=n
|
||||
|
||||
48
configure
vendored
48
configure
vendored
@@ -41,7 +41,12 @@ then
|
||||
# This file is auto-generated by configure to support in-source tree
|
||||
# 'make' command invocation
|
||||
|
||||
build:
|
||||
ifeq ($(MAKECMDGOALS),)
|
||||
recurse: all
|
||||
endif
|
||||
|
||||
.NOTPARALLEL: %
|
||||
%: force
|
||||
@echo 'changing dir to build for $(MAKE) "$(MAKECMDGOALS)"...'
|
||||
@$(MAKE) -C build -f Makefile $(MAKECMDGOALS)
|
||||
@if test "$(MAKECMDGOALS)" = "distclean" && \
|
||||
@@ -49,9 +54,8 @@ build:
|
||||
then \
|
||||
rm -rf build GNUmakefile ; \
|
||||
fi
|
||||
%: build
|
||||
@
|
||||
.PHONY: build
|
||||
force: ;
|
||||
.PHONY: force
|
||||
GNUmakefile: ;
|
||||
|
||||
EOF
|
||||
@@ -964,14 +968,14 @@ meson="$(cd pyvenv/bin; pwd)/meson"
|
||||
|
||||
# Conditionally ensure Sphinx is installed.
|
||||
|
||||
mkvenv_online_flag=""
|
||||
if test "$download" = "enabled" ; then
|
||||
mkvenv_online_flag=" --online"
|
||||
mkvenv_flags=""
|
||||
if test "$download" = "enabled" -a "$docs" = "enabled" ; then
|
||||
mkvenv_flags="--online"
|
||||
fi
|
||||
|
||||
if test "$docs" != "disabled" ; then
|
||||
if ! $mkvenv ensuregroup \
|
||||
$(test "$docs" = "enabled" && echo "$mkvenv_online_flag") \
|
||||
$mkvenv_flags \
|
||||
${source_path}/pythondeps.toml docs;
|
||||
then
|
||||
if test "$docs" = "enabled" ; then
|
||||
@@ -1303,8 +1307,8 @@ probe_target_compiler() {
|
||||
container_cross_cc=${container_cross_prefix}gcc
|
||||
;;
|
||||
i386)
|
||||
container_image=debian-i686-cross
|
||||
container_cross_prefix=i686-linux-gnu-
|
||||
container_image=fedora-i386-cross
|
||||
container_cross_prefix=
|
||||
;;
|
||||
loongarch64)
|
||||
container_image=debian-loongarch-cross
|
||||
@@ -1387,19 +1391,16 @@ probe_target_compiler() {
|
||||
done
|
||||
|
||||
try=cross
|
||||
# For softmmu/roms we might be able to use the host compiler
|
||||
if [ "${1%softmmu}" != "$1" ]; then
|
||||
case "$target_arch:$cpu" in
|
||||
aarch64_be:aarch64 | \
|
||||
armeb:arm | \
|
||||
i386:x86_64 | \
|
||||
mips*:mips64 | \
|
||||
ppc*:ppc64 | \
|
||||
sparc:sparc64 | \
|
||||
"$cpu:$cpu")
|
||||
try='native cross' ;;
|
||||
esac
|
||||
fi
|
||||
case "$target_arch:$cpu" in
|
||||
aarch64_be:aarch64 | \
|
||||
armeb:arm | \
|
||||
i386:x86_64 | \
|
||||
mips*:mips64 | \
|
||||
ppc*:ppc64 | \
|
||||
sparc:sparc64 | \
|
||||
"$cpu:$cpu")
|
||||
try='native cross' ;;
|
||||
esac
|
||||
eval "target_cflags=\${cross_cc_cflags_$target_arch}"
|
||||
for thistry in $try; do
|
||||
case $thistry in
|
||||
@@ -1630,7 +1631,6 @@ if test "$container" != no; then
|
||||
fi
|
||||
echo "SUBDIRS=$subdirs" >> $config_host_mak
|
||||
echo "PYTHON=$python" >> $config_host_mak
|
||||
echo "MKVENV_ENSUREGROUP=$mkvenv ensuregroup $mkvenv_online_flag" >> $config_host_mak
|
||||
echo "GENISOIMAGE=$genisoimage" >> $config_host_mak
|
||||
echo "MESON=$meson" >> $config_host_mak
|
||||
echo "NINJA=$ninja" >> $config_host_mak
|
||||
|
||||
@@ -49,7 +49,7 @@ all: $(SONAMES)
|
||||
$(CC) $(CFLAGS) $(PLUGIN_CFLAGS) -c -o $@ $<
|
||||
|
||||
ifeq ($(CONFIG_WIN32),y)
|
||||
lib%$(SO_SUFFIX): %.o win32_linker.o ../../plugins/libqemu_plugin_api.a
|
||||
lib%$(SO_SUFFIX): %.o win32_linker.o ../../plugins/qemu_plugin_api.lib
|
||||
$(CC) -shared -o $@ $^ $(LDLIBS)
|
||||
else ifeq ($(CONFIG_DARWIN),y)
|
||||
lib%$(SO_SUFFIX): %.o
|
||||
|
||||
@@ -401,7 +401,7 @@ virgl_cmd_set_scanout(VuGpu *g,
|
||||
|
||||
if (g->use_modifiers) {
|
||||
/*
|
||||
* The message uses all the fields set in dmabuf_scanout plus
|
||||
* The mesage uses all the fields set in dmabuf_scanout plus
|
||||
* modifiers which is appended after VhostUserGpuDMABUFScanout.
|
||||
*/
|
||||
msg.request = VHOST_USER_GPU_DMABUF_SCANOUT2;
|
||||
|
||||
26
disas/cris.c
26
disas/cris.c
@@ -1731,10 +1731,10 @@ format_hex (unsigned long number,
|
||||
unsigned (== 0). */
|
||||
|
||||
static char *
|
||||
format_dec (long number, char *outbuffer, size_t outsize, int signedp)
|
||||
format_dec (long number, char *outbuffer, int signedp)
|
||||
{
|
||||
last_immediate = number;
|
||||
snprintf (outbuffer, outsize, signedp ? "%ld" : "%lu", number);
|
||||
sprintf (outbuffer, signedp ? "%ld" : "%lu", number);
|
||||
|
||||
return outbuffer + strlen (outbuffer);
|
||||
}
|
||||
@@ -1876,12 +1876,6 @@ print_flags (struct cris_disasm_data *disdata, unsigned int insn, char *cp)
|
||||
return cp;
|
||||
}
|
||||
|
||||
#define FORMAT_DEC(number, tp, signedp) \
|
||||
format_dec (number, tp, ({ \
|
||||
assert(tp >= temp && tp <= temp + sizeof(temp)); \
|
||||
temp + sizeof(temp) - tp; \
|
||||
}), signedp)
|
||||
|
||||
/* Print out an insn with its operands, and update the info->insn_type
|
||||
fields. The prefix_opcodep and the rest hold a prefix insn that is
|
||||
supposed to be output as an address mode. */
|
||||
@@ -2111,7 +2105,7 @@ print_with_operands (const struct cris_opcode *opcodep,
|
||||
if ((*cs == 'z' && (insn & 0x20))
|
||||
|| (opcodep->match == BDAP_QUICK_OPCODE
|
||||
&& (nbytes <= 2 || buffer[1 + nbytes] == 0)))
|
||||
tp = FORMAT_DEC (number, tp, signedp);
|
||||
tp = format_dec (number, tp, signedp);
|
||||
else
|
||||
{
|
||||
unsigned int highbyte = (number >> 24) & 0xff;
|
||||
@@ -2247,7 +2241,7 @@ print_with_operands (const struct cris_opcode *opcodep,
|
||||
with_reg_prefix);
|
||||
if (number >= 0)
|
||||
*tp++ = '+';
|
||||
tp = FORMAT_DEC (number, tp, 1);
|
||||
tp = format_dec (number, tp, 1);
|
||||
|
||||
info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG;
|
||||
info->target = (prefix_insn >> 12) & 15;
|
||||
@@ -2346,7 +2340,7 @@ print_with_operands (const struct cris_opcode *opcodep,
|
||||
{
|
||||
if (number >= 0)
|
||||
*tp++ = '+';
|
||||
tp = FORMAT_DEC (number, tp, 1);
|
||||
tp = format_dec (number, tp, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -2403,7 +2397,7 @@ print_with_operands (const struct cris_opcode *opcodep,
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
tp = FORMAT_DEC (insn & 63, tp, 0);
|
||||
tp = format_dec (insn & 63, tp, 0);
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
@@ -2432,11 +2426,11 @@ print_with_operands (const struct cris_opcode *opcodep,
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
tp = FORMAT_DEC (insn & 31, tp, 0);
|
||||
tp = format_dec (insn & 31, tp, 0);
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
tp = FORMAT_DEC (insn & 15, tp, 0);
|
||||
tp = format_dec (insn & 15, tp, 0);
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
@@ -2469,7 +2463,7 @@ print_with_operands (const struct cris_opcode *opcodep,
|
||||
if (number > 127)
|
||||
number = number - 256;
|
||||
|
||||
tp = FORMAT_DEC (number, tp, 1);
|
||||
tp = format_dec (number, tp, 1);
|
||||
*tp++ = ',';
|
||||
tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix);
|
||||
}
|
||||
@@ -2480,7 +2474,7 @@ print_with_operands (const struct cris_opcode *opcodep,
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
tp = FORMAT_DEC ((insn & 32) ? (insn & 31) | ~31L : insn & 31, tp, 1);
|
||||
tp = format_dec ((insn & 32) ? (insn & 31) | ~31L : insn & 31, tp, 1);
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
|
||||
@@ -1968,10 +1968,6 @@ print_insn_hppa (bfd_vma memaddr, disassemble_info *info)
|
||||
|
||||
insn = bfd_getb32 (buffer);
|
||||
|
||||
info->fprintf_func(info->stream, " %02x %02x %02x %02x ",
|
||||
(insn >> 24) & 0xff, (insn >> 16) & 0xff,
|
||||
(insn >> 8) & 0xff, insn & 0xff);
|
||||
|
||||
for (i = 0; i < NUMOPCODES; ++i)
|
||||
{
|
||||
const struct pa_opcode *opcode = &pa_opcodes[i];
|
||||
@@ -2830,6 +2826,6 @@ print_insn_hppa (bfd_vma memaddr, disassemble_info *info)
|
||||
return sizeof (insn);
|
||||
}
|
||||
}
|
||||
info->fprintf_func(info->stream, "<unknown>");
|
||||
(*info->fprintf_func) (info->stream, "#%8x", insn);
|
||||
return sizeof (insn);
|
||||
}
|
||||
|
||||
@@ -236,16 +236,6 @@ it. Since all recent x86 hardware from the past >10 years is capable of the
|
||||
64-bit x86 extensions, a corresponding 64-bit OS should be used instead.
|
||||
|
||||
|
||||
System emulator CPUs
|
||||
--------------------
|
||||
|
||||
Nios II CPU (since 8.2)
|
||||
'''''''''''''''''''''''
|
||||
|
||||
The Nios II architecture is orphan. The ``nios2`` guest CPU support is
|
||||
deprecated and will be removed in a future version of QEMU.
|
||||
|
||||
|
||||
System emulator machines
|
||||
------------------------
|
||||
|
||||
@@ -264,11 +254,6 @@ These old machine types are quite neglected nowadays and thus might have
|
||||
various pitfalls with regards to live migration. Use a newer machine type
|
||||
instead.
|
||||
|
||||
Nios II ``10m50-ghrd`` and ``nios2-generic-nommu`` machines (since 8.2)
|
||||
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
The Nios II architecture is orphan.
|
||||
|
||||
|
||||
Backend options
|
||||
---------------
|
||||
@@ -529,5 +514,5 @@ old compression method (since 8.2)
|
||||
|
||||
Compression method fails too much. Too many races. We are going to
|
||||
remove it if nobody fixes it. For starters, migration-test
|
||||
compression tests are disabled because they fail randomly. If you need
|
||||
compression tests are disabled becase they fail randomly. If you need
|
||||
compression, use multifd compression methods.
|
||||
|
||||
@@ -129,9 +129,8 @@ causing most hypervisors to trap and fault on them.
|
||||
.. warning::
|
||||
Semihosting inherently bypasses any isolation there may be between
|
||||
the guest and the host. As a result a program using semihosting can
|
||||
happily trash your host system. Some semihosting calls (e.g.
|
||||
``SYS_READC``) can block execution indefinitely. You should only
|
||||
ever run trusted code with semihosting enabled.
|
||||
happily trash your host system. You should only ever run trusted
|
||||
code with semihosting enabled.
|
||||
|
||||
Redirection
|
||||
~~~~~~~~~~~
|
||||
|
||||
@@ -122,78 +122,10 @@ functioning. These are performed using a few more helper functions:
|
||||
indicated by $TMPC.
|
||||
|
||||
|
||||
Python virtual environments and the build process
|
||||
-------------------------------------------------
|
||||
|
||||
An important step in ``configure`` is to create a Python virtual
|
||||
environment (venv) during the configuration phase. The Python interpreter
|
||||
comes from the ``--python`` command line option, the ``$PYTHON`` variable
|
||||
from the environment, or the system PATH, in this order. The venv resides
|
||||
in the ``pyvenv`` directory in the build tree, and provides consistency
|
||||
in how the build process runs Python code.
|
||||
|
||||
At this stage, ``configure`` also queries the chosen Python interpreter
|
||||
about QEMU's build dependencies. Note that the build process does *not*
|
||||
look for ``meson``, ``sphinx-build`` or ``avocado`` binaries in the PATH;
|
||||
likewise, there are no options such as ``--meson`` or ``--sphinx-build``.
|
||||
This avoids a potential mismatch, where Meson and Sphinx binaries on the
|
||||
PATH might operate in a different Python environment than the one chosen
|
||||
by the user during the build process. On the other hand, it introduces
|
||||
a potential source of confusion where the user installs a dependency but
|
||||
``configure`` is not able to find it. When this happens, the dependency
|
||||
was installed in the ``site-packages`` directory of another interpreter,
|
||||
or with the wrong ``pip`` program.
|
||||
|
||||
If a package is available for the chosen interpreter, ``configure``
|
||||
prepares a small script that invokes it from the venv itself[#distlib]_.
|
||||
If not, ``configure`` can also optionally install dependencies in the
|
||||
virtual environment with ``pip``, either from wheels in ``python/wheels``
|
||||
or by downloading the package with PyPI. Downloading can be disabled with
|
||||
``--disable-download``; and anyway, it only happens when a ``configure``
|
||||
option (currently, only ``--enable-docs``) is explicitly enabled but
|
||||
the dependencies are not present[#pip]_.
|
||||
|
||||
.. [#distlib] The scripts are created based on the package's metadata,
|
||||
specifically the ``console_script`` entry points. This is the
|
||||
same mechanism that ``pip`` uses when installing a package.
|
||||
Currently, in all cases it would be possible to use ``python -m``
|
||||
instead of an entry point script, which makes this approach a
|
||||
bit overkill. On the other hand, creating the scripts is
|
||||
future proof and it makes the contents of the ``pyvenv/bin``
|
||||
directory more informative. Portability is also not an issue,
|
||||
because the Python Packaging Authority provides a package
|
||||
``distlib.scripts`` to perform this task.
|
||||
|
||||
.. [#pip] ``pip`` might also be used when running ``make check-avocado``
|
||||
if downloading is enabled, to ensure that Avocado is
|
||||
available.
|
||||
|
||||
The required versions of the packages are stored in a configuration file
|
||||
``pythondeps.toml``. The format is custom to QEMU, but it is documented
|
||||
at the top of the file itself and it should be easy to understand. The
|
||||
requirements should make it possible to use the version that is packaged
|
||||
that is provided by supported distros.
|
||||
|
||||
When dependencies are downloaded, instead, ``configure`` uses a "known
|
||||
good" version that is also listed in ``pythondeps.toml``. In this
|
||||
scenario, ``pythondeps.toml`` behaves like the "lock file" used by
|
||||
``cargo``, ``poetry`` or other dependency management systems.
|
||||
|
||||
|
||||
Bundled Python packages
|
||||
-----------------------
|
||||
|
||||
Python packages that are **mandatory** dependencies to build QEMU,
|
||||
but are not available in all supported distros, are bundled with the
|
||||
QEMU sources. Currently this includes Meson (outdated in CentOS 8
|
||||
and derivatives, Ubuntu 20.04 and 22.04, and openSUSE Leap) and tomli
|
||||
(absent in Ubuntu 20.04).
|
||||
|
||||
If you need to update these, please do so by modifying and rerunning
|
||||
``python/scripts/vendor.py``. This script embeds the sha256 hash of
|
||||
package sources and checks it. The pypi.org web site provides an easy
|
||||
way to retrieve the sha256 hash of the sources.
|
||||
Python virtual environments and the QEMU build system
|
||||
-----------------------------------------------------
|
||||
|
||||
TBD
|
||||
|
||||
Stage 2: Meson
|
||||
==============
|
||||
@@ -444,15 +376,6 @@ This is needed to obey the --python= option passed to the configure
|
||||
script, which may point to something other than the first python3
|
||||
binary on the path.
|
||||
|
||||
By the time Meson runs, Python dependencies are available in the virtual
|
||||
environment and should be invoked through the scripts that ``configure``
|
||||
places under ``pyvenv``. One way to do so is as follows, using Meson's
|
||||
``find_program`` function::
|
||||
|
||||
sphinx_build = find_program(
|
||||
fs.parent(python.full_path()) / 'sphinx-build',
|
||||
required: get_option('docs'))
|
||||
|
||||
|
||||
Stage 3: Make
|
||||
=============
|
||||
@@ -511,11 +434,6 @@ number of dynamically created files listed later.
|
||||
executables. Build rules for various subdirectories are included in
|
||||
other meson.build files spread throughout the QEMU source tree.
|
||||
|
||||
``python/scripts/mkvenv.py``
|
||||
A wrapper for the Python ``venv`` and ``distlib.scripts`` packages.
|
||||
It handles creating the virtual environment, creating scripts in
|
||||
``pyvenv/bin``, and calling ``pip`` to install dependencies.
|
||||
|
||||
``tests/Makefile.include``
|
||||
Rules for external test harnesses. These include the TCG tests
|
||||
and the Avocado-based integration tests.
|
||||
|
||||
@@ -1061,7 +1061,7 @@ QEMU version, in this case pc-5.1.
|
||||
|
||||
4 - qemu-5.1 -M pc-5.2 -> migrates to -> qemu-5.1 -M pc-5.2
|
||||
|
||||
This combination is not possible as the qemu-5.1 doesn't understand
|
||||
This combination is not possible as the qemu-5.1 doen't understand
|
||||
pc-5.2 machine type. So nothing to worry here.
|
||||
|
||||
Now it comes the interesting ones, when both QEMU processes are
|
||||
@@ -1214,8 +1214,8 @@ machine types to have the right value::
|
||||
...
|
||||
};
|
||||
|
||||
A device with different features on both sides
|
||||
----------------------------------------------
|
||||
A device with diferent features on both sides
|
||||
---------------------------------------------
|
||||
|
||||
Let's assume that we are using the same QEMU binary on both sides,
|
||||
just to make the things easier. But we have a device that has
|
||||
@@ -1294,12 +1294,12 @@ Host B:
|
||||
|
||||
$ qemu-system-x86_64 -cpu host,taa-no=off
|
||||
|
||||
And you would be able to migrate between them. It is responsibility
|
||||
And you would be able to migrate between them. It is responsability
|
||||
of the management application or of the user to make sure that the
|
||||
configuration is correct. QEMU doesn't know how to look at this kind
|
||||
of features in general.
|
||||
|
||||
Notice that we don't recommend to use -cpu host for migration. It is
|
||||
Notice that we don't recomend to use -cpu host for migration. It is
|
||||
used in this example because it makes the example simpler.
|
||||
|
||||
Other devices have worse control about individual features. If they
|
||||
|
||||
@@ -15,7 +15,7 @@ have default values:
|
||||
-smp 1,drawers=3,books=3,sockets=2,cores=2,maxcpus=36 \
|
||||
-device z14-s390x-cpu,core-id=19,entitlement=high \
|
||||
-device z14-s390x-cpu,core-id=11,entitlement=low \
|
||||
-device z14-s390x-cpu,core-id=12,entitlement=high \
|
||||
-device z14-s390x-cpu,core-id=112,entitlement=high \
|
||||
...
|
||||
|
||||
Additions to query-cpus-fast
|
||||
@@ -78,7 +78,7 @@ modifiers for all configured vCPUs.
|
||||
"dedicated": true,
|
||||
"thread-id": 537005,
|
||||
"props": {
|
||||
"core-id": 12,
|
||||
"core-id": 112,
|
||||
"socket-id": 0,
|
||||
"drawer-id": 3,
|
||||
"book-id": 2
|
||||
@@ -86,7 +86,7 @@ modifiers for all configured vCPUs.
|
||||
"cpu-state": "operating",
|
||||
"entitlement": "high",
|
||||
"qom-path": "/machine/peripheral-anon/device[2]",
|
||||
"cpu-index": 12,
|
||||
"cpu-index": 112,
|
||||
"target": "s390x"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -62,6 +62,12 @@ To deal with this case, when an I/O access is made we:
|
||||
- re-compile a single [1]_ instruction block for the current PC
|
||||
- exit the cpu loop and execute the re-compiled block
|
||||
|
||||
The new block is created with the CF_LAST_IO compile flag which
|
||||
ensures the final instruction translation starts with a call to
|
||||
gen_io_start() so we don't enter a perpetual loop constantly
|
||||
recompiling a single instruction block. For translators using the
|
||||
common translator_loop this is done automatically.
|
||||
|
||||
.. [1] sometimes two instructions if dealing with delay slots
|
||||
|
||||
Other I/O operations
|
||||
|
||||
@@ -1016,7 +1016,7 @@ class. Here's a simple usage example:
|
||||
self.vm.launch()
|
||||
res = self.vm.cmd('human-monitor-command',
|
||||
command_line='info version')
|
||||
self.assertRegex(res, r'^(\d+\.\d+\.\d)')
|
||||
self.assertRegexpMatches(res, r'^(\d+\.\d+\.\d)')
|
||||
|
||||
To execute your test, run:
|
||||
|
||||
@@ -1077,7 +1077,7 @@ and hypothetical example follows:
|
||||
'human-monitor-command',
|
||||
command_line='info version')
|
||||
|
||||
self.assertEqual(first_res, second_res, third_res)
|
||||
self.assertEquals(first_res, second_res, third_res)
|
||||
|
||||
At test "tear down", ``avocado_qemu.Test`` handles all the QEMUMachines
|
||||
shutdown.
|
||||
|
||||
@@ -70,7 +70,7 @@ the following architecture extensions:
|
||||
- FEAT_PAN2 (AT S1E1R and AT S1E1W instruction variants affected by PSTATE.PAN)
|
||||
- FEAT_PAN3 (Support for SCTLR_ELx.EPAN)
|
||||
- FEAT_PAuth (Pointer authentication)
|
||||
- FEAT_PAuth2 (Enhancements to pointer authentication)
|
||||
- FEAT_PAuth2 (Enhacements to pointer authentication)
|
||||
- FEAT_PMULL (PMULL, PMULL2 instructions)
|
||||
- FEAT_PMUv3p1 (PMU Extensions v3.1)
|
||||
- FEAT_PMUv3p4 (PMU Extensions v3.4)
|
||||
|
||||
@@ -38,6 +38,7 @@ Supported mechanisms
|
||||
Currently supported confidential guest mechanisms are:
|
||||
|
||||
* AMD Secure Encrypted Virtualization (SEV) (see :doc:`i386/amd-memory-encryption`)
|
||||
* Intel Trust Domain Extension (TDX) (see :doc:`i386/tdx`)
|
||||
* POWER Protected Execution Facility (PEF) (see :ref:`power-papr-protected-execution-facility-pef`)
|
||||
* s390x Protected Virtualization (PV) (see :doc:`s390x/protvirt`)
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ As TCG cannot track all memory accesses in user-mode there is no
|
||||
support for watchpoints.
|
||||
|
||||
Relocating code
|
||||
===============
|
||||
---------------
|
||||
|
||||
On modern kernels confusion can be caused by code being relocated by
|
||||
features such as address space layout randomisation. To avoid
|
||||
@@ -68,17 +68,6 @@ confusion when debugging such things you either need to update gdb's
|
||||
view of where things are in memory or perhaps more trivially disable
|
||||
ASLR when booting the system.
|
||||
|
||||
Debugging user-space in system emulation
|
||||
========================================
|
||||
|
||||
While it is technically possible to debug a user-space program running
|
||||
inside a system image, it does present challenges. Kernel preemption
|
||||
and execution mode changes between kernel and user mode can make it
|
||||
hard to follow what's going on. Unless you are specifically trying to
|
||||
debug some interaction between kernel and user-space you are better
|
||||
off running your guest program with gdb either in the guest or using
|
||||
a gdbserver exposed via a port to the outside world.
|
||||
|
||||
Debugging multicore machines
|
||||
============================
|
||||
|
||||
|
||||
113
docs/system/i386/tdx.rst
Normal file
113
docs/system/i386/tdx.rst
Normal file
@@ -0,0 +1,113 @@
|
||||
Intel Trusted Domain eXtension (TDX)
|
||||
====================================
|
||||
|
||||
Intel Trusted Domain eXtensions (TDX) refers to an Intel technology that extends
|
||||
Virtual Machine Extensions (VMX) and Multi-Key Total Memory Encryption (MKTME)
|
||||
with a new kind of virtual machine guest called a Trust Domain (TD). A TD runs
|
||||
in a CPU mode that is designed to protect the confidentiality of its memory
|
||||
contents and its CPU state from any other software, including the hosting
|
||||
Virtual Machine Monitor (VMM), unless explicitly shared by the TD itself.
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
To run TD, the physical machine needs to have TDX module loaded and initialized
|
||||
while KVM hypervisor has TDX support and has TDX enabled. If those requirements
|
||||
are met, the ``KVM_CAP_VM_TYPES`` will report the support of ``KVM_X86_TDX_VM``.
|
||||
|
||||
Trust Domain Virtual Firmware (TDVF)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Trust Domain Virtual Firmware (TDVF) is required to provide TD services to boot
|
||||
TD Guest OS. TDVF needs to be copied to guest private memory and measured before
|
||||
a TD boots.
|
||||
|
||||
The VM scope ``MEMORY_ENCRYPT_OP`` ioctl provides command ``KVM_TDX_INIT_MEM_REGION``
|
||||
to copy the TDVF image to TD's private memory space.
|
||||
|
||||
Since TDX doesn't support readonly memslot, TDVF cannot be mapped as pflash
|
||||
device and it actually works as RAM. "-bios" option is chosen to load TDVF.
|
||||
|
||||
OVMF is the opensource firmware that implements the TDVF support. Thus the
|
||||
command line to specify and load TDVF is ``-bios OVMF.fd``
|
||||
|
||||
KVM private gmem
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
TD's memory (RAM) needs to be able to be transformed between private and shared.
|
||||
And its BIOS (OVMF/TDVF) needs to be mapped as private. Thus QEMU needs to
|
||||
allocate private gmem for them via KVM's IOCTL (KVM_CREATE_GUEST_MEMFD), which
|
||||
requires KVM is newer enough that reports KVM_CAP_GUEST_MEMFD.
|
||||
|
||||
Feature Control
|
||||
---------------
|
||||
|
||||
Unlike non-TDX VM, the CPU features (enumerated by CPU or MSR) of a TD is not
|
||||
under full control of VMM. VMM can only configure part of features of a TD on
|
||||
``KVM_TDX_INIT_VM`` command of VM scope ``MEMORY_ENCRYPT_OP`` ioctl.
|
||||
|
||||
The configurable features have three types:
|
||||
|
||||
- Attributes:
|
||||
- PKS (bit 30) controls whether Supervisor Protection Keys is exposed to TD,
|
||||
which determines related CPUID bit and CR4 bit;
|
||||
- PERFMON (bit 63) controls whether PMU is exposed to TD.
|
||||
|
||||
- XSAVE related features (XFAM):
|
||||
XFAM is a 64b mask, which has the same format as XCR0 or IA32_XSS MSR. It
|
||||
determines the set of extended features available for use by the guest TD.
|
||||
|
||||
- CPUID features:
|
||||
Only some bits of some CPUID leaves are directly configurable by VMM.
|
||||
|
||||
What features can be configured is reported via TDX capabilities.
|
||||
|
||||
TDX capabilities
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
The VM scope ``MEMORY_ENCRYPT_OP`` ioctl provides command ``KVM_TDX_CAPABILITIES``
|
||||
to get the TDX capabilities from KVM. It returns a data structure of
|
||||
``struct kvm_tdx_capabilites``, which tells the supported configuration of
|
||||
attributes, XFAM and CPUIDs.
|
||||
|
||||
Launching a TD (TDX VM)
|
||||
-----------------------
|
||||
|
||||
To launch a TDX guest, below are new added and required:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
|qemu_system_x86| \\
|
||||
-object tdx-guest,id=tdx0 \\
|
||||
-machine ...,kernel-irqchip=split,confidential-guest-support=tdx0 \\
|
||||
-bios OVMF.fd \\
|
||||
|
||||
Debugging
|
||||
---------
|
||||
|
||||
Bit 0 of TD attributes, is DEBUG bit, which decides if the TD runs in off-TD
|
||||
debug mode. When in off-TD debug mode, TD's VCPU state and private memory are
|
||||
accessible via given SEAMCALLs. This requires KVM to expose APIs to invoke those
|
||||
SEAMCALLs and resonponding QEMU change.
|
||||
|
||||
It's targeted as future work.
|
||||
|
||||
restrictions
|
||||
------------
|
||||
|
||||
- kernel-irqchip must be split;
|
||||
|
||||
- No readonly support for private memory;
|
||||
|
||||
- No SMM support: SMM support requires manipulating the guset register states
|
||||
which is not allowed;
|
||||
|
||||
Live Migration
|
||||
--------------
|
||||
|
||||
TODO
|
||||
|
||||
References
|
||||
----------
|
||||
|
||||
- `TDX Homepage <https://www.intel.com/content/www/us/en/developer/articles/technical/intel-trust-domain-extensions.html>`__
|
||||
@@ -29,6 +29,7 @@ Architectural features
|
||||
i386/kvm-pv
|
||||
i386/sgx
|
||||
i386/amd-memory-encryption
|
||||
i386/tdx
|
||||
|
||||
OS requirements
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -692,7 +692,7 @@ static int gdb_handle_vcont(const char *p)
|
||||
/*
|
||||
* target_count and last_target keep track of how many CPUs we are going to
|
||||
* step or resume, and a pointer to the state structure of one of them,
|
||||
* respectively
|
||||
* respectivelly
|
||||
*/
|
||||
int target_count = 0;
|
||||
CPUState *last_target = NULL;
|
||||
|
||||
@@ -169,8 +169,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp)
|
||||
epit_table[i].irq));
|
||||
}
|
||||
|
||||
object_property_set_uint(OBJECT(&s->fec), "phy-num", s->phy_num,
|
||||
&error_abort);
|
||||
object_property_set_uint(OBJECT(&s->fec), "phy-num", s->phy_num, &err);
|
||||
qdev_set_nic_properties(DEVICE(&s->fec), &nd_table[0]);
|
||||
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->fec), errp)) {
|
||||
|
||||
@@ -379,8 +379,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
|
||||
spi_table[i].irq));
|
||||
}
|
||||
|
||||
object_property_set_uint(OBJECT(&s->eth), "phy-num", s->phy_num,
|
||||
&error_abort);
|
||||
object_property_set_uint(OBJECT(&s->eth), "phy-num", s->phy_num, &err);
|
||||
qdev_set_nic_properties(DEVICE(&s->eth), &nd_table[0]);
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->eth), errp)) {
|
||||
return;
|
||||
|
||||
@@ -44,6 +44,7 @@ static void netduino2_init(MachineState *machine)
|
||||
clock_set_hz(sysclk, SYSCLK_FRQ);
|
||||
|
||||
dev = qdev_new(TYPE_STM32F205_SOC);
|
||||
qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m3"));
|
||||
qdev_connect_clock_in(dev, "sysclk", sysclk);
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
|
||||
@@ -53,14 +54,8 @@ static void netduino2_init(MachineState *machine)
|
||||
|
||||
static void netduino2_machine_init(MachineClass *mc)
|
||||
{
|
||||
static const char * const valid_cpu_types[] = {
|
||||
ARM_CPU_TYPE_NAME("cortex-m3"),
|
||||
NULL
|
||||
};
|
||||
|
||||
mc->desc = "Netduino 2 Machine (Cortex-M3)";
|
||||
mc->init = netduino2_init;
|
||||
mc->valid_cpu_types = valid_cpu_types;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ static void netduinoplus2_init(MachineState *machine)
|
||||
clock_set_hz(sysclk, SYSCLK_FRQ);
|
||||
|
||||
dev = qdev_new(TYPE_STM32F405_SOC);
|
||||
qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m4"));
|
||||
qdev_connect_clock_in(dev, "sysclk", sysclk);
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
|
||||
@@ -54,14 +55,8 @@ static void netduinoplus2_init(MachineState *machine)
|
||||
|
||||
static void netduinoplus2_machine_init(MachineClass *mc)
|
||||
{
|
||||
static const char * const valid_cpu_types[] = {
|
||||
ARM_CPU_TYPE_NAME("cortex-m4"),
|
||||
NULL
|
||||
};
|
||||
|
||||
mc->desc = "Netduino Plus 2 Machine (Cortex-M4)";
|
||||
mc->init = netduinoplus2_init;
|
||||
mc->valid_cpu_types = valid_cpu_types;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("netduinoplus2", netduinoplus2_machine_init)
|
||||
|
||||
@@ -47,6 +47,7 @@ static void olimex_stm32_h405_init(MachineState *machine)
|
||||
clock_set_hz(sysclk, SYSCLK_FRQ);
|
||||
|
||||
dev = qdev_new(TYPE_STM32F405_SOC);
|
||||
qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m4"));
|
||||
qdev_connect_clock_in(dev, "sysclk", sysclk);
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
|
||||
@@ -57,14 +58,9 @@ static void olimex_stm32_h405_init(MachineState *machine)
|
||||
|
||||
static void olimex_stm32_h405_machine_init(MachineClass *mc)
|
||||
{
|
||||
static const char * const valid_cpu_types[] = {
|
||||
ARM_CPU_TYPE_NAME("cortex-m4"),
|
||||
NULL
|
||||
};
|
||||
|
||||
mc->desc = "Olimex STM32-H405 (Cortex-M4)";
|
||||
mc->init = olimex_stm32_h405_init;
|
||||
mc->valid_cpu_types = valid_cpu_types;
|
||||
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m4");
|
||||
|
||||
/* SRAM pre-allocated as part of the SoC instantiation */
|
||||
mc->default_ram_size = 0;
|
||||
|
||||
@@ -115,7 +115,7 @@ static void stm32f100_soc_realize(DeviceState *dev_soc, Error **errp)
|
||||
/* Init ARMv7m */
|
||||
armv7m = DEVICE(&s->armv7m);
|
||||
qdev_prop_set_uint32(armv7m, "num-irq", 61);
|
||||
qdev_prop_set_string(armv7m, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m3"));
|
||||
qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type);
|
||||
qdev_prop_set_bit(armv7m, "enable-bitband", true);
|
||||
qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk);
|
||||
qdev_connect_clock_in(armv7m, "refclk", s->refclk);
|
||||
@@ -180,12 +180,17 @@ static void stm32f100_soc_realize(DeviceState *dev_soc, Error **errp)
|
||||
create_unimplemented_device("CRC", 0x40023000, 0x400);
|
||||
}
|
||||
|
||||
static Property stm32f100_soc_properties[] = {
|
||||
DEFINE_PROP_STRING("cpu-type", STM32F100State, cpu_type),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void stm32f100_soc_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = stm32f100_soc_realize;
|
||||
/* No vmstate or reset required: device has no internal state */
|
||||
device_class_set_props(dc, stm32f100_soc_properties);
|
||||
}
|
||||
|
||||
static const TypeInfo stm32f100_soc_info = {
|
||||
|
||||
@@ -127,7 +127,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
|
||||
|
||||
armv7m = DEVICE(&s->armv7m);
|
||||
qdev_prop_set_uint32(armv7m, "num-irq", 96);
|
||||
qdev_prop_set_string(armv7m, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m3"));
|
||||
qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type);
|
||||
qdev_prop_set_bit(armv7m, "enable-bitband", true);
|
||||
qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk);
|
||||
qdev_connect_clock_in(armv7m, "refclk", s->refclk);
|
||||
@@ -201,12 +201,17 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
static Property stm32f205_soc_properties[] = {
|
||||
DEFINE_PROP_STRING("cpu-type", STM32F205State, cpu_type),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void stm32f205_soc_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = stm32f205_soc_realize;
|
||||
/* No vmstate or reset required: device has no internal state */
|
||||
device_class_set_props(dc, stm32f205_soc_properties);
|
||||
}
|
||||
|
||||
static const TypeInfo stm32f205_soc_info = {
|
||||
|
||||
@@ -149,7 +149,7 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp)
|
||||
|
||||
armv7m = DEVICE(&s->armv7m);
|
||||
qdev_prop_set_uint32(armv7m, "num-irq", 96);
|
||||
qdev_prop_set_string(armv7m, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m4"));
|
||||
qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type);
|
||||
qdev_prop_set_bit(armv7m, "enable-bitband", true);
|
||||
qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk);
|
||||
qdev_connect_clock_in(armv7m, "refclk", s->refclk);
|
||||
@@ -287,11 +287,17 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp)
|
||||
create_unimplemented_device("RNG", 0x50060800, 0x400);
|
||||
}
|
||||
|
||||
static Property stm32f405_soc_properties[] = {
|
||||
DEFINE_PROP_STRING("cpu-type", STM32F405State, cpu_type),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void stm32f405_soc_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = stm32f405_soc_realize;
|
||||
device_class_set_props(dc, stm32f405_soc_properties);
|
||||
/* No vmstate or reset required: device has no internal state */
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ static void stm32vldiscovery_init(MachineState *machine)
|
||||
clock_set_hz(sysclk, SYSCLK_FRQ);
|
||||
|
||||
dev = qdev_new(TYPE_STM32F100_SOC);
|
||||
qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m3"));
|
||||
qdev_connect_clock_in(dev, "sysclk", sysclk);
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
|
||||
@@ -57,14 +58,8 @@ static void stm32vldiscovery_init(MachineState *machine)
|
||||
|
||||
static void stm32vldiscovery_machine_init(MachineClass *mc)
|
||||
{
|
||||
static const char * const valid_cpu_types[] = {
|
||||
ARM_CPU_TYPE_NAME("cortex-m3"),
|
||||
NULL
|
||||
};
|
||||
|
||||
mc->desc = "ST STM32VLDISCOVERY (Cortex-M3)";
|
||||
mc->init = stm32vldiscovery_init;
|
||||
mc->valid_cpu_types = valid_cpu_types;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("stm32vldiscovery", stm32vldiscovery_machine_init)
|
||||
|
||||
@@ -211,14 +211,14 @@ static void out_cb(void *opaque, int avail)
|
||||
AUD_set_active_out(s->vo, 0);
|
||||
}
|
||||
if (c->type & STAT_EOL) {
|
||||
via_isa_set_irq(&s->dev, 0, 1);
|
||||
pci_set_irq(&s->dev, 1);
|
||||
}
|
||||
}
|
||||
if (CLEN_IS_FLAG(c)) {
|
||||
c->stat |= STAT_FLAG;
|
||||
c->stat |= STAT_PAUSED;
|
||||
if (c->type & STAT_FLAG) {
|
||||
via_isa_set_irq(&s->dev, 0, 1);
|
||||
pci_set_irq(&s->dev, 1);
|
||||
}
|
||||
}
|
||||
if (CLEN_IS_STOP(c)) {
|
||||
@@ -305,13 +305,13 @@ static void sgd_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
|
||||
if (val & STAT_EOL) {
|
||||
s->aur.stat &= ~(STAT_EOL | STAT_PAUSED);
|
||||
if (s->aur.type & STAT_EOL) {
|
||||
via_isa_set_irq(&s->dev, 0, 0);
|
||||
pci_set_irq(&s->dev, 0);
|
||||
}
|
||||
}
|
||||
if (val & STAT_FLAG) {
|
||||
s->aur.stat &= ~(STAT_FLAG | STAT_PAUSED);
|
||||
if (s->aur.type & STAT_FLAG) {
|
||||
via_isa_set_irq(&s->dev, 0, 0);
|
||||
pci_set_irq(&s->dev, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1126,7 +1126,7 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
|
||||
status = virtio_snd_set_pcm_params(vsnd, i, &default_params);
|
||||
if (status != cpu_to_le32(VIRTIO_SND_S_OK)) {
|
||||
error_setg(errp,
|
||||
"Can't initialize stream params, device responded with %s.",
|
||||
"Can't initalize stream params, device responded with %s.",
|
||||
print_code(status));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -233,10 +233,6 @@ static void atmega_realize(DeviceState *dev, Error **errp)
|
||||
|
||||
/* CPU */
|
||||
object_initialize_child(OBJECT(dev), "cpu", &s->cpu, mc->cpu_type);
|
||||
|
||||
object_property_set_uint(OBJECT(&s->cpu), "init-sp",
|
||||
mc->io_size + mc->sram_size - 1, &error_abort);
|
||||
|
||||
qdev_realize(DEVICE(&s->cpu), NULL, &error_abort);
|
||||
cpudev = DEVICE(&s->cpu);
|
||||
|
||||
|
||||
@@ -91,27 +91,9 @@ static bool xen_block_find_free_vdev(XenBlockDevice *blockdev, Error **errp)
|
||||
|
||||
existing_frontends = qemu_xen_xs_directory(xenbus->xsh, XBT_NULL, fe_path,
|
||||
&nr_existing);
|
||||
if (!existing_frontends) {
|
||||
if (errno == ENOENT) {
|
||||
/*
|
||||
* If the frontend directory doesn't exist because there are
|
||||
* no existing vbd devices, that's fine. Just ensure that we
|
||||
* don't dereference the NULL existing_frontends pointer, by
|
||||
* checking that nr_existing is zero so the loop below is not
|
||||
* entered.
|
||||
*
|
||||
* In fact this is redundant since nr_existing is initialized
|
||||
* to zero, but setting it again here makes it abundantly clear
|
||||
* to Coverity, and to the human reader who doesn't know the
|
||||
* semantics of qemu_xen_xs_directory() off the top of their
|
||||
* head.
|
||||
*/
|
||||
nr_existing = 0;
|
||||
} else {
|
||||
/* All other errors accessing the frontend directory are fatal. */
|
||||
error_setg_errno(errp, errno, "cannot read %s", fe_path);
|
||||
return false;
|
||||
}
|
||||
if (!existing_frontends && errno != ENOENT) {
|
||||
error_setg_errno(errp, errno, "cannot read %s", fe_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(used_devs, 0, sizeof(used_devs));
|
||||
|
||||
@@ -505,7 +505,7 @@ ssize_t load_elf_ram_sym(const char *filename,
|
||||
clear_lsb, data_swab, as, load_rom, sym_cb);
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
if (ret != ELF_LOAD_FAILED) {
|
||||
debuginfo_report_elf(filename, fd, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -1189,6 +1189,11 @@ bool machine_mem_merge(MachineState *machine)
|
||||
return machine->mem_merge;
|
||||
}
|
||||
|
||||
bool machine_require_guest_memfd(MachineState *machine)
|
||||
{
|
||||
return machine->require_guest_memfd;
|
||||
}
|
||||
|
||||
static char *cpu_slot_to_string(const CPUArchId *cpu)
|
||||
{
|
||||
GString *s = g_string_new(NULL);
|
||||
|
||||
@@ -689,36 +689,23 @@ static void get_prop_array(Object *obj, Visitor *v, const char *name,
|
||||
Property *prop = opaque;
|
||||
uint32_t *alenptr = object_field_prop_ptr(obj, prop);
|
||||
void **arrayptr = (void *)obj + prop->arrayoffset;
|
||||
char *elemptr = *arrayptr;
|
||||
ArrayElementList *list = NULL, *elem;
|
||||
ArrayElementList **tail = &list;
|
||||
const size_t size = sizeof(*list);
|
||||
char *elem = *arrayptr;
|
||||
GenericList *list;
|
||||
const size_t list_elem_size = sizeof(*list) + prop->arrayfieldsize;
|
||||
int i;
|
||||
bool ok;
|
||||
|
||||
/* At least the string output visitor needs a real list */
|
||||
for (i = 0; i < *alenptr; i++) {
|
||||
elem = g_new0(ArrayElementList, 1);
|
||||
elem->value = elemptr;
|
||||
elemptr += prop->arrayfieldsize;
|
||||
|
||||
*tail = elem;
|
||||
tail = &elem->next;
|
||||
}
|
||||
|
||||
if (!visit_start_list(v, name, (GenericList **) &list, size, errp)) {
|
||||
if (!visit_start_list(v, name, &list, list_elem_size, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
elem = list;
|
||||
while (elem) {
|
||||
Property elem_prop = array_elem_prop(obj, prop, name, elem->value);
|
||||
for (i = 0; i < *alenptr; i++) {
|
||||
Property elem_prop = array_elem_prop(obj, prop, name, elem);
|
||||
prop->arrayinfo->get(obj, v, NULL, &elem_prop, errp);
|
||||
if (*errp) {
|
||||
goto out_obj;
|
||||
}
|
||||
elem = (ArrayElementList *) visit_next_list(v, (GenericList*) elem,
|
||||
size);
|
||||
elem += prop->arrayfieldsize;
|
||||
}
|
||||
|
||||
/* visit_check_list() can only fail for input visitors */
|
||||
@@ -727,12 +714,6 @@ static void get_prop_array(Object *obj, Visitor *v, const char *name,
|
||||
|
||||
out_obj:
|
||||
visit_end_list(v, (void**) &list);
|
||||
|
||||
while (list) {
|
||||
elem = list;
|
||||
list = elem->next;
|
||||
g_free(elem);
|
||||
}
|
||||
}
|
||||
|
||||
static void default_prop_array(ObjectProperty *op, const Property *prop)
|
||||
|
||||
@@ -81,7 +81,7 @@ static uint64_t cxl_cache_mem_read_reg(void *opaque, hwaddr offset,
|
||||
return 0;
|
||||
default:
|
||||
/*
|
||||
* In line with specification limitaions on access sizes, this
|
||||
* In line with specifiction limitaions on access sizes, this
|
||||
* routine is not called with other sizes.
|
||||
*/
|
||||
g_assert_not_reached();
|
||||
@@ -152,7 +152,7 @@ static void cxl_cache_mem_write_reg(void *opaque, hwaddr offset, uint64_t value,
|
||||
return;
|
||||
default:
|
||||
/*
|
||||
* In line with specification limitaions on access sizes, this
|
||||
* In line with specifiction limitaions on access sizes, this
|
||||
* routine is not called with other sizes.
|
||||
*/
|
||||
g_assert_not_reached();
|
||||
|
||||
@@ -431,7 +431,7 @@ static CXLRetCode cmd_identify_switch_device(const struct cxl_cmd *cmd,
|
||||
out = (struct cxl_fmapi_ident_switch_dev_resp_pl *)payload_out;
|
||||
*out = (struct cxl_fmapi_ident_switch_dev_resp_pl) {
|
||||
.num_physical_ports = num_phys_ports + 1, /* 1 USP */
|
||||
.num_vcss = 1, /* Not yet support multiple VCS - potentially tricky */
|
||||
.num_vcss = 1, /* Not yet support multiple VCS - potentialy tricky */
|
||||
.active_vcs_bitmask[0] = 0x1,
|
||||
.total_vppbs = num_phys_ports + 1,
|
||||
.bound_vppbs = num_phys_ports + 1,
|
||||
|
||||
@@ -33,13 +33,13 @@
|
||||
|
||||
/*
|
||||
* Ref: UG1087 (v1.7) February 8, 2019
|
||||
* https://www.xilinx.com/html_docs/registers/ug1087/ug1087-zynq-ultrascale-registers
|
||||
* https://www.xilinx.com/html_docs/registers/ug1087/ug1087-zynq-ultrascale-registers.html
|
||||
* CSUDMA Module section
|
||||
*/
|
||||
REG32(ADDR, 0x0)
|
||||
FIELD(ADDR, ADDR, 2, 30) /* wo */
|
||||
REG32(SIZE, 0x4)
|
||||
FIELD(SIZE, SIZE, 2, 27)
|
||||
FIELD(SIZE, SIZE, 2, 27) /* wo */
|
||||
FIELD(SIZE, LAST_WORD, 0, 1) /* rw, only exists in SRC */
|
||||
REG32(STATUS, 0x8)
|
||||
FIELD(STATUS, DONE_CNT, 13, 3) /* wtc */
|
||||
@@ -335,14 +335,10 @@ static uint64_t addr_pre_write(RegisterInfo *reg, uint64_t val)
|
||||
static uint64_t size_pre_write(RegisterInfo *reg, uint64_t val)
|
||||
{
|
||||
XlnxCSUDMA *s = XLNX_CSU_DMA(reg->opaque);
|
||||
uint64_t size = val & R_SIZE_SIZE_MASK;
|
||||
|
||||
if (s->regs[R_SIZE] != 0) {
|
||||
if (size || s->is_dst) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Starting DMA while already running.\n",
|
||||
__func__);
|
||||
}
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Starting DMA while already running.\n", __func__);
|
||||
}
|
||||
|
||||
if (!s->is_dst) {
|
||||
@@ -350,7 +346,7 @@ static uint64_t size_pre_write(RegisterInfo *reg, uint64_t val)
|
||||
}
|
||||
|
||||
/* Size is word aligned */
|
||||
return size;
|
||||
return val & R_SIZE_SIZE_MASK;
|
||||
}
|
||||
|
||||
static uint64_t size_post_read(RegisterInfo *reg, uint64_t val)
|
||||
|
||||
@@ -672,18 +672,19 @@ static void hppa_nmi(NMIState *n, int cpu_index, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
static const char *HP_B160L_machine_valid_cpu_types[] = {
|
||||
TYPE_HPPA_CPU,
|
||||
NULL
|
||||
};
|
||||
|
||||
static void HP_B160L_machine_init_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
static const char * const valid_cpu_types[] = {
|
||||
TYPE_HPPA_CPU,
|
||||
NULL
|
||||
};
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
NMIClass *nc = NMI_CLASS(oc);
|
||||
|
||||
mc->desc = "HP B160L workstation";
|
||||
mc->default_cpu_type = TYPE_HPPA_CPU;
|
||||
mc->valid_cpu_types = valid_cpu_types;
|
||||
mc->valid_cpu_types = HP_B160L_machine_valid_cpu_types;
|
||||
mc->init = machine_HP_B160L_init;
|
||||
mc->reset = hppa_machine_reset;
|
||||
mc->block_default_type = IF_SCSI;
|
||||
@@ -708,18 +709,19 @@ static const TypeInfo HP_B160L_machine_init_typeinfo = {
|
||||
},
|
||||
};
|
||||
|
||||
static const char *HP_C3700_machine_valid_cpu_types[] = {
|
||||
TYPE_HPPA64_CPU,
|
||||
NULL
|
||||
};
|
||||
|
||||
static void HP_C3700_machine_init_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
static const char * const valid_cpu_types[] = {
|
||||
TYPE_HPPA64_CPU,
|
||||
NULL
|
||||
};
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
NMIClass *nc = NMI_CLASS(oc);
|
||||
|
||||
mc->desc = "HP C3700 workstation";
|
||||
mc->default_cpu_type = TYPE_HPPA64_CPU;
|
||||
mc->valid_cpu_types = valid_cpu_types;
|
||||
mc->valid_cpu_types = HP_C3700_machine_valid_cpu_types;
|
||||
mc->init = machine_HP_C3700_init;
|
||||
mc->reset = hppa_machine_reset;
|
||||
mc->block_default_type = IF_SCSI;
|
||||
|
||||
@@ -10,6 +10,11 @@ config SGX
|
||||
bool
|
||||
depends on KVM
|
||||
|
||||
config TDX
|
||||
bool
|
||||
select X86_FW_OVMF
|
||||
depends on KVM
|
||||
|
||||
config PC
|
||||
bool
|
||||
imply APPLESMC
|
||||
@@ -26,6 +31,7 @@ config PC
|
||||
imply QXL
|
||||
imply SEV
|
||||
imply SGX
|
||||
imply TDX
|
||||
imply TEST_DEVICES
|
||||
imply TPM_CRB
|
||||
imply TPM_TIS_ISA
|
||||
|
||||
@@ -975,7 +975,8 @@ static void build_dbg_aml(Aml *table)
|
||||
aml_append(table, scope);
|
||||
}
|
||||
|
||||
static Aml *build_link_dev(const char *name, uint8_t uid, Aml *reg)
|
||||
static Aml *build_link_dev(const char *name, uint8_t uid, Aml *reg,
|
||||
bool level_trigger_unsupported)
|
||||
{
|
||||
Aml *dev;
|
||||
Aml *crs;
|
||||
@@ -987,7 +988,10 @@ static Aml *build_link_dev(const char *name, uint8_t uid, Aml *reg)
|
||||
aml_append(dev, aml_name_decl("_UID", aml_int(uid)));
|
||||
|
||||
crs = aml_resource_template();
|
||||
aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
|
||||
aml_append(crs, aml_interrupt(AML_CONSUMER,
|
||||
level_trigger_unsupported ?
|
||||
AML_EDGE : AML_LEVEL,
|
||||
AML_ACTIVE_HIGH,
|
||||
AML_SHARED, irqs, ARRAY_SIZE(irqs)));
|
||||
aml_append(dev, aml_name_decl("_PRS", crs));
|
||||
|
||||
@@ -1011,7 +1015,8 @@ static Aml *build_link_dev(const char *name, uint8_t uid, Aml *reg)
|
||||
return dev;
|
||||
}
|
||||
|
||||
static Aml *build_gsi_link_dev(const char *name, uint8_t uid, uint8_t gsi)
|
||||
static Aml *build_gsi_link_dev(const char *name, uint8_t uid,
|
||||
uint8_t gsi, bool level_trigger_unsupported)
|
||||
{
|
||||
Aml *dev;
|
||||
Aml *crs;
|
||||
@@ -1024,7 +1029,10 @@ static Aml *build_gsi_link_dev(const char *name, uint8_t uid, uint8_t gsi)
|
||||
|
||||
crs = aml_resource_template();
|
||||
irqs = gsi;
|
||||
aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
|
||||
aml_append(crs, aml_interrupt(AML_CONSUMER,
|
||||
level_trigger_unsupported ?
|
||||
AML_EDGE : AML_LEVEL,
|
||||
AML_ACTIVE_HIGH,
|
||||
AML_SHARED, &irqs, 1));
|
||||
aml_append(dev, aml_name_decl("_PRS", crs));
|
||||
|
||||
@@ -1043,7 +1051,7 @@ static Aml *build_gsi_link_dev(const char *name, uint8_t uid, uint8_t gsi)
|
||||
}
|
||||
|
||||
/* _CRS method - get current settings */
|
||||
static Aml *build_iqcr_method(bool is_piix4)
|
||||
static Aml *build_iqcr_method(bool is_piix4, bool level_trigger_unsupported)
|
||||
{
|
||||
Aml *if_ctx;
|
||||
uint32_t irqs;
|
||||
@@ -1051,7 +1059,9 @@ static Aml *build_iqcr_method(bool is_piix4)
|
||||
Aml *crs = aml_resource_template();
|
||||
|
||||
irqs = 0;
|
||||
aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL,
|
||||
aml_append(crs, aml_interrupt(AML_CONSUMER,
|
||||
level_trigger_unsupported ?
|
||||
AML_EDGE : AML_LEVEL,
|
||||
AML_ACTIVE_HIGH, AML_SHARED, &irqs, 1));
|
||||
aml_append(method, aml_name_decl("PRR0", crs));
|
||||
|
||||
@@ -1085,7 +1095,7 @@ static Aml *build_irq_status_method(void)
|
||||
return method;
|
||||
}
|
||||
|
||||
static void build_piix4_pci0_int(Aml *table)
|
||||
static void build_piix4_pci0_int(Aml *table, bool level_trigger_unsupported)
|
||||
{
|
||||
Aml *dev;
|
||||
Aml *crs;
|
||||
@@ -1098,12 +1108,16 @@ static void build_piix4_pci0_int(Aml *table)
|
||||
aml_append(sb_scope, pci0_scope);
|
||||
|
||||
aml_append(sb_scope, build_irq_status_method());
|
||||
aml_append(sb_scope, build_iqcr_method(true));
|
||||
aml_append(sb_scope, build_iqcr_method(true, level_trigger_unsupported));
|
||||
|
||||
aml_append(sb_scope, build_link_dev("LNKA", 0, aml_name("PRQ0")));
|
||||
aml_append(sb_scope, build_link_dev("LNKB", 1, aml_name("PRQ1")));
|
||||
aml_append(sb_scope, build_link_dev("LNKC", 2, aml_name("PRQ2")));
|
||||
aml_append(sb_scope, build_link_dev("LNKD", 3, aml_name("PRQ3")));
|
||||
aml_append(sb_scope, build_link_dev("LNKA", 0, aml_name("PRQ0"),
|
||||
level_trigger_unsupported));
|
||||
aml_append(sb_scope, build_link_dev("LNKB", 1, aml_name("PRQ1"),
|
||||
level_trigger_unsupported));
|
||||
aml_append(sb_scope, build_link_dev("LNKC", 2, aml_name("PRQ2"),
|
||||
level_trigger_unsupported));
|
||||
aml_append(sb_scope, build_link_dev("LNKD", 3, aml_name("PRQ3"),
|
||||
level_trigger_unsupported));
|
||||
|
||||
dev = aml_device("LNKS");
|
||||
{
|
||||
@@ -1112,7 +1126,9 @@ static void build_piix4_pci0_int(Aml *table)
|
||||
|
||||
crs = aml_resource_template();
|
||||
irqs = 9;
|
||||
aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL,
|
||||
aml_append(crs, aml_interrupt(AML_CONSUMER,
|
||||
level_trigger_unsupported ?
|
||||
AML_EDGE : AML_LEVEL,
|
||||
AML_ACTIVE_HIGH, AML_SHARED,
|
||||
&irqs, 1));
|
||||
aml_append(dev, aml_name_decl("_PRS", crs));
|
||||
@@ -1198,7 +1214,7 @@ static Aml *build_q35_routing_table(const char *str)
|
||||
return pkg;
|
||||
}
|
||||
|
||||
static void build_q35_pci0_int(Aml *table)
|
||||
static void build_q35_pci0_int(Aml *table, bool level_trigger_unsupported)
|
||||
{
|
||||
Aml *method;
|
||||
Aml *sb_scope = aml_scope("_SB");
|
||||
@@ -1237,25 +1253,41 @@ static void build_q35_pci0_int(Aml *table)
|
||||
aml_append(sb_scope, pci0_scope);
|
||||
|
||||
aml_append(sb_scope, build_irq_status_method());
|
||||
aml_append(sb_scope, build_iqcr_method(false));
|
||||
aml_append(sb_scope, build_iqcr_method(false, level_trigger_unsupported));
|
||||
|
||||
aml_append(sb_scope, build_link_dev("LNKA", 0, aml_name("PRQA")));
|
||||
aml_append(sb_scope, build_link_dev("LNKB", 1, aml_name("PRQB")));
|
||||
aml_append(sb_scope, build_link_dev("LNKC", 2, aml_name("PRQC")));
|
||||
aml_append(sb_scope, build_link_dev("LNKD", 3, aml_name("PRQD")));
|
||||
aml_append(sb_scope, build_link_dev("LNKE", 4, aml_name("PRQE")));
|
||||
aml_append(sb_scope, build_link_dev("LNKF", 5, aml_name("PRQF")));
|
||||
aml_append(sb_scope, build_link_dev("LNKG", 6, aml_name("PRQG")));
|
||||
aml_append(sb_scope, build_link_dev("LNKH", 7, aml_name("PRQH")));
|
||||
aml_append(sb_scope, build_link_dev("LNKA", 0, aml_name("PRQA"),
|
||||
level_trigger_unsupported));
|
||||
aml_append(sb_scope, build_link_dev("LNKB", 1, aml_name("PRQB"),
|
||||
level_trigger_unsupported));
|
||||
aml_append(sb_scope, build_link_dev("LNKC", 2, aml_name("PRQC"),
|
||||
level_trigger_unsupported));
|
||||
aml_append(sb_scope, build_link_dev("LNKD", 3, aml_name("PRQD"),
|
||||
level_trigger_unsupported));
|
||||
aml_append(sb_scope, build_link_dev("LNKE", 4, aml_name("PRQE"),
|
||||
level_trigger_unsupported));
|
||||
aml_append(sb_scope, build_link_dev("LNKF", 5, aml_name("PRQF"),
|
||||
level_trigger_unsupported));
|
||||
aml_append(sb_scope, build_link_dev("LNKG", 6, aml_name("PRQG"),
|
||||
level_trigger_unsupported));
|
||||
aml_append(sb_scope, build_link_dev("LNKH", 7, aml_name("PRQH"),
|
||||
level_trigger_unsupported));
|
||||
|
||||
aml_append(sb_scope, build_gsi_link_dev("GSIA", 0x10, 0x10));
|
||||
aml_append(sb_scope, build_gsi_link_dev("GSIB", 0x11, 0x11));
|
||||
aml_append(sb_scope, build_gsi_link_dev("GSIC", 0x12, 0x12));
|
||||
aml_append(sb_scope, build_gsi_link_dev("GSID", 0x13, 0x13));
|
||||
aml_append(sb_scope, build_gsi_link_dev("GSIE", 0x14, 0x14));
|
||||
aml_append(sb_scope, build_gsi_link_dev("GSIF", 0x15, 0x15));
|
||||
aml_append(sb_scope, build_gsi_link_dev("GSIG", 0x16, 0x16));
|
||||
aml_append(sb_scope, build_gsi_link_dev("GSIH", 0x17, 0x17));
|
||||
aml_append(sb_scope, build_gsi_link_dev("GSIA", 0x10, 0x10,
|
||||
level_trigger_unsupported));
|
||||
aml_append(sb_scope, build_gsi_link_dev("GSIB", 0x11, 0x11,
|
||||
level_trigger_unsupported));
|
||||
aml_append(sb_scope, build_gsi_link_dev("GSIC", 0x12, 0x12,
|
||||
level_trigger_unsupported));
|
||||
aml_append(sb_scope, build_gsi_link_dev("GSID", 0x13, 0x13,
|
||||
level_trigger_unsupported));
|
||||
aml_append(sb_scope, build_gsi_link_dev("GSIE", 0x14, 0x14,
|
||||
level_trigger_unsupported));
|
||||
aml_append(sb_scope, build_gsi_link_dev("GSIF", 0x15, 0x15,
|
||||
level_trigger_unsupported));
|
||||
aml_append(sb_scope, build_gsi_link_dev("GSIG", 0x16, 0x16,
|
||||
level_trigger_unsupported));
|
||||
aml_append(sb_scope, build_gsi_link_dev("GSIH", 0x17, 0x17,
|
||||
level_trigger_unsupported));
|
||||
|
||||
aml_append(table, sb_scope);
|
||||
}
|
||||
@@ -1436,6 +1468,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
||||
PCMachineState *pcms = PC_MACHINE(machine);
|
||||
PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(machine);
|
||||
X86MachineState *x86ms = X86_MACHINE(machine);
|
||||
bool level_trigger_unsupported = x86ms->eoi_intercept_unsupported;
|
||||
AcpiMcfgInfo mcfg;
|
||||
bool mcfg_valid = !!acpi_get_mcfg(&mcfg);
|
||||
uint32_t nr_mem = machine->ram_slots;
|
||||
@@ -1468,7 +1501,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
||||
if (pm->pcihp_bridge_en || pm->pcihp_root_en) {
|
||||
build_x86_acpi_pci_hotplug(dsdt, pm->pcihp_io_base);
|
||||
}
|
||||
build_piix4_pci0_int(dsdt);
|
||||
build_piix4_pci0_int(dsdt, level_trigger_unsupported);
|
||||
} else if (q35) {
|
||||
sb_scope = aml_scope("_SB");
|
||||
dev = aml_device("PCI0");
|
||||
@@ -1512,7 +1545,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
||||
if (pm->pcihp_bridge_en) {
|
||||
build_x86_acpi_pci_hotplug(dsdt, pm->pcihp_io_base);
|
||||
}
|
||||
build_q35_pci0_int(dsdt);
|
||||
build_q35_pci0_int(dsdt, level_trigger_unsupported);
|
||||
}
|
||||
|
||||
if (misc->has_hpet) {
|
||||
|
||||
@@ -103,6 +103,7 @@ void acpi_build_madt(GArray *table_data, BIOSLinker *linker,
|
||||
const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(x86ms));
|
||||
AcpiTable table = { .sig = "APIC", .rev = 3, .oem_id = oem_id,
|
||||
.oem_table_id = oem_table_id };
|
||||
bool level_trigger_unsupported = x86ms->eoi_intercept_unsupported;
|
||||
|
||||
acpi_table_begin(&table, table_data);
|
||||
/* Local APIC Address */
|
||||
@@ -122,18 +123,43 @@ void acpi_build_madt(GArray *table_data, BIOSLinker *linker,
|
||||
IO_APIC_SECONDARY_ADDRESS, IO_APIC_SECONDARY_IRQBASE);
|
||||
}
|
||||
|
||||
if (x86ms->apic_xrupt_override) {
|
||||
build_xrupt_override(table_data, 0, 2,
|
||||
0 /* Flags: Conforms to the specifications of the bus */);
|
||||
}
|
||||
|
||||
for (i = 1; i < 16; i++) {
|
||||
if (!(x86ms->pci_irq_mask & (1 << i))) {
|
||||
/* No need for a INT source override structure. */
|
||||
continue;
|
||||
if (level_trigger_unsupported) {
|
||||
/* Force edge trigger */
|
||||
if (x86ms->apic_xrupt_override) {
|
||||
build_xrupt_override(table_data, 0, 2,
|
||||
/* Flags: active high, edge triggered */
|
||||
1 | (1 << 2));
|
||||
}
|
||||
|
||||
for (i = x86ms->apic_xrupt_override ? 1 : 0; i < 16; i++) {
|
||||
build_xrupt_override(table_data, i, i,
|
||||
/* Flags: active high, edge triggered */
|
||||
1 | (1 << 2));
|
||||
}
|
||||
|
||||
if (x86ms->ioapic2) {
|
||||
for (i = 0; i < 16; i++) {
|
||||
build_xrupt_override(table_data, IO_APIC_SECONDARY_IRQBASE + i,
|
||||
IO_APIC_SECONDARY_IRQBASE + i,
|
||||
/* Flags: active high, edge triggered */
|
||||
1 | (1 << 2));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (x86ms->apic_xrupt_override) {
|
||||
build_xrupt_override(table_data, 0, 2,
|
||||
0 /* Flags: Conforms to the specifications of the bus */);
|
||||
}
|
||||
|
||||
for (i = 1; i < 16; i++) {
|
||||
if (!(x86ms->pci_irq_mask & (1 << i))) {
|
||||
/* No need for a INT source override structure. */
|
||||
continue;
|
||||
}
|
||||
build_xrupt_override(table_data, i, i,
|
||||
0xd /* Flags: Active high, Level Triggered */);
|
||||
|
||||
}
|
||||
build_xrupt_override(table_data, i, i,
|
||||
0xd /* Flags: Active high, Level Triggered */);
|
||||
}
|
||||
|
||||
if (x2apic_mode) {
|
||||
|
||||
@@ -27,6 +27,7 @@ i386_ss.add(when: 'CONFIG_PC', if_true: files(
|
||||
'port92.c'))
|
||||
i386_ss.add(when: 'CONFIG_X86_FW_OVMF', if_true: files('pc_sysfw_ovmf.c'),
|
||||
if_false: files('pc_sysfw_ovmf-stubs.c'))
|
||||
i386_ss.add(when: 'CONFIG_TDX', if_true: files('tdvf.c', 'tdvf-hob.c'))
|
||||
|
||||
subdir('kvm')
|
||||
subdir('xen')
|
||||
|
||||
26
hw/i386/pc.c
26
hw/i386/pc.c
@@ -43,6 +43,7 @@
|
||||
#include "sysemu/xen.h"
|
||||
#include "sysemu/reset.h"
|
||||
#include "kvm/kvm_i386.h"
|
||||
#include "kvm/tdx.h"
|
||||
#include "hw/xen/xen.h"
|
||||
#include "qapi/qmp/qlist.h"
|
||||
#include "qemu/error-report.h"
|
||||
@@ -1036,16 +1037,18 @@ void pc_memory_init(PCMachineState *pcms,
|
||||
/* Initialize PC system firmware */
|
||||
pc_system_firmware_init(pcms, rom_memory);
|
||||
|
||||
option_rom_mr = g_malloc(sizeof(*option_rom_mr));
|
||||
memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
|
||||
&error_fatal);
|
||||
if (pcmc->pci_enabled) {
|
||||
memory_region_set_readonly(option_rom_mr, true);
|
||||
if (!is_tdx_vm()) {
|
||||
option_rom_mr = g_malloc(sizeof(*option_rom_mr));
|
||||
memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
|
||||
&error_fatal);
|
||||
if (pcmc->pci_enabled) {
|
||||
memory_region_set_readonly(option_rom_mr, true);
|
||||
}
|
||||
memory_region_add_subregion_overlap(rom_memory,
|
||||
PC_ROM_MIN_VGA,
|
||||
option_rom_mr,
|
||||
1);
|
||||
}
|
||||
memory_region_add_subregion_overlap(rom_memory,
|
||||
PC_ROM_MIN_VGA,
|
||||
option_rom_mr,
|
||||
1);
|
||||
|
||||
fw_cfg = fw_cfg_arch_create(machine,
|
||||
x86ms->boot_cpus, x86ms->apic_id_limit);
|
||||
@@ -1755,11 +1758,6 @@ static void pc_machine_initfn(Object *obj)
|
||||
cxl_machine_init(obj, &pcms->cxl_devices_state);
|
||||
}
|
||||
|
||||
int pc_machine_kvm_type(MachineState *machine, const char *kvm_type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pc_machine_reset(MachineState *machine, ShutdownCause reason)
|
||||
{
|
||||
CPUState *cs;
|
||||
|
||||
@@ -236,6 +236,8 @@ static void pc_q35_init(MachineState *machine)
|
||||
x86ms->above_4g_mem_size, NULL);
|
||||
object_property_set_bool(phb, PCI_HOST_BYPASS_IOMMU,
|
||||
pcms->default_bus_bypass_iommu, NULL);
|
||||
object_property_set_bool(phb, PCI_HOST_PROP_SMM_RANGES,
|
||||
x86_machine_is_smm_enabled(x86ms), NULL);
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(phb), &error_fatal);
|
||||
|
||||
/* pci */
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "hw/block/flash.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "sev.h"
|
||||
#include "kvm/tdx.h"
|
||||
|
||||
#define FLASH_SECTOR_SIZE 4096
|
||||
|
||||
@@ -265,5 +266,11 @@ void x86_firmware_configure(void *ptr, int size)
|
||||
}
|
||||
|
||||
sev_encrypt_flash(ptr, size, &error_fatal);
|
||||
} else if (is_tdx_vm()) {
|
||||
ret = tdx_parse_tdvf(ptr, size);
|
||||
if (ret) {
|
||||
error_report("failed to parse TDVF for TDX VM");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
147
hw/i386/tdvf-hob.c
Normal file
147
hw/i386/tdvf-hob.c
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
* Copyright (c) 2020 Intel Corporation
|
||||
* Author: Isaku Yamahata <isaku.yamahata at gmail.com>
|
||||
* <isaku.yamahata at intel.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "e820_memory_layout.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/i386/x86.h"
|
||||
#include "hw/pci/pcie_host.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "standard-headers/uefi/uefi.h"
|
||||
#include "tdvf-hob.h"
|
||||
|
||||
typedef struct TdvfHob {
|
||||
hwaddr hob_addr;
|
||||
void *ptr;
|
||||
int size;
|
||||
|
||||
/* working area */
|
||||
void *current;
|
||||
void *end;
|
||||
} TdvfHob;
|
||||
|
||||
static uint64_t tdvf_current_guest_addr(const TdvfHob *hob)
|
||||
{
|
||||
return hob->hob_addr + (hob->current - hob->ptr);
|
||||
}
|
||||
|
||||
static void tdvf_align(TdvfHob *hob, size_t align)
|
||||
{
|
||||
hob->current = QEMU_ALIGN_PTR_UP(hob->current, align);
|
||||
}
|
||||
|
||||
static void *tdvf_get_area(TdvfHob *hob, uint64_t size)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
if (hob->current + size > hob->end) {
|
||||
error_report("TD_HOB overrun, size = 0x%" PRIx64, size);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = hob->current;
|
||||
hob->current += size;
|
||||
tdvf_align(hob, 8);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void tdvf_hob_add_memory_resources(TdxGuest *tdx, TdvfHob *hob)
|
||||
{
|
||||
EFI_HOB_RESOURCE_DESCRIPTOR *region;
|
||||
EFI_RESOURCE_ATTRIBUTE_TYPE attr;
|
||||
EFI_RESOURCE_TYPE resource_type;
|
||||
|
||||
TdxRamEntry *e;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < tdx->nr_ram_entries; i++) {
|
||||
e = &tdx->ram_entries[i];
|
||||
|
||||
if (e->type == TDX_RAM_UNACCEPTED) {
|
||||
resource_type = EFI_RESOURCE_MEMORY_UNACCEPTED;
|
||||
attr = EFI_RESOURCE_ATTRIBUTE_TDVF_UNACCEPTED;
|
||||
} else if (e->type == TDX_RAM_ADDED){
|
||||
resource_type = EFI_RESOURCE_SYSTEM_MEMORY;
|
||||
attr = EFI_RESOURCE_ATTRIBUTE_TDVF_PRIVATE;
|
||||
} else {
|
||||
error_report("unknown TDX_RAM_ENTRY type %d", e->type);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
region = tdvf_get_area(hob, sizeof(*region));
|
||||
*region = (EFI_HOB_RESOURCE_DESCRIPTOR) {
|
||||
.Header = {
|
||||
.HobType = EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,
|
||||
.HobLength = cpu_to_le16(sizeof(*region)),
|
||||
.Reserved = cpu_to_le32(0),
|
||||
},
|
||||
.Owner = EFI_HOB_OWNER_ZERO,
|
||||
.ResourceType = cpu_to_le32(resource_type),
|
||||
.ResourceAttribute = cpu_to_le32(attr),
|
||||
.PhysicalStart = cpu_to_le64(e->address),
|
||||
.ResourceLength = cpu_to_le64(e->length),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void tdvf_hob_create(TdxGuest *tdx, TdxFirmwareEntry *td_hob)
|
||||
{
|
||||
TdvfHob hob = {
|
||||
.hob_addr = td_hob->address,
|
||||
.size = td_hob->size,
|
||||
.ptr = td_hob->mem_ptr,
|
||||
|
||||
.current = td_hob->mem_ptr,
|
||||
.end = td_hob->mem_ptr + td_hob->size,
|
||||
};
|
||||
|
||||
EFI_HOB_GENERIC_HEADER *last_hob;
|
||||
EFI_HOB_HANDOFF_INFO_TABLE *hit;
|
||||
|
||||
/* Note, Efi{Free}Memory{Bottom,Top} are ignored, leave 'em zeroed. */
|
||||
hit = tdvf_get_area(&hob, sizeof(*hit));
|
||||
*hit = (EFI_HOB_HANDOFF_INFO_TABLE) {
|
||||
.Header = {
|
||||
.HobType = EFI_HOB_TYPE_HANDOFF,
|
||||
.HobLength = cpu_to_le16(sizeof(*hit)),
|
||||
.Reserved = cpu_to_le32(0),
|
||||
},
|
||||
.Version = cpu_to_le32(EFI_HOB_HANDOFF_TABLE_VERSION),
|
||||
.BootMode = cpu_to_le32(0),
|
||||
.EfiMemoryTop = cpu_to_le64(0),
|
||||
.EfiMemoryBottom = cpu_to_le64(0),
|
||||
.EfiFreeMemoryTop = cpu_to_le64(0),
|
||||
.EfiFreeMemoryBottom = cpu_to_le64(0),
|
||||
.EfiEndOfHobList = cpu_to_le64(0), /* initialized later */
|
||||
};
|
||||
|
||||
tdvf_hob_add_memory_resources(tdx, &hob);
|
||||
|
||||
last_hob = tdvf_get_area(&hob, sizeof(*last_hob));
|
||||
*last_hob = (EFI_HOB_GENERIC_HEADER) {
|
||||
.HobType = EFI_HOB_TYPE_END_OF_HOB_LIST,
|
||||
.HobLength = cpu_to_le16(sizeof(*last_hob)),
|
||||
.Reserved = cpu_to_le32(0),
|
||||
};
|
||||
hit->EfiEndOfHobList = tdvf_current_guest_addr(&hob);
|
||||
}
|
||||
24
hw/i386/tdvf-hob.h
Normal file
24
hw/i386/tdvf-hob.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef HW_I386_TD_HOB_H
|
||||
#define HW_I386_TD_HOB_H
|
||||
|
||||
#include "hw/i386/tdvf.h"
|
||||
#include "target/i386/kvm/tdx.h"
|
||||
|
||||
void tdvf_hob_create(TdxGuest *tdx, TdxFirmwareEntry *td_hob);
|
||||
|
||||
#define EFI_RESOURCE_ATTRIBUTE_TDVF_PRIVATE \
|
||||
(EFI_RESOURCE_ATTRIBUTE_PRESENT | \
|
||||
EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
|
||||
EFI_RESOURCE_ATTRIBUTE_TESTED)
|
||||
|
||||
#define EFI_RESOURCE_ATTRIBUTE_TDVF_UNACCEPTED \
|
||||
(EFI_RESOURCE_ATTRIBUTE_PRESENT | \
|
||||
EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
|
||||
EFI_RESOURCE_ATTRIBUTE_TESTED)
|
||||
|
||||
#define EFI_RESOURCE_ATTRIBUTE_TDVF_MMIO \
|
||||
(EFI_RESOURCE_ATTRIBUTE_PRESENT | \
|
||||
EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
|
||||
EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE)
|
||||
|
||||
#endif
|
||||
200
hw/i386/tdvf.c
Normal file
200
hw/i386/tdvf.c
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
* Copyright (c) 2020 Intel Corporation
|
||||
* Author: Isaku Yamahata <isaku.yamahata at gmail.com>
|
||||
* <isaku.yamahata at intel.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/i386/tdvf.h"
|
||||
#include "sysemu/kvm.h"
|
||||
|
||||
#define TDX_METADATA_OFFSET_GUID "e47a6535-984a-4798-865e-4685a7bf8ec2"
|
||||
#define TDX_METADATA_VERSION 1
|
||||
#define TDVF_SIGNATURE 0x46564454 /* TDVF as little endian */
|
||||
|
||||
typedef struct {
|
||||
uint32_t DataOffset;
|
||||
uint32_t RawDataSize;
|
||||
uint64_t MemoryAddress;
|
||||
uint64_t MemoryDataSize;
|
||||
uint32_t Type;
|
||||
uint32_t Attributes;
|
||||
} TdvfSectionEntry;
|
||||
|
||||
typedef struct {
|
||||
uint32_t Signature;
|
||||
uint32_t Length;
|
||||
uint32_t Version;
|
||||
uint32_t NumberOfSectionEntries;
|
||||
TdvfSectionEntry SectionEntries[];
|
||||
} TdvfMetadata;
|
||||
|
||||
struct tdx_metadata_offset {
|
||||
uint32_t offset;
|
||||
};
|
||||
|
||||
static TdvfMetadata *tdvf_get_metadata(void *flash_ptr, int size)
|
||||
{
|
||||
TdvfMetadata *metadata;
|
||||
uint32_t offset = 0;
|
||||
uint8_t *data;
|
||||
|
||||
if ((uint32_t) size != size) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pc_system_ovmf_table_find(TDX_METADATA_OFFSET_GUID, &data, NULL)) {
|
||||
offset = size - le32_to_cpu(((struct tdx_metadata_offset *)data)->offset);
|
||||
|
||||
if (offset + sizeof(*metadata) > size) {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
error_report("Cannot find TDX_METADATA_OFFSET_GUID");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
metadata = flash_ptr + offset;
|
||||
|
||||
/* Finally, verify the signature to determine if this is a TDVF image. */
|
||||
metadata->Signature = le32_to_cpu(metadata->Signature);
|
||||
if (metadata->Signature != TDVF_SIGNATURE) {
|
||||
error_report("Invalid TDVF signature in metadata!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Sanity check that the TDVF doesn't overlap its own metadata. */
|
||||
metadata->Length = le32_to_cpu(metadata->Length);
|
||||
if (offset + metadata->Length > size) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Only version 1 is supported/defined. */
|
||||
metadata->Version = le32_to_cpu(metadata->Version);
|
||||
if (metadata->Version != TDX_METADATA_VERSION) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
static int tdvf_parse_and_check_section_entry(const TdvfSectionEntry *src,
|
||||
TdxFirmwareEntry *entry)
|
||||
{
|
||||
entry->data_offset = le32_to_cpu(src->DataOffset);
|
||||
entry->data_len = le32_to_cpu(src->RawDataSize);
|
||||
entry->address = le64_to_cpu(src->MemoryAddress);
|
||||
entry->size = le64_to_cpu(src->MemoryDataSize);
|
||||
entry->type = le32_to_cpu(src->Type);
|
||||
entry->attributes = le32_to_cpu(src->Attributes);
|
||||
|
||||
/* sanity check */
|
||||
if (entry->size < entry->data_len) {
|
||||
error_report("Broken metadata RawDataSize 0x%x MemoryDataSize 0x%lx",
|
||||
entry->data_len, entry->size);
|
||||
return -1;
|
||||
}
|
||||
if (!QEMU_IS_ALIGNED(entry->address, TARGET_PAGE_SIZE)) {
|
||||
error_report("MemoryAddress 0x%lx not page aligned", entry->address);
|
||||
return -1;
|
||||
}
|
||||
if (!QEMU_IS_ALIGNED(entry->size, TARGET_PAGE_SIZE)) {
|
||||
error_report("MemoryDataSize 0x%lx not page aligned", entry->size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (entry->type) {
|
||||
case TDVF_SECTION_TYPE_BFV:
|
||||
case TDVF_SECTION_TYPE_CFV:
|
||||
/* The sections that must be copied from firmware image to TD memory */
|
||||
if (entry->data_len == 0) {
|
||||
error_report("%d section with RawDataSize == 0", entry->type);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case TDVF_SECTION_TYPE_TD_HOB:
|
||||
case TDVF_SECTION_TYPE_TEMP_MEM:
|
||||
/* The sections that no need to be copied from firmware image */
|
||||
if (entry->data_len != 0) {
|
||||
error_report("%d section with RawDataSize 0x%x != 0",
|
||||
entry->type, entry->data_len);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error_report("TDVF contains unsupported section type %d", entry->type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tdvf_parse_metadata(TdxFirmware *fw, void *flash_ptr, int size)
|
||||
{
|
||||
TdvfSectionEntry *sections;
|
||||
TdvfMetadata *metadata;
|
||||
ssize_t entries_size;
|
||||
uint32_t len, i;
|
||||
|
||||
metadata = tdvf_get_metadata(flash_ptr, size);
|
||||
if (!metadata) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
//load and parse metadata entries
|
||||
fw->nr_entries = le32_to_cpu(metadata->NumberOfSectionEntries);
|
||||
if (fw->nr_entries < 2) {
|
||||
error_report("Invalid number of fw entries (%u) in TDVF", fw->nr_entries);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
len = le32_to_cpu(metadata->Length);
|
||||
entries_size = fw->nr_entries * sizeof(TdvfSectionEntry);
|
||||
if (len != sizeof(*metadata) + entries_size) {
|
||||
error_report("TDVF metadata len (0x%x) mismatch, expected (0x%x)",
|
||||
len, (uint32_t)(sizeof(*metadata) + entries_size));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fw->entries = g_new(TdxFirmwareEntry, fw->nr_entries);
|
||||
sections = g_new(TdvfSectionEntry, fw->nr_entries);
|
||||
|
||||
if (!memcpy(sections, (void *)metadata + sizeof(*metadata), entries_size)) {
|
||||
error_report("Failed to read TDVF section entries");
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (i = 0; i < fw->nr_entries; i++) {
|
||||
if (tdvf_parse_and_check_section_entry(§ions[i], &fw->entries[i])) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
g_free(sections);
|
||||
|
||||
fw->mem_ptr = flash_ptr;
|
||||
return 0;
|
||||
|
||||
err:
|
||||
g_free(sections);
|
||||
fw->entries = 0;
|
||||
g_free(fw->entries);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -47,6 +47,7 @@
|
||||
#include "hw/intc/i8259.h"
|
||||
#include "hw/rtc/mc146818rtc.h"
|
||||
#include "target/i386/sev.h"
|
||||
#include "kvm/tdx.h"
|
||||
|
||||
#include "hw/acpi/cpu_hotplug.h"
|
||||
#include "hw/irq.h"
|
||||
@@ -1145,9 +1146,17 @@ void x86_bios_rom_init(MachineState *ms, const char *default_firmware,
|
||||
(bios_size % 65536) != 0) {
|
||||
goto bios_error;
|
||||
}
|
||||
|
||||
bios = g_malloc(sizeof(*bios));
|
||||
memory_region_init_ram(bios, NULL, "pc.bios", bios_size, &error_fatal);
|
||||
if (sev_enabled()) {
|
||||
if (is_tdx_vm()) {
|
||||
memory_region_init_ram_guest_memfd(bios, NULL, "pc.bios", bios_size,
|
||||
&error_fatal);
|
||||
tdx_set_tdvf_region(bios);
|
||||
} else {
|
||||
memory_region_init_ram(bios, NULL, "pc.bios", bios_size, &error_fatal);
|
||||
}
|
||||
|
||||
if (sev_enabled() || is_tdx_vm()) {
|
||||
/*
|
||||
* The concept of a "reset" simply doesn't exist for
|
||||
* confidential computing guests, we have to destroy and
|
||||
@@ -1169,17 +1178,20 @@ void x86_bios_rom_init(MachineState *ms, const char *default_firmware,
|
||||
}
|
||||
g_free(filename);
|
||||
|
||||
/* map the last 128KB of the BIOS in ISA space */
|
||||
isa_bios_size = MIN(bios_size, 128 * KiB);
|
||||
isa_bios = g_malloc(sizeof(*isa_bios));
|
||||
memory_region_init_alias(isa_bios, NULL, "isa-bios", bios,
|
||||
bios_size - isa_bios_size, isa_bios_size);
|
||||
memory_region_add_subregion_overlap(rom_memory,
|
||||
0x100000 - isa_bios_size,
|
||||
isa_bios,
|
||||
1);
|
||||
if (!isapc_ram_fw) {
|
||||
memory_region_set_readonly(isa_bios, true);
|
||||
/* For TDX, alias different GPAs to same private memory is not supported */
|
||||
if (!is_tdx_vm()) {
|
||||
/* map the last 128KB of the BIOS in ISA space */
|
||||
isa_bios_size = MIN(bios_size, 128 * KiB);
|
||||
isa_bios = g_malloc(sizeof(*isa_bios));
|
||||
memory_region_init_alias(isa_bios, NULL, "isa-bios", bios,
|
||||
bios_size - isa_bios_size, isa_bios_size);
|
||||
memory_region_add_subregion_overlap(rom_memory,
|
||||
0x100000 - isa_bios_size,
|
||||
isa_bios,
|
||||
1);
|
||||
if (!isapc_ram_fw) {
|
||||
memory_region_set_readonly(isa_bios, true);
|
||||
}
|
||||
}
|
||||
|
||||
/* map all the bios at the top of memory */
|
||||
@@ -1377,6 +1389,17 @@ static void machine_set_sgx_epc(Object *obj, Visitor *v, const char *name,
|
||||
qapi_free_SgxEPCList(list);
|
||||
}
|
||||
|
||||
static int x86_kvm_type(MachineState *ms, const char *vm_type)
|
||||
{
|
||||
X86MachineState *x86ms = X86_MACHINE(ms);
|
||||
int kvm_type;
|
||||
|
||||
kvm_type = kvm_get_vm_type(ms, vm_type);
|
||||
x86ms->vm_type = kvm_type;
|
||||
|
||||
return kvm_type;
|
||||
}
|
||||
|
||||
static void x86_machine_initfn(Object *obj)
|
||||
{
|
||||
X86MachineState *x86ms = X86_MACHINE(obj);
|
||||
@@ -1390,6 +1413,7 @@ static void x86_machine_initfn(Object *obj)
|
||||
x86ms->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8);
|
||||
x86ms->bus_lock_ratelimit = 0;
|
||||
x86ms->above_4g_mem_start = 4 * GiB;
|
||||
x86ms->eoi_intercept_unsupported = false;
|
||||
}
|
||||
|
||||
static void x86_machine_class_init(ObjectClass *oc, void *data)
|
||||
@@ -1401,6 +1425,7 @@ static void x86_machine_class_init(ObjectClass *oc, void *data)
|
||||
mc->cpu_index_to_instance_props = x86_cpu_index_to_props;
|
||||
mc->get_default_cpu_node_id = x86_get_default_cpu_node_id;
|
||||
mc->possible_cpu_arch_ids = x86_possible_cpu_arch_ids;
|
||||
mc->kvm_type = x86_kvm_type;
|
||||
x86mc->save_tsc_khz = true;
|
||||
x86mc->fwcfg_dma_enabled = true;
|
||||
nc->nmi_monitor_handler = x86_nmi;
|
||||
|
||||
@@ -623,13 +623,9 @@ static void ahci_init_d2h(AHCIDevice *ad)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* For simplicity, do not call ahci_clear_cmd_issue() for this
|
||||
* ahci_write_fis_d2h(). (The reset value for PxCI is 0.)
|
||||
*/
|
||||
if (ahci_write_fis_d2h(ad, true)) {
|
||||
ad->init_d2h_sent = true;
|
||||
/* We're emulating receiving the first Reg D2H FIS from the device;
|
||||
/* We're emulating receiving the first Reg H2D Fis from the device;
|
||||
* Update the SIG register, but otherwise proceed as normal. */
|
||||
pr->sig = ((uint32_t)ide_state->hcyl << 24) |
|
||||
(ide_state->lcyl << 16) |
|
||||
@@ -667,7 +663,6 @@ static void ahci_reset_port(AHCIState *s, int port)
|
||||
pr->scr_act = 0;
|
||||
pr->tfdata = 0x7F;
|
||||
pr->sig = 0xFFFFFFFF;
|
||||
pr->cmd_issue = 0;
|
||||
d->busy_slot = -1;
|
||||
d->init_d2h_sent = false;
|
||||
|
||||
@@ -1247,30 +1242,10 @@ static void handle_reg_h2d_fis(AHCIState *s, int port,
|
||||
case STATE_RUN:
|
||||
if (cmd_fis[15] & ATA_SRST) {
|
||||
s->dev[port].port_state = STATE_RESET;
|
||||
/*
|
||||
* When setting SRST in the first H2D FIS in the reset sequence,
|
||||
* the device does not send a D2H FIS. Host software thus has to
|
||||
* set the "Clear Busy upon R_OK" bit such that PxCI (and BUSY)
|
||||
* gets cleared. See AHCI 1.3.1, section 10.4.1 Software Reset.
|
||||
*/
|
||||
if (opts & AHCI_CMD_CLR_BUSY) {
|
||||
ahci_clear_cmd_issue(ad, slot);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STATE_RESET:
|
||||
if (!(cmd_fis[15] & ATA_SRST)) {
|
||||
/*
|
||||
* When clearing SRST in the second H2D FIS in the reset
|
||||
* sequence, the device will execute diagnostics. When this is
|
||||
* done, the device will send a D2H FIS with the good status.
|
||||
* See SATA 3.5a Gold, section 11.4 Software reset protocol.
|
||||
*
|
||||
* This D2H FIS is the first D2H FIS received from the device,
|
||||
* and is received regardless if the reset was performed by a
|
||||
* COMRESET or by setting and clearing the SRST bit. Therefore,
|
||||
* the logic for this is found in ahci_init_d2h() and not here.
|
||||
*/
|
||||
ahci_reset_port(s, port);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -81,18 +81,6 @@ static const char *IDE_DMA_CMD_str(enum ide_dma_cmd enval)
|
||||
|
||||
static void ide_dummy_transfer_stop(IDEState *s);
|
||||
|
||||
const MemoryRegionPortio ide_portio_list[] = {
|
||||
{ 0, 8, 1, .read = ide_ioport_read, .write = ide_ioport_write },
|
||||
{ 0, 1, 2, .read = ide_data_readw, .write = ide_data_writew },
|
||||
{ 0, 1, 4, .read = ide_data_readl, .write = ide_data_writel },
|
||||
PORTIO_END_OF_LIST(),
|
||||
};
|
||||
|
||||
const MemoryRegionPortio ide_portio2_list[] = {
|
||||
{ 0, 1, 1, .read = ide_status_read, .write = ide_ctrl_write },
|
||||
PORTIO_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void padstr(char *str, const char *src, int len)
|
||||
{
|
||||
int i, v;
|
||||
|
||||
@@ -28,6 +28,18 @@
|
||||
#include "hw/ide/internal.h"
|
||||
#include "trace.h"
|
||||
|
||||
static const MemoryRegionPortio ide_portio_list[] = {
|
||||
{ 0, 8, 1, .read = ide_ioport_read, .write = ide_ioport_write },
|
||||
{ 0, 1, 2, .read = ide_data_readw, .write = ide_data_writew },
|
||||
{ 0, 1, 4, .read = ide_data_readl, .write = ide_data_writel },
|
||||
PORTIO_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static const MemoryRegionPortio ide_portio2_list[] = {
|
||||
{ 0, 1, 1, .read = ide_status_read, .write = ide_ctrl_write },
|
||||
PORTIO_END_OF_LIST(),
|
||||
};
|
||||
|
||||
int ide_init_ioport(IDEBus *bus, ISADevice *dev, int iobase, int iobase2)
|
||||
{
|
||||
int ret;
|
||||
|
||||
84
hw/ide/pci.c
84
hw/ide/pci.c
@@ -104,90 +104,6 @@ const MemoryRegionOps pci_ide_data_le_ops = {
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
void pci_ide_update_mode(PCIIDEState *s)
|
||||
{
|
||||
PCIDevice *d = PCI_DEVICE(s);
|
||||
uint8_t mode = d->config[PCI_CLASS_PROG];
|
||||
|
||||
/*
|
||||
* This function only configures the BARs/ioports for now: PCI IDE
|
||||
* controllers must manage their own IRQ routing
|
||||
*/
|
||||
|
||||
switch (mode & 0xf) {
|
||||
case 0xa:
|
||||
/* Both channels legacy mode */
|
||||
|
||||
/*
|
||||
* TODO: according to the PCI IDE specification the BARs should
|
||||
* be completely disabled, however Linux for the pegasos2
|
||||
* machine stil accesses the BAR addresses after switching to legacy
|
||||
* mode. Hence we leave them active for now.
|
||||
*/
|
||||
|
||||
/* Clear interrupt pin */
|
||||
pci_config_set_interrupt_pin(d->config, 0);
|
||||
|
||||
/* Add legacy IDE ports */
|
||||
if (!s->bus[0].portio_list.owner) {
|
||||
portio_list_init(&s->bus[0].portio_list, OBJECT(d),
|
||||
ide_portio_list, &s->bus[0], "ide");
|
||||
portio_list_add(&s->bus[0].portio_list,
|
||||
pci_address_space_io(d), 0x1f0);
|
||||
}
|
||||
|
||||
if (!s->bus[0].portio2_list.owner) {
|
||||
portio_list_init(&s->bus[0].portio2_list, OBJECT(d),
|
||||
ide_portio2_list, &s->bus[0], "ide");
|
||||
portio_list_add(&s->bus[0].portio2_list,
|
||||
pci_address_space_io(d), 0x3f6);
|
||||
}
|
||||
|
||||
if (!s->bus[1].portio_list.owner) {
|
||||
portio_list_init(&s->bus[1].portio_list, OBJECT(d),
|
||||
ide_portio_list, &s->bus[1], "ide");
|
||||
portio_list_add(&s->bus[1].portio_list,
|
||||
pci_address_space_io(d), 0x170);
|
||||
}
|
||||
|
||||
if (!s->bus[1].portio2_list.owner) {
|
||||
portio_list_init(&s->bus[1].portio2_list, OBJECT(d),
|
||||
ide_portio2_list, &s->bus[1], "ide");
|
||||
portio_list_add(&s->bus[1].portio2_list,
|
||||
pci_address_space_io(d), 0x376);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xf:
|
||||
/* Both channels native mode */
|
||||
|
||||
/* Set interrupt pin */
|
||||
pci_config_set_interrupt_pin(d->config, 1);
|
||||
|
||||
/* Remove legacy IDE ports */
|
||||
if (s->bus[0].portio_list.owner) {
|
||||
portio_list_del(&s->bus[0].portio_list);
|
||||
portio_list_destroy(&s->bus[0].portio_list);
|
||||
}
|
||||
|
||||
if (s->bus[0].portio2_list.owner) {
|
||||
portio_list_del(&s->bus[0].portio2_list);
|
||||
portio_list_destroy(&s->bus[0].portio2_list);
|
||||
}
|
||||
|
||||
if (s->bus[1].portio_list.owner) {
|
||||
portio_list_del(&s->bus[1].portio_list);
|
||||
portio_list_destroy(&s->bus[1].portio_list);
|
||||
}
|
||||
|
||||
if (s->bus[1].portio2_list.owner) {
|
||||
portio_list_del(&s->bus[1].portio2_list);
|
||||
portio_list_destroy(&s->bus[1].portio2_list);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static IDEState *bmdma_active_if(BMDMAState *bmdma)
|
||||
{
|
||||
assert(bmdma->bus->retry_unit != (uint8_t)-1);
|
||||
|
||||
49
hw/ide/via.c
49
hw/ide/via.c
@@ -28,7 +28,6 @@
|
||||
#include "hw/pci/pci.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/range.h"
|
||||
#include "sysemu/dma.h"
|
||||
#include "hw/isa/vt82c686.h"
|
||||
#include "hw/ide/pci.h"
|
||||
@@ -129,14 +128,16 @@ static void via_ide_reset(DeviceState *dev)
|
||||
ide_bus_reset(&d->bus[i]);
|
||||
}
|
||||
|
||||
pci_config_set_prog_interface(pci_conf, 0x8a); /* legacy mode */
|
||||
pci_ide_update_mode(d);
|
||||
|
||||
pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_WAIT);
|
||||
pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_FAST_BACK |
|
||||
PCI_STATUS_DEVSEL_MEDIUM);
|
||||
|
||||
pci_set_byte(pci_conf + PCI_INTERRUPT_LINE, 0xe);
|
||||
pci_set_long(pci_conf + PCI_BASE_ADDRESS_0, 0x000001f0);
|
||||
pci_set_long(pci_conf + PCI_BASE_ADDRESS_1, 0x000003f4);
|
||||
pci_set_long(pci_conf + PCI_BASE_ADDRESS_2, 0x00000170);
|
||||
pci_set_long(pci_conf + PCI_BASE_ADDRESS_3, 0x00000374);
|
||||
pci_set_long(pci_conf + PCI_BASE_ADDRESS_4, 0x0000cc01); /* BMIBA: 20-23h */
|
||||
pci_set_long(pci_conf + PCI_INTERRUPT_LINE, 0x0000010e);
|
||||
|
||||
/* IDE chip enable, IDE configuration 1/2, IDE FIFO Configuration*/
|
||||
pci_set_long(pci_conf + 0x40, 0x0a090600);
|
||||
@@ -158,41 +159,6 @@ static void via_ide_reset(DeviceState *dev)
|
||||
pci_set_long(pci_conf + 0xc0, 0x00020001);
|
||||
}
|
||||
|
||||
static uint32_t via_ide_cfg_read(PCIDevice *pd, uint32_t addr, int len)
|
||||
{
|
||||
uint32_t val = pci_default_read_config(pd, addr, len);
|
||||
uint8_t mode = pd->config[PCI_CLASS_PROG];
|
||||
|
||||
if ((mode & 0xf) == 0xa) {
|
||||
if (ranges_overlap(addr, len, PCI_BASE_ADDRESS_0, 16)) {
|
||||
/* BARs 0-3 always read back zero in legacy mode */
|
||||
for (int i = addr; i < addr + len; i++) {
|
||||
if (i >= PCI_BASE_ADDRESS_0 && i < PCI_BASE_ADDRESS_0 + 16) {
|
||||
val &= ~(0xffULL << ((i - addr) << 3));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (addr == PCI_BASE_ADDRESS_4 && val == PCI_BASE_ADDRESS_SPACE_IO) {
|
||||
/* BAR4 default value if unset */
|
||||
val = 0xcc00 | PCI_BASE_ADDRESS_SPACE_IO;
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void via_ide_cfg_write(PCIDevice *pd, uint32_t addr,
|
||||
uint32_t val, int len)
|
||||
{
|
||||
PCIIDEState *d = PCI_IDE(pd);
|
||||
|
||||
pci_default_write_config(pd, addr, val, len);
|
||||
|
||||
if (range_covers_byte(addr, len, PCI_CLASS_PROG)) {
|
||||
pci_ide_update_mode(d);
|
||||
}
|
||||
}
|
||||
|
||||
static void via_ide_realize(PCIDevice *dev, Error **errp)
|
||||
{
|
||||
PCIIDEState *d = PCI_IDE(dev);
|
||||
@@ -200,6 +166,7 @@ static void via_ide_realize(PCIDevice *dev, Error **errp)
|
||||
uint8_t *pci_conf = dev->config;
|
||||
int i;
|
||||
|
||||
pci_config_set_prog_interface(pci_conf, 0x8a); /* legacy mode */
|
||||
pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0);
|
||||
dev->wmask[PCI_INTERRUPT_LINE] = 0;
|
||||
dev->wmask[PCI_CLASS_PROG] = 5;
|
||||
@@ -254,8 +221,6 @@ static void via_ide_class_init(ObjectClass *klass, void *data)
|
||||
/* Reason: only works as function of VIA southbridge */
|
||||
dc->user_creatable = false;
|
||||
|
||||
k->config_read = via_ide_cfg_read;
|
||||
k->config_write = via_ide_cfg_write;
|
||||
k->realize = via_ide_realize;
|
||||
k->exit = via_ide_exitfn;
|
||||
k->vendor_id = PCI_VENDOR_ID_VIA;
|
||||
|
||||
@@ -63,13 +63,6 @@ static void stellaris_gamepad_realize(DeviceState *dev, Error **errp)
|
||||
qemu_input_handler_register(dev, &stellaris_gamepad_handler);
|
||||
}
|
||||
|
||||
static void stellaris_gamepad_finalize(Object *obj)
|
||||
{
|
||||
StellarisGamepad *s = STELLARIS_GAMEPAD(obj);
|
||||
|
||||
g_free(s->keycodes);
|
||||
}
|
||||
|
||||
static void stellaris_gamepad_reset_enter(Object *obj, ResetType type)
|
||||
{
|
||||
StellarisGamepad *s = STELLARIS_GAMEPAD(obj);
|
||||
@@ -99,7 +92,6 @@ static const TypeInfo stellaris_gamepad_info[] = {
|
||||
.name = TYPE_STELLARIS_GAMEPAD,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(StellarisGamepad),
|
||||
.instance_finalize = stellaris_gamepad_finalize,
|
||||
.class_init = stellaris_gamepad_class_init,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -146,7 +146,7 @@ static uint32_t icv_fullprio_mask(GICv3CPUState *cs)
|
||||
* with the group priority, whose mask depends on the value of VBPR
|
||||
* for the interrupt group.)
|
||||
*/
|
||||
return (~0U << (8 - cs->vpribits)) & 0xff;
|
||||
return ~0U << (8 - cs->vpribits);
|
||||
}
|
||||
|
||||
static int ich_highest_active_virt_prio(GICv3CPUState *cs)
|
||||
@@ -803,7 +803,7 @@ static uint32_t icc_fullprio_mask(GICv3CPUState *cs)
|
||||
* with the group priority, whose mask depends on the value of BPR
|
||||
* for the interrupt group.)
|
||||
*/
|
||||
return (~0U << (8 - cs->pribits)) & 0xff;
|
||||
return ~0U << (8 - cs->pribits);
|
||||
}
|
||||
|
||||
static inline int icc_min_bpr(GICv3CPUState *cs)
|
||||
|
||||
@@ -549,7 +549,6 @@ struct ViaISAState {
|
||||
PCIDevice dev;
|
||||
qemu_irq cpu_intr;
|
||||
qemu_irq *isa_irqs_in;
|
||||
uint16_t irq_state[ISA_NUM_IRQS];
|
||||
ViaSuperIOState via_sio;
|
||||
MC146818RtcState rtc;
|
||||
PCIIDEState ide;
|
||||
@@ -593,9 +592,15 @@ static const TypeInfo via_isa_info = {
|
||||
},
|
||||
};
|
||||
|
||||
static int via_isa_get_pci_irq(const ViaISAState *s, int pin)
|
||||
static void via_isa_request_i8259_irq(void *opaque, int irq, int level)
|
||||
{
|
||||
switch (pin) {
|
||||
ViaISAState *s = opaque;
|
||||
qemu_set_irq(s->cpu_intr, level);
|
||||
}
|
||||
|
||||
static int via_isa_get_pci_irq(const ViaISAState *s, int irq_num)
|
||||
{
|
||||
switch (irq_num) {
|
||||
case 0:
|
||||
return s->dev.config[0x55] >> 4;
|
||||
case 1:
|
||||
@@ -608,60 +613,29 @@ static int via_isa_get_pci_irq(const ViaISAState *s, int pin)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void via_isa_set_irq(PCIDevice *d, int pin, int level)
|
||||
{
|
||||
ViaISAState *s = VIA_ISA(pci_get_function_0(d));
|
||||
uint8_t irq = d->config[PCI_INTERRUPT_LINE], max_irq = 15;
|
||||
int f = PCI_FUNC(d->devfn);
|
||||
uint16_t mask = BIT(f);
|
||||
|
||||
switch (f) {
|
||||
case 0: /* PIRQ/PINT inputs */
|
||||
irq = via_isa_get_pci_irq(s, pin);
|
||||
f = 8 + pin; /* Use function 8-11 for PCI interrupt inputs */
|
||||
break;
|
||||
case 2: /* USB ports 0-1 */
|
||||
case 3: /* USB ports 2-3 */
|
||||
case 5: /* AC97 audio */
|
||||
max_irq = 14;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Keep track of the state of all sources */
|
||||
if (level) {
|
||||
s->irq_state[0] |= mask;
|
||||
} else {
|
||||
s->irq_state[0] &= ~mask;
|
||||
}
|
||||
if (irq == 0 || irq == 0xff) {
|
||||
return; /* disabled */
|
||||
}
|
||||
if (unlikely(irq > max_irq || irq == 2)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "Invalid ISA IRQ routing %d for %d",
|
||||
irq, f);
|
||||
return;
|
||||
}
|
||||
/* Record source state at mapped IRQ */
|
||||
if (level) {
|
||||
s->irq_state[irq] |= mask;
|
||||
} else {
|
||||
s->irq_state[irq] &= ~mask;
|
||||
}
|
||||
/* Make sure there are no stuck bits if mapping has changed */
|
||||
s->irq_state[irq] &= s->irq_state[0];
|
||||
/* ISA IRQ level is the OR of all sources routed to it */
|
||||
qemu_set_irq(s->isa_irqs_in[irq], !!s->irq_state[irq]);
|
||||
}
|
||||
|
||||
static void via_isa_pirq(void *opaque, int pin, int level)
|
||||
{
|
||||
via_isa_set_irq(opaque, pin, level);
|
||||
}
|
||||
|
||||
static void via_isa_request_i8259_irq(void *opaque, int irq, int level)
|
||||
static void via_isa_set_pci_irq(void *opaque, int irq_num, int level)
|
||||
{
|
||||
ViaISAState *s = opaque;
|
||||
qemu_set_irq(s->cpu_intr, level);
|
||||
PCIBus *bus = pci_get_bus(&s->dev);
|
||||
int i, pic_level, pic_irq = via_isa_get_pci_irq(s, irq_num);
|
||||
|
||||
/* IRQ 0: disabled, IRQ 2,8,13: reserved */
|
||||
if (!pic_irq) {
|
||||
return;
|
||||
}
|
||||
if (unlikely(pic_irq == 2 || pic_irq == 8 || pic_irq == 13)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "Invalid ISA IRQ routing");
|
||||
}
|
||||
|
||||
/* The pic level is the logical OR of all the PCI irqs mapped to it. */
|
||||
pic_level = 0;
|
||||
for (i = 0; i < PCI_NUM_PINS; i++) {
|
||||
if (pic_irq == via_isa_get_pci_irq(s, i)) {
|
||||
pic_level |= pci_bus_get_irq_level(bus, i);
|
||||
}
|
||||
}
|
||||
/* Now we change the pic irq level according to the via irq mappings. */
|
||||
qemu_set_irq(s->isa_irqs_in[pic_irq], pic_level);
|
||||
}
|
||||
|
||||
static void via_isa_realize(PCIDevice *d, Error **errp)
|
||||
@@ -674,7 +648,6 @@ static void via_isa_realize(PCIDevice *d, Error **errp)
|
||||
int i;
|
||||
|
||||
qdev_init_gpio_out(dev, &s->cpu_intr, 1);
|
||||
qdev_init_gpio_in_named(dev, via_isa_pirq, "pirq", PCI_NUM_PINS);
|
||||
isa_irq = qemu_allocate_irqs(via_isa_request_i8259_irq, s, 1);
|
||||
isa_bus = isa_bus_new(dev, pci_address_space(d), pci_address_space_io(d),
|
||||
errp);
|
||||
@@ -688,6 +661,8 @@ static void via_isa_realize(PCIDevice *d, Error **errp)
|
||||
i8254_pit_init(isa_bus, 0x40, 0, NULL);
|
||||
i8257_dma_init(isa_bus, 0);
|
||||
|
||||
qdev_init_gpio_in_named(dev, via_isa_set_pci_irq, "pirq", PCI_NUM_PINS);
|
||||
|
||||
/* RTC */
|
||||
qdev_prop_set_int32(DEVICE(&s->rtc), "base_year", 2000);
|
||||
if (!qdev_realize(DEVICE(&s->rtc), BUS(isa_bus), errp)) {
|
||||
|
||||
@@ -726,18 +726,19 @@ static GlobalProperty hw_compat_q800[] = {
|
||||
};
|
||||
static const size_t hw_compat_q800_len = G_N_ELEMENTS(hw_compat_q800);
|
||||
|
||||
static const char *q800_machine_valid_cpu_types[] = {
|
||||
M68K_CPU_TYPE_NAME("m68040"),
|
||||
NULL
|
||||
};
|
||||
|
||||
static void q800_machine_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
static const char * const valid_cpu_types[] = {
|
||||
M68K_CPU_TYPE_NAME("m68040"),
|
||||
NULL
|
||||
};
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "Macintosh Quadra 800";
|
||||
mc->init = q800_machine_init;
|
||||
mc->default_cpu_type = M68K_CPU_TYPE_NAME("m68040");
|
||||
mc->valid_cpu_types = valid_cpu_types;
|
||||
mc->valid_cpu_types = q800_machine_valid_cpu_types;
|
||||
mc->max_cpus = 1;
|
||||
mc->block_default_type = IF_SCSI;
|
||||
mc->default_ram_id = "m68k_mac.ram";
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user