diff options
author | Vaporeon | 2018-08-29 02:46:34 +1200 |
---|---|---|
committer | Vaporeon | 2018-08-29 02:46:34 +1200 |
commit | 6deed290a0f3db7fd433395a6d1305cd5726c0db (patch) | |
tree | 6bf2c361a3e3cd478098d04100c0b7cce9d5174c | |
parent | b5d8c4ec72a9b2fe1acc0de2da58332a00459485 (diff) | |
download | aur-6deed290a0f3db7fd433395a6d1305cd5726c0db.tar.gz |
update 3.0.0
-rw-r--r-- | .SRCINFO | 20 | ||||
-rw-r--r-- | PKGBUILD | 18 | ||||
-rw-r--r-- | amd-smt-fixes-v7.patch | 1148 | ||||
-rw-r--r-- | pa-fixes.patch (renamed from audio-improvements.patch) | 350 | ||||
-rw-r--r-- | ps2-fixes-v2.patch | 315 |
5 files changed, 53 insertions, 1798 deletions
@@ -1,9 +1,9 @@ # Generated by mksrcinfo v8 -# Mon Aug 6 00:22:48 UTC 2018 +# Tue Aug 28 14:34:40 UTC 2018 pkgbase = qemu-patched pkgdesc = A generic and open source machine emulator and virtualizer - Patched for extra functionality - pkgver = 2.12.1 - pkgrel = 4 + pkgver = 3.0.0 + pkgrel = 1 url = http://wiki.qemu.org/ arch = x86_64 license = GPL2 @@ -33,24 +33,20 @@ pkgbase = qemu-patched depends = spice depends = libcacard depends = usbredir - source = http://wiki.qemu.org//download/qemu-2.12.1.tar.xz - source = http://wiki.qemu.org//download/qemu-2.12.1.tar.xz.sig + source = http://wiki.qemu.org//download/qemu-3.0.0.tar.xz + source = http://wiki.qemu.org//download/qemu-3.0.0.tar.xz.sig source = qemu-ga.service source = 65-kvm.rules source = allow_elf64.patch source = cpu-pinning.patch - source = audio-improvements.patch - source = amd-smt-fixes-v7.patch - source = ps2-fixes-v2.patch - sha256sums = 33583800e0006cd00b78226b85be5a27c8e3b156bed2e60e83ecbeb7b9b8364f + source = pa-fixes.patch + sha256sums = 8d7af64fe8bd5ea5c3bdf17131a8b858491bcce1ee3839425a6d91fb821b5713 sha256sums = SKIP sha256sums = c39bcde4a09165e64419fd2033b3532378bba84d509d39e2d51694d44c1f8d88 sha256sums = a66f0e791b16b03b91049aac61a25950d93e962e1b2ba64a38c6ad7f609b532c sha256sums = 59751f1ed26ea61b2a37ebee4be6979e584a450b611282138a0893aa9173e2e4 sha256sums = 5c6baf8d171a75c342ffcc5c4259570b3d8d4f34166d7bc1f694ecf571662f2d - sha256sums = 2368e94e0e0c7bbabe5117f2019ceb0e942726d2161d9984d231f775a71d9b19 - sha256sums = 4a06b86eaa9cde2ad5613a7cd7ac0a222b388a116f5dcf285252dddcb883108b - sha256sums = 6d83a0f70c5f57a0c0fbb657b47ecceeb79273487625f5b29639f105261c33f8 + sha256sums = 0fd49e734ee141b90d7d41d534f5635c175734a454e61c1c7e31b9fec3e19508 pkgname = qemu-patched optdepends = qemu-patched-arch-extra: extra architectures support @@ -7,8 +7,8 @@ pkgname=(qemu-patched qemu-patched-headless qemu-patched-arch-extra qemu-patched qemu-patched-block-{iscsi,rbd,gluster} qemu-patched-guest-agent) _pkgname=qemu pkgdesc="A generic and open source machine emulator and virtualizer - Patched for extra functionality" -pkgver=2.12.1 -pkgrel=4 +pkgver=3.0.0 +pkgrel=1 arch=(x86_64) license=(GPL2 LGPL2.1) url="http://wiki.qemu.org/" @@ -21,18 +21,14 @@ source=("$url/download/${_pkgname}-${pkgver}.tar.xz"{,.sig} 65-kvm.rules allow_elf64.patch cpu-pinning.patch - audio-improvements.patch - amd-smt-fixes-v7.patch - ps2-fixes-v2.patch) -sha256sums=('33583800e0006cd00b78226b85be5a27c8e3b156bed2e60e83ecbeb7b9b8364f' + pa-fixes.patch) +sha256sums=('8d7af64fe8bd5ea5c3bdf17131a8b858491bcce1ee3839425a6d91fb821b5713' 'SKIP' 'c39bcde4a09165e64419fd2033b3532378bba84d509d39e2d51694d44c1f8d88' 'a66f0e791b16b03b91049aac61a25950d93e962e1b2ba64a38c6ad7f609b532c' '59751f1ed26ea61b2a37ebee4be6979e584a450b611282138a0893aa9173e2e4' '5c6baf8d171a75c342ffcc5c4259570b3d8d4f34166d7bc1f694ecf571662f2d' - '2368e94e0e0c7bbabe5117f2019ceb0e942726d2161d9984d231f775a71d9b19' - '4a06b86eaa9cde2ad5613a7cd7ac0a222b388a116f5dcf285252dddcb883108b' - '6d83a0f70c5f57a0c0fbb657b47ecceeb79273487625f5b29639f105261c33f8') + '0fd49e734ee141b90d7d41d534f5635c175734a454e61c1c7e31b9fec3e19508') validpgpkeys=('CEACC9E15534EBABB82D3FA03353C9CEF108B584') case $CARCH in @@ -49,9 +45,7 @@ prepare() { patch -p1 < ../allow_elf64.patch patch -p1 < ../cpu-pinning.patch - patch -p0 < ../audio-improvements.patch - patch -p1 < ../amd-smt-fixes-v7.patch - patch -p1 < ../ps2-fixes-v2.patch + patch -p1 < ../pa-fixes.patch } build() { diff --git a/amd-smt-fixes-v7.patch b/amd-smt-fixes-v7.patch deleted file mode 100644 index 66fd9b2693be..000000000000 --- a/amd-smt-fixes-v7.patch +++ /dev/null @@ -1,1148 +0,0 @@ -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index a20fe26..b6c1592 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -56,33 +56,240 @@ - - #include "disas/capstone.h" - -+/* Helpers for building CPUID[2] descriptors: */ -+ -+struct CPUID2CacheDescriptorInfo { -+ enum CacheType type; -+ int level; -+ int size; -+ int line_size; -+ int associativity; -+}; - --/* Cache topology CPUID constants: */ -+#define KiB 1024 -+#define MiB (1024 * 1024) - --/* CPUID Leaf 2 Descriptors */ -+/* -+ * Known CPUID 2 cache descriptors. -+ * From Intel SDM Volume 2A, CPUID instruction -+ */ -+struct CPUID2CacheDescriptorInfo cpuid2_cache_descriptors[] = { -+ [0x06] = { .level = 1, .type = ICACHE, .size = 8 * KiB, -+ .associativity = 4, .line_size = 32, }, -+ [0x08] = { .level = 1, .type = ICACHE, .size = 16 * KiB, -+ .associativity = 4, .line_size = 32, }, -+ [0x09] = { .level = 1, .type = ICACHE, .size = 32 * KiB, -+ .associativity = 4, .line_size = 64, }, -+ [0x0A] = { .level = 1, .type = DCACHE, .size = 8 * KiB, -+ .associativity = 2, .line_size = 32, }, -+ [0x0C] = { .level = 1, .type = DCACHE, .size = 16 * KiB, -+ .associativity = 4, .line_size = 32, }, -+ [0x0D] = { .level = 1, .type = DCACHE, .size = 16 * KiB, -+ .associativity = 4, .line_size = 64, }, -+ [0x0E] = { .level = 1, .type = DCACHE, .size = 24 * KiB, -+ .associativity = 6, .line_size = 64, }, -+ [0x1D] = { .level = 2, .type = UNIFIED_CACHE, .size = 128 * KiB, -+ .associativity = 2, .line_size = 64, }, -+ [0x21] = { .level = 2, .type = UNIFIED_CACHE, .size = 256 * KiB, -+ .associativity = 8, .line_size = 64, }, -+ /* lines per sector is not supported cpuid2_cache_descriptor(), -+ * so descriptors 0x22, 0x23 are not included -+ */ -+ [0x24] = { .level = 2, .type = UNIFIED_CACHE, .size = 1 * MiB, -+ .associativity = 16, .line_size = 64, }, -+ /* lines per sector is not supported cpuid2_cache_descriptor(), -+ * so descriptors 0x25, 0x20 are not included -+ */ -+ [0x2C] = { .level = 1, .type = DCACHE, .size = 32 * KiB, -+ .associativity = 8, .line_size = 64, }, -+ [0x30] = { .level = 1, .type = ICACHE, .size = 32 * KiB, -+ .associativity = 8, .line_size = 64, }, -+ [0x41] = { .level = 2, .type = UNIFIED_CACHE, .size = 128 * KiB, -+ .associativity = 4, .line_size = 32, }, -+ [0x42] = { .level = 2, .type = UNIFIED_CACHE, .size = 256 * KiB, -+ .associativity = 4, .line_size = 32, }, -+ [0x43] = { .level = 2, .type = UNIFIED_CACHE, .size = 512 * KiB, -+ .associativity = 4, .line_size = 32, }, -+ [0x44] = { .level = 2, .type = UNIFIED_CACHE, .size = 1 * MiB, -+ .associativity = 4, .line_size = 32, }, -+ [0x45] = { .level = 2, .type = UNIFIED_CACHE, .size = 2 * MiB, -+ .associativity = 4, .line_size = 32, }, -+ [0x46] = { .level = 3, .type = UNIFIED_CACHE, .size = 4 * MiB, -+ .associativity = 4, .line_size = 64, }, -+ [0x47] = { .level = 3, .type = UNIFIED_CACHE, .size = 8 * MiB, -+ .associativity = 8, .line_size = 64, }, -+ [0x48] = { .level = 2, .type = UNIFIED_CACHE, .size = 3 * MiB, -+ .associativity = 12, .line_size = 64, }, -+ /* Descriptor 0x49 depends on CPU family/model, so it is not included */ -+ [0x4A] = { .level = 3, .type = UNIFIED_CACHE, .size = 6 * MiB, -+ .associativity = 12, .line_size = 64, }, -+ [0x4B] = { .level = 3, .type = UNIFIED_CACHE, .size = 8 * MiB, -+ .associativity = 16, .line_size = 64, }, -+ [0x4C] = { .level = 3, .type = UNIFIED_CACHE, .size = 12 * MiB, -+ .associativity = 12, .line_size = 64, }, -+ [0x4D] = { .level = 3, .type = UNIFIED_CACHE, .size = 16 * MiB, -+ .associativity = 16, .line_size = 64, }, -+ [0x4E] = { .level = 2, .type = UNIFIED_CACHE, .size = 6 * MiB, -+ .associativity = 24, .line_size = 64, }, -+ [0x60] = { .level = 1, .type = DCACHE, .size = 16 * KiB, -+ .associativity = 8, .line_size = 64, }, -+ [0x66] = { .level = 1, .type = DCACHE, .size = 8 * KiB, -+ .associativity = 4, .line_size = 64, }, -+ [0x67] = { .level = 1, .type = DCACHE, .size = 16 * KiB, -+ .associativity = 4, .line_size = 64, }, -+ [0x68] = { .level = 1, .type = DCACHE, .size = 32 * KiB, -+ .associativity = 4, .line_size = 64, }, -+ [0x78] = { .level = 2, .type = UNIFIED_CACHE, .size = 1 * MiB, -+ .associativity = 4, .line_size = 64, }, -+ /* lines per sector is not supported cpuid2_cache_descriptor(), -+ * so descriptors 0x79, 0x7A, 0x7B, 0x7C are not included. -+ */ -+ [0x7D] = { .level = 2, .type = UNIFIED_CACHE, .size = 2 * MiB, -+ .associativity = 8, .line_size = 64, }, -+ [0x7F] = { .level = 2, .type = UNIFIED_CACHE, .size = 512 * KiB, -+ .associativity = 2, .line_size = 64, }, -+ [0x80] = { .level = 2, .type = UNIFIED_CACHE, .size = 512 * KiB, -+ .associativity = 8, .line_size = 64, }, -+ [0x82] = { .level = 2, .type = UNIFIED_CACHE, .size = 256 * KiB, -+ .associativity = 8, .line_size = 32, }, -+ [0x83] = { .level = 2, .type = UNIFIED_CACHE, .size = 512 * KiB, -+ .associativity = 8, .line_size = 32, }, -+ [0x84] = { .level = 2, .type = UNIFIED_CACHE, .size = 1 * MiB, -+ .associativity = 8, .line_size = 32, }, -+ [0x85] = { .level = 2, .type = UNIFIED_CACHE, .size = 2 * MiB, -+ .associativity = 8, .line_size = 32, }, -+ [0x86] = { .level = 2, .type = UNIFIED_CACHE, .size = 512 * KiB, -+ .associativity = 4, .line_size = 64, }, -+ [0x87] = { .level = 2, .type = UNIFIED_CACHE, .size = 1 * MiB, -+ .associativity = 8, .line_size = 64, }, -+ [0xD0] = { .level = 3, .type = UNIFIED_CACHE, .size = 512 * KiB, -+ .associativity = 4, .line_size = 64, }, -+ [0xD1] = { .level = 3, .type = UNIFIED_CACHE, .size = 1 * MiB, -+ .associativity = 4, .line_size = 64, }, -+ [0xD2] = { .level = 3, .type = UNIFIED_CACHE, .size = 2 * MiB, -+ .associativity = 4, .line_size = 64, }, -+ [0xD6] = { .level = 3, .type = UNIFIED_CACHE, .size = 1 * MiB, -+ .associativity = 8, .line_size = 64, }, -+ [0xD7] = { .level = 3, .type = UNIFIED_CACHE, .size = 2 * MiB, -+ .associativity = 8, .line_size = 64, }, -+ [0xD8] = { .level = 3, .type = UNIFIED_CACHE, .size = 4 * MiB, -+ .associativity = 8, .line_size = 64, }, -+ [0xDC] = { .level = 3, .type = UNIFIED_CACHE, .size = 1.5 * MiB, -+ .associativity = 12, .line_size = 64, }, -+ [0xDD] = { .level = 3, .type = UNIFIED_CACHE, .size = 3 * MiB, -+ .associativity = 12, .line_size = 64, }, -+ [0xDE] = { .level = 3, .type = UNIFIED_CACHE, .size = 6 * MiB, -+ .associativity = 12, .line_size = 64, }, -+ [0xE2] = { .level = 3, .type = UNIFIED_CACHE, .size = 2 * MiB, -+ .associativity = 16, .line_size = 64, }, -+ [0xE3] = { .level = 3, .type = UNIFIED_CACHE, .size = 4 * MiB, -+ .associativity = 16, .line_size = 64, }, -+ [0xE4] = { .level = 3, .type = UNIFIED_CACHE, .size = 8 * MiB, -+ .associativity = 16, .line_size = 64, }, -+ [0xEA] = { .level = 3, .type = UNIFIED_CACHE, .size = 12 * MiB, -+ .associativity = 24, .line_size = 64, }, -+ [0xEB] = { .level = 3, .type = UNIFIED_CACHE, .size = 18 * MiB, -+ .associativity = 24, .line_size = 64, }, -+ [0xEC] = { .level = 3, .type = UNIFIED_CACHE, .size = 24 * MiB, -+ .associativity = 24, .line_size = 64, }, -+}; -+ -+/* -+ * "CPUID leaf 2 does not report cache descriptor information, -+ * use CPUID leaf 4 to query cache parameters" -+ */ -+#define CACHE_DESCRIPTOR_UNAVAILABLE 0xFF - --#define CPUID_2_L1D_32KB_8WAY_64B 0x2c --#define CPUID_2_L1I_32KB_8WAY_64B 0x30 --#define CPUID_2_L2_2MB_8WAY_64B 0x7d --#define CPUID_2_L3_16MB_16WAY_64B 0x4d -+/* -+ * Return a CPUID 2 cache descriptor for a given cache. -+ * If no known descriptor is found, return CACHE_DESCRIPTOR_UNAVAILABLE -+ */ -+static uint8_t cpuid2_cache_descriptor(CPUCacheInfo *cache) -+{ -+ int i; -+ -+ assert(cache->size > 0); -+ assert(cache->level > 0); -+ assert(cache->line_size > 0); -+ assert(cache->associativity > 0); -+ for (i = 0; i < ARRAY_SIZE(cpuid2_cache_descriptors); i++) { -+ struct CPUID2CacheDescriptorInfo *d = &cpuid2_cache_descriptors[i]; -+ if (d->level == cache->level && d->type == cache->type && -+ d->size == cache->size && d->line_size == cache->line_size && -+ d->associativity == cache->associativity) { -+ return i; -+ } -+ } - -+ return CACHE_DESCRIPTOR_UNAVAILABLE; -+} - - /* CPUID Leaf 4 constants: */ - - /* EAX: */ --#define CPUID_4_TYPE_DCACHE 1 --#define CPUID_4_TYPE_ICACHE 2 --#define CPUID_4_TYPE_UNIFIED 3 -+#define CACHE_TYPE_D 1 -+#define CACHE_TYPE_I 2 -+#define CACHE_TYPE_UNIFIED 3 - --#define CPUID_4_LEVEL(l) ((l) << 5) -+#define CACHE_LEVEL(l) (l << 5) - --#define CPUID_4_SELF_INIT_LEVEL (1 << 8) --#define CPUID_4_FULLY_ASSOC (1 << 9) -+#define CACHE_SELF_INIT_LEVEL (1 << 8) - - /* EDX: */ --#define CPUID_4_NO_INVD_SHARING (1 << 0) --#define CPUID_4_INCLUSIVE (1 << 1) --#define CPUID_4_COMPLEX_IDX (1 << 2) -+#define CACHE_NO_INVD_SHARING (1 << 0) -+#define CACHE_INCLUSIVE (1 << 1) -+#define CACHE_COMPLEX_IDX (1 << 2) -+ -+/* Encode CacheType for CPUID[4].EAX */ -+#define CACHE_TYPE(t) (((t) == DCACHE) ? CACHE_TYPE_D : \ -+ ((t) == ICACHE) ? CACHE_TYPE_I : \ -+ ((t) == UNIFIED_CACHE) ? CACHE_TYPE_UNIFIED : \ -+ 0 /* Invalid value */) -+ -+ -+/* Encode cache info for CPUID[4] */ -+static void encode_cache_cpuid4(CPUCacheInfo *cache, -+ int num_apic_ids, int num_cores, -+ uint32_t *eax, uint32_t *ebx, -+ uint32_t *ecx, uint32_t *edx) -+{ -+ assert(cache->size == cache->line_size * cache->associativity * -+ cache->partitions * cache->sets); -+ -+ assert(num_apic_ids > 0); -+ *eax = CACHE_TYPE(cache->type) | -+ CACHE_LEVEL(cache->level) | -+ (cache->self_init ? CACHE_SELF_INIT_LEVEL : 0) | -+ ((num_cores - 1) << 26) | -+ ((num_apic_ids - 1) << 14); -+ -+ assert(cache->line_size > 0); -+ assert(cache->partitions > 0); -+ assert(cache->associativity > 0); -+ /* We don't implement fully-associative caches */ -+ assert(cache->associativity < cache->sets); -+ *ebx = (cache->line_size - 1) | -+ ((cache->partitions - 1) << 12) | -+ ((cache->associativity - 1) << 22); -+ -+ assert(cache->sets > 0); -+ *ecx = cache->sets - 1; -+ -+ *edx = (cache->no_invd_sharing ? CACHE_NO_INVD_SHARING : 0) | -+ (cache->inclusive ? CACHE_INCLUSIVE : 0) | -+ (cache->complex_indexing ? CACHE_COMPLEX_IDX : 0); -+} -+ -+/* Encode cache info for CPUID[0x80000005].ECX or CPUID[0x80000005].EDX */ -+static uint32_t encode_cache_cpuid80000005(CPUCacheInfo *cache) -+{ -+ assert(cache->size % 1024 == 0); -+ assert(cache->lines_per_tag > 0); -+ assert(cache->associativity > 0); -+ assert(cache->line_size > 0); -+ return ((cache->size / 1024) << 24) | (cache->associativity << 16) | -+ (cache->lines_per_tag << 8) | (cache->line_size); -+} - - #define ASSOC_FULL 0xFF - -@@ -100,57 +307,140 @@ - a == ASSOC_FULL ? 0xF : \ - 0 /* invalid value */) - -+/* -+ * Encode cache info for CPUID[0x80000006].ECX and CPUID[0x80000006].EDX -+ * @l3 can be NULL. -+ */ -+static void encode_cache_cpuid80000006(CPUCacheInfo *l2, -+ CPUCacheInfo *l3, -+ uint32_t *ecx, uint32_t *edx) -+{ -+ assert(l2->size % 1024 == 0); -+ assert(l2->associativity > 0); -+ assert(l2->lines_per_tag > 0); -+ assert(l2->line_size > 0); -+ *ecx = ((l2->size / 1024) << 16) | -+ (AMD_ENC_ASSOC(l2->associativity) << 12) | -+ (l2->lines_per_tag << 8) | (l2->line_size); -+ -+ if (l3) { -+ assert(l3->size % (512 * 1024) == 0); -+ assert(l3->associativity > 0); -+ assert(l3->lines_per_tag > 0); -+ assert(l3->line_size > 0); -+ *edx = ((l3->size / (512 * 1024)) << 18) | -+ (AMD_ENC_ASSOC(l3->associativity) << 12) | -+ (l3->lines_per_tag << 8) | (l3->line_size); -+ } else { -+ *edx = 0; -+ } -+} - - /* Definitions of the hardcoded cache entries we expose: */ - - /* L1 data cache: */ --#define L1D_LINE_SIZE 64 --#define L1D_ASSOCIATIVITY 8 --#define L1D_SETS 64 --#define L1D_PARTITIONS 1 --/* Size = LINE_SIZE*ASSOCIATIVITY*SETS*PARTITIONS = 32KiB */ --#define L1D_DESCRIPTOR CPUID_2_L1D_32KB_8WAY_64B -+static CPUCacheInfo l1d_cache = { -+ .type = DCACHE, -+ .level = 1, -+ .size = 32 * KiB, -+ .self_init = 1, -+ .line_size = 64, -+ .associativity = 8, -+ .sets = 64, -+ .partitions = 1, -+ .no_invd_sharing = true, -+}; -+ - /*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */ --#define L1D_LINES_PER_TAG 1 --#define L1D_SIZE_KB_AMD 64 --#define L1D_ASSOCIATIVITY_AMD 2 -+static CPUCacheInfo l1d_cache_amd = { -+ .type = DCACHE, -+ .level = 1, -+ .size = 64 * KiB, -+ .self_init = 1, -+ .line_size = 64, -+ .associativity = 2, -+ .sets = 512, -+ .partitions = 1, -+ .lines_per_tag = 1, -+ .no_invd_sharing = true, -+}; - - /* L1 instruction cache: */ --#define L1I_LINE_SIZE 64 --#define L1I_ASSOCIATIVITY 8 --#define L1I_SETS 64 --#define L1I_PARTITIONS 1 --/* Size = LINE_SIZE*ASSOCIATIVITY*SETS*PARTITIONS = 32KiB */ --#define L1I_DESCRIPTOR CPUID_2_L1I_32KB_8WAY_64B -+static CPUCacheInfo l1i_cache = { -+ .type = ICACHE, -+ .level = 1, -+ .size = 32 * KiB, -+ .self_init = 1, -+ .line_size = 64, -+ .associativity = 8, -+ .sets = 64, -+ .partitions = 1, -+ .no_invd_sharing = true, -+}; -+ - /*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */ --#define L1I_LINES_PER_TAG 1 --#define L1I_SIZE_KB_AMD 64 --#define L1I_ASSOCIATIVITY_AMD 2 -+static CPUCacheInfo l1i_cache_amd = { -+ .type = ICACHE, -+ .level = 1, -+ .size = 64 * KiB, -+ .self_init = 1, -+ .line_size = 64, -+ .associativity = 2, -+ .sets = 512, -+ .partitions = 1, -+ .lines_per_tag = 1, -+ .no_invd_sharing = true, -+}; - - /* Level 2 unified cache: */ --#define L2_LINE_SIZE 64 --#define L2_ASSOCIATIVITY 16 --#define L2_SETS 4096 --#define L2_PARTITIONS 1 --/* Size = LINE_SIZE*ASSOCIATIVITY*SETS*PARTITIONS = 4MiB */ -+static CPUCacheInfo l2_cache = { -+ .type = UNIFIED_CACHE, -+ .level = 2, -+ .size = 4 * MiB, -+ .self_init = 1, -+ .line_size = 64, -+ .associativity = 16, -+ .sets = 4096, -+ .partitions = 1, -+ .no_invd_sharing = true, -+}; -+ - /*FIXME: CPUID leaf 2 descriptor is inconsistent with CPUID leaf 4 */ --#define L2_DESCRIPTOR CPUID_2_L2_2MB_8WAY_64B -+static CPUCacheInfo l2_cache_cpuid2 = { -+ .type = UNIFIED_CACHE, -+ .level = 2, -+ .size = 2 * MiB, -+ .line_size = 64, -+ .associativity = 8, -+}; -+ -+ - /*FIXME: CPUID leaf 0x80000006 is inconsistent with leaves 2 & 4 */ --#define L2_LINES_PER_TAG 1 --#define L2_SIZE_KB_AMD 512 -+static CPUCacheInfo l2_cache_amd = { -+ .type = UNIFIED_CACHE, -+ .level = 2, -+ .size = 512 * KiB, -+ .line_size = 64, -+ .lines_per_tag = 1, -+ .associativity = 8, -+ .sets = 1024, -+ .partitions = 1, -+}; - - /* Level 3 unified cache: */ --#define L3_SIZE_KB 0 /* disabled */ --#define L3_ASSOCIATIVITY 0 /* disabled */ --#define L3_LINES_PER_TAG 0 /* disabled */ --#define L3_LINE_SIZE 0 /* disabled */ --#define L3_N_LINE_SIZE 64 --#define L3_N_ASSOCIATIVITY 16 --#define L3_N_SETS 16384 --#define L3_N_PARTITIONS 1 --#define L3_N_DESCRIPTOR CPUID_2_L3_16MB_16WAY_64B --#define L3_N_LINES_PER_TAG 1 --#define L3_N_SIZE_KB_AMD 16384 -+static CPUCacheInfo l3_cache = { -+ .type = UNIFIED_CACHE, -+ .level = 3, -+ .size = 16 * MiB, -+ .line_size = 64, -+ .associativity = 16, -+ .sets = 16384, -+ .partitions = 1, -+ .lines_per_tag = 1, -+ .self_init = true, -+ .inclusive = true, -+ .complex_indexing = true, -+}; - - /* TLB definitions: */ - -@@ -3301,85 +3591,53 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, - if (!cpu->enable_l3_cache) { - *ecx = 0; - } else { -- *ecx = L3_N_DESCRIPTOR; -+ *ecx = cpuid2_cache_descriptor(&l3_cache); - } -- *edx = (L1D_DESCRIPTOR << 16) | \ -- (L1I_DESCRIPTOR << 8) | \ -- (L2_DESCRIPTOR); -+ *edx = (cpuid2_cache_descriptor(&l1d_cache) << 16) | -+ (cpuid2_cache_descriptor(&l1i_cache) << 8) | -+ (cpuid2_cache_descriptor(&l2_cache_cpuid2)); - break; - case 4: - /* cache info: needed for Core compatibility */ - if (cpu->cache_info_passthrough) { - host_cpuid(index, count, eax, ebx, ecx, edx); -+ /* QEMU gives out its own APIC IDs, never pass down bits 31..26. */ - *eax &= ~0xFC000000; -+ if ((*eax & 31) && cs->nr_cores > 1) { -+ *eax |= (cs->nr_cores - 1) << 26; -+ } - } else { - *eax = 0; - switch (count) { - case 0: /* L1 dcache info */ -- *eax |= CPUID_4_TYPE_DCACHE | \ -- CPUID_4_LEVEL(1) | \ -- CPUID_4_SELF_INIT_LEVEL; -- *ebx = (L1D_LINE_SIZE - 1) | \ -- ((L1D_PARTITIONS - 1) << 12) | \ -- ((L1D_ASSOCIATIVITY - 1) << 22); -- *ecx = L1D_SETS - 1; -- *edx = CPUID_4_NO_INVD_SHARING; -+ encode_cache_cpuid4(&l1d_cache, -+ 1, cs->nr_cores, -+ eax, ebx, ecx, edx); - break; - case 1: /* L1 icache info */ -- *eax |= CPUID_4_TYPE_ICACHE | \ -- CPUID_4_LEVEL(1) | \ -- CPUID_4_SELF_INIT_LEVEL; -- *ebx = (L1I_LINE_SIZE - 1) | \ -- ((L1I_PARTITIONS - 1) << 12) | \ -- ((L1I_ASSOCIATIVITY - 1) << 22); -- *ecx = L1I_SETS - 1; -- *edx = CPUID_4_NO_INVD_SHARING; -+ encode_cache_cpuid4(&l1i_cache, -+ 1, cs->nr_cores, -+ eax, ebx, ecx, edx); - break; - case 2: /* L2 cache info */ -- *eax |= CPUID_4_TYPE_UNIFIED | \ -- CPUID_4_LEVEL(2) | \ -- CPUID_4_SELF_INIT_LEVEL; -- if (cs->nr_threads > 1) { -- *eax |= (cs->nr_threads - 1) << 14; -- } -- *ebx = (L2_LINE_SIZE - 1) | \ -- ((L2_PARTITIONS - 1) << 12) | \ -- ((L2_ASSOCIATIVITY - 1) << 22); -- *ecx = L2_SETS - 1; -- *edx = CPUID_4_NO_INVD_SHARING; -+ encode_cache_cpuid4(&l2_cache, -+ cs->nr_threads, cs->nr_cores, -+ eax, ebx, ecx, edx); - break; - case 3: /* L3 cache info */ -- if (!cpu->enable_l3_cache) { -- *eax = 0; -- *ebx = 0; -- *ecx = 0; -- *edx = 0; -+ pkg_offset = apicid_pkg_offset(cs->nr_cores, cs->nr_threads); -+ if (cpu->enable_l3_cache) { -+ encode_cache_cpuid4(&l3_cache, -+ (1 << pkg_offset), cs->nr_cores, -+ eax, ebx, ecx, edx); - break; - } -- *eax |= CPUID_4_TYPE_UNIFIED | \ -- CPUID_4_LEVEL(3) | \ -- CPUID_4_SELF_INIT_LEVEL; -- pkg_offset = apicid_pkg_offset(cs->nr_cores, cs->nr_threads); -- *eax |= ((1 << pkg_offset) - 1) << 14; -- *ebx = (L3_N_LINE_SIZE - 1) | \ -- ((L3_N_PARTITIONS - 1) << 12) | \ -- ((L3_N_ASSOCIATIVITY - 1) << 22); -- *ecx = L3_N_SETS - 1; -- *edx = CPUID_4_INCLUSIVE | CPUID_4_COMPLEX_IDX; -- break; -+ /* fall through */ - default: /* end of info */ -- *eax = 0; -- *ebx = 0; -- *ecx = 0; -- *edx = 0; -+ *eax = *ebx = *ecx = *edx = 0; - break; - } - } -- -- /* QEMU gives out its own APIC IDs, never pass down bits 31..26. */ -- if ((*eax & 31) && cs->nr_cores > 1) { -- *eax |= (cs->nr_cores - 1) << 26; -- } - break; - case 5: - /* mwait info: needed for Core compatibility */ -@@ -3583,10 +3841,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, - (L1_ITLB_2M_ASSOC << 8) | (L1_ITLB_2M_ENTRIES); - *ebx = (L1_DTLB_4K_ASSOC << 24) | (L1_DTLB_4K_ENTRIES << 16) | \ - (L1_ITLB_4K_ASSOC << 8) | (L1_ITLB_4K_ENTRIES); -- *ecx = (L1D_SIZE_KB_AMD << 24) | (L1D_ASSOCIATIVITY_AMD << 16) | \ -- (L1D_LINES_PER_TAG << 8) | (L1D_LINE_SIZE); -- *edx = (L1I_SIZE_KB_AMD << 24) | (L1I_ASSOCIATIVITY_AMD << 16) | \ -- (L1I_LINES_PER_TAG << 8) | (L1I_LINE_SIZE); -+ *ecx = encode_cache_cpuid80000005(&l1d_cache_amd); -+ *edx = encode_cache_cpuid80000005(&l1i_cache_amd); - break; - case 0x80000006: - /* cache info (L2 cache) */ -@@ -3602,18 +3858,9 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, - (L2_DTLB_4K_ENTRIES << 16) | \ - (AMD_ENC_ASSOC(L2_ITLB_4K_ASSOC) << 12) | \ - (L2_ITLB_4K_ENTRIES); -- *ecx = (L2_SIZE_KB_AMD << 16) | \ -- (AMD_ENC_ASSOC(L2_ASSOCIATIVITY) << 12) | \ -- (L2_LINES_PER_TAG << 8) | (L2_LINE_SIZE); -- if (!cpu->enable_l3_cache) { -- *edx = ((L3_SIZE_KB / 512) << 18) | \ -- (AMD_ENC_ASSOC(L3_ASSOCIATIVITY) << 12) | \ -- (L3_LINES_PER_TAG << 8) | (L3_LINE_SIZE); -- } else { -- *edx = ((L3_N_SIZE_KB_AMD / 512) << 18) | \ -- (AMD_ENC_ASSOC(L3_N_ASSOCIATIVITY) << 12) | \ -- (L3_N_LINES_PER_TAG << 8) | (L3_N_LINE_SIZE); -- } -+ encode_cache_cpuid80000006(&l2_cache_amd, -+ cpu->enable_l3_cache ? &l3_cache : NULL, -+ ecx, edx); - break; - case 0x80000007: - *eax = 0; -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 1b219fa..fa03e2c 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -1044,6 +1044,59 @@ typedef enum TPRAccess { - TPR_ACCESS_WRITE, - } TPRAccess; - -+/* Cache information data structures: */ -+ -+enum CacheType { -+ DCACHE, -+ ICACHE, -+ UNIFIED_CACHE -+}; -+ -+typedef struct CPUCacheInfo { -+ enum CacheType type; -+ uint8_t level; -+ /* Size in bytes */ -+ uint32_t size; -+ /* Line size, in bytes */ -+ uint16_t line_size; -+ /* -+ * Associativity. -+ * Note: representation of fully-associative caches is not implemented -+ */ -+ uint8_t associativity; -+ /* Physical line partitions. CPUID[0x8000001D].EBX, CPUID[4].EBX */ -+ uint8_t partitions; -+ /* Number of sets. CPUID[0x8000001D].ECX, CPUID[4].ECX */ -+ uint32_t sets; -+ /* -+ * Lines per tag. -+ * AMD-specific: CPUID[0x80000005], CPUID[0x80000006]. -+ * (Is this synonym to @partitions?) -+ */ -+ uint8_t lines_per_tag; -+ -+ /* Self-initializing cache */ -+ bool self_init; -+ /* -+ * WBINVD/INVD is not guaranteed to act upon lower level caches of -+ * non-originating threads sharing this cache. -+ * CPUID[4].EDX[bit 0], CPUID[0x8000001D].EDX[bit 0] -+ */ -+ bool no_invd_sharing; -+ /* -+ * Cache is inclusive of lower cache levels. -+ * CPUID[4].EDX[bit 1], CPUID[0x8000001D].EDX[bit 1]. -+ */ -+ bool inclusive; -+ /* -+ * A complex function is used to index the cache, potentially using all -+ * address bits. CPUID[4].EDX[bit 2]. -+ */ -+ bool complex_indexing; -+} CPUCacheInfo; -+ -+ -+ - typedef struct CPUX86State { - /* standard registers */ - target_ulong regs[CPU_NB_REGS]; -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index b6c1592..a518a0f 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -1105,6 +1105,7 @@ struct X86CPUDefinition { - int stepping; - FeatureWordArray features; - const char *model_id; -+ CPUCaches cache_info; - }; - - static X86CPUDefinition builtin_x86_defs[] = { -@@ -3242,6 +3243,9 @@ static void x86_cpu_load_def(X86CPU *cpu, X86CPUDefinition *def, Error **errp) - env->features[w] = def->features[w]; - } - -+ /* Load Cache information from the X86CPUDefinition */ -+ memcpy(&env->cache_info, &def->cache_info, sizeof(CPUCaches)); -+ - /* Special cases not set in the X86CPUDefinition structs: */ - /* TODO: in-kernel irqchip for hvf */ - if (kvm_enabled()) { -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index fa03e2c..1213bb7 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -1096,6 +1096,13 @@ typedef struct CPUCacheInfo { - } CPUCacheInfo; - - -+typedef struct CPUCaches { -+ bool valid; -+ CPUCacheInfo l1d_cache; -+ CPUCacheInfo l1i_cache; -+ CPUCacheInfo l2_cache; -+ CPUCacheInfo l3_cache; -+} CPUCaches; - - typedef struct CPUX86State { - /* standard registers */ -@@ -1282,6 +1289,7 @@ typedef struct CPUX86State { - /* Features that were explicitly enabled/disabled */ - FeatureWordArray user_features; - uint32_t cpuid_model[12]; -+ CPUCaches cache_info; - - /* MTRRs */ - uint64_t mtrr_fixed[11]; -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index a518a0f..5d88363 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -2302,6 +2302,54 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_6_EAX_ARAT, - .xlevel = 0x8000000A, - .model_id = "AMD EPYC Processor", -+ .cache_info.valid = 1, -+ .cache_info.l1d_cache = { -+ .type = DCACHE, -+ .level = 1, -+ .size = 32 * KiB, -+ .line_size = 64, -+ .associativity = 8, -+ .partitions = 1, -+ .sets = 64, -+ .lines_per_tag = 1, -+ .self_init = 1, -+ .no_invd_sharing = true, -+ }, -+ .cache_info.l1i_cache = { -+ .type = ICACHE, -+ .level = 1, -+ .size = 64 * KiB, -+ .line_size = 64, -+ .associativity = 4, -+ .partitions = 1, -+ .sets = 256, -+ .lines_per_tag = 1, -+ .self_init = 1, -+ .no_invd_sharing = true, -+ }, -+ .cache_info.l2_cache = { -+ .type = UNIFIED_CACHE, -+ .level = 2, -+ .size = 512 * KiB, -+ .line_size = 64, -+ .associativity = 8, -+ .partitions = 1, -+ .sets = 1024, -+ .lines_per_tag = 1, -+ }, -+ .cache_info.l3_cache = { -+ .type = UNIFIED_CACHE, -+ .level = 3, -+ .size = 8 * MiB, -+ .line_size = 64, -+ .associativity = 16, -+ .partitions = 1, -+ .sets = 8192, -+ .lines_per_tag = 1, -+ .self_init = true, -+ .inclusive = true, -+ .complex_indexing = true, -+ }, - }, - { - .name = "EPYC-IBPB", -@@ -2348,6 +2396,54 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_6_EAX_ARAT, - .xlevel = 0x8000000A, - .model_id = "AMD EPYC Processor (with IBPB)", -+ .cache_info.valid = 1, -+ .cache_info.l1d_cache = { -+ .type = DCACHE, -+ .level = 1, -+ .size = 32 * KiB, -+ .line_size = 64, -+ .associativity = 8, -+ .partitions = 1, -+ .sets = 64, -+ .lines_per_tag = 1, -+ .self_init = 1, -+ .no_invd_sharing = true, -+ }, -+ .cache_info.l1i_cache = { -+ .type = ICACHE, -+ .level = 1, -+ .size = 64 * KiB, -+ .line_size = 64, -+ .associativity = 4, -+ .partitions = 1, -+ .sets = 256, -+ .lines_per_tag = 1, -+ .self_init = 1, -+ .no_invd_sharing = true, -+ }, -+ .cache_info.l2_cache = { -+ .type = UNIFIED_CACHE, -+ .level = 2, -+ .size = 512 * KiB, -+ .line_size = 64, -+ .associativity = 8, -+ .partitions = 1, -+ .sets = 1024, -+ .lines_per_tag = 1, -+ }, -+ .cache_info.l3_cache = { -+ .type = UNIFIED_CACHE, -+ .level = 3, -+ .size = 8 * MiB, -+ .line_size = 64, -+ .associativity = 16, -+ .partitions = 1, -+ .sets = 8192, -+ .lines_per_tag = 1, -+ .self_init = true, -+ .inclusive = true, -+ .complex_indexing = true, -+ }, - }, - }; - -diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h -index ffee841..d904a3c 100644 ---- a/include/hw/i386/pc.h -+++ b/include/hw/i386/pc.h -@@ -327,6 +327,10 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); - .driver = "q35-pcihost",\ - .property = "x-pci-hole64-fix",\ - .value = "off",\ -+ },{\ -+ .driver = TYPE_X86_CPU,\ -+ .property = "legacy-cache",\ -+ .value = "on",\ - }, - - #define PC_COMPAT_2_9 \ -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 5d88363..a27b658 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -5138,6 +5138,7 @@ static Property x86_cpu_properties[] = { - false), - DEFINE_PROP_BOOL("vmware-cpuid-freq", X86CPU, vmware_cpuid_freq, true), - DEFINE_PROP_BOOL("tcg-cpuid", X86CPU, expose_tcg, true), -+ DEFINE_PROP_BOOL("legacy-cache", X86CPU, legacy_cache, false), - - /* - * From "Requirements for Implementing the Microsoft -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 1213bb7..852586a 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -1395,6 +1395,11 @@ struct X86CPU { - */ - bool enable_l3_cache; - -+ /* Compatibility bits for old machine types. -+ * If true present the old cache topology information -+ */ -+ bool legacy_cache; -+ - /* Compatibility bits for old machine types: */ - bool enable_cpuid_0xb; - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index a27b658..56d2f0b 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -3941,8 +3941,13 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, - (L1_ITLB_2M_ASSOC << 8) | (L1_ITLB_2M_ENTRIES); - *ebx = (L1_DTLB_4K_ASSOC << 24) | (L1_DTLB_4K_ENTRIES << 16) | \ - (L1_ITLB_4K_ASSOC << 8) | (L1_ITLB_4K_ENTRIES); -- *ecx = encode_cache_cpuid80000005(&l1d_cache_amd); -- *edx = encode_cache_cpuid80000005(&l1i_cache_amd); -+ if (env->cache_info.valid && !cpu->legacy_cache) { -+ *ecx = encode_cache_cpuid80000005(&env->cache_info.l1d_cache); -+ *edx = encode_cache_cpuid80000005(&env->cache_info.l1i_cache); -+ } else { -+ *ecx = encode_cache_cpuid80000005(&l1d_cache_amd); -+ *edx = encode_cache_cpuid80000005(&l1i_cache_amd); -+ } - break; - case 0x80000006: - /* cache info (L2 cache) */ -@@ -3958,9 +3963,16 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, - (L2_DTLB_4K_ENTRIES << 16) | \ - (AMD_ENC_ASSOC(L2_ITLB_4K_ASSOC) << 12) | \ - (L2_ITLB_4K_ENTRIES); -- encode_cache_cpuid80000006(&l2_cache_amd, -- cpu->enable_l3_cache ? &l3_cache : NULL, -- ecx, edx); -+ if (env->cache_info.valid && !cpu->legacy_cache) { -+ encode_cache_cpuid80000006(&env->cache_info.l2_cache, -+ cpu->enable_l3_cache ? -+ &env->cache_info.l3_cache : NULL, -+ ecx, edx); -+ } else { -+ encode_cache_cpuid80000006(&l2_cache_amd, -+ cpu->enable_l3_cache ? &l3_cache : NULL, -+ ecx, edx); -+ } - break; - case 0x80000007: - *eax = 0; -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 56d2f0b..1024b09 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -307,6 +307,14 @@ static uint32_t encode_cache_cpuid80000005(CPUCacheInfo *cache) - a == ASSOC_FULL ? 0xF : \ - 0 /* invalid value */) - -+/* Definitions used on CPUID Leaf 0x8000001D */ -+/* Number of logical cores in a complex */ -+#define CORES_IN_CMPLX 4 -+/* Number of logical processors sharing cache */ -+#define NUM_SHARING_CACHE(threads) (threads ? \ -+ (((CORES_IN_CMPLX - 1) * 2) + 1) : \ -+ (CORES_IN_CMPLX - 1)) -+ - /* - * Encode cache info for CPUID[0x80000006].ECX and CPUID[0x80000006].EDX - * @l3 can be NULL. -@@ -336,6 +344,41 @@ static void encode_cache_cpuid80000006(CPUCacheInfo *l2, - } - } - -+/* Encode cache info for CPUID[8000001D] */ -+static void encode_cache_cpuid8000001d(CPUCacheInfo *cache, int nr_threads, -+ uint32_t *eax, uint32_t *ebx, -+ uint32_t *ecx, uint32_t *edx) -+{ -+ assert(cache->size == cache->line_size * cache->associativity * -+ cache->partitions * cache->sets); -+ -+ *eax = CACHE_TYPE(cache->type) | CACHE_LEVEL(cache->level) | -+ (cache->self_init ? CACHE_SELF_INIT_LEVEL : 0); -+ -+ /* L3 is shared among multiple cores */ -+ if (cache->level == 3) { -+ *eax |= (NUM_SHARING_CACHE(nr_threads - 1) << 14); -+ } else { -+ *eax |= ((nr_threads - 1) << 14); -+ } -+ -+ assert(cache->line_size > 0); -+ assert(cache->partitions > 0); -+ assert(cache->associativity > 0); -+ /* We don't implement fully-associative caches */ -+ assert(cache->associativity < cache->sets); -+ *ebx = (cache->line_size - 1) | -+ ((cache->partitions - 1) << 12) | -+ ((cache->associativity - 1) << 22); -+ -+ assert(cache->sets > 0); -+ *ecx = cache->sets - 1; -+ -+ *edx = (cache->no_invd_sharing ? CACHE_NO_INVD_SHARING : 0) | -+ (cache->inclusive ? CACHE_INCLUSIVE : 0) | -+ (cache->complex_indexing ? CACHE_COMPLEX_IDX : 0); -+} -+ - /* Definitions of the hardcoded cache entries we expose: */ - - /* L1 data cache: */ -@@ -4013,6 +4056,55 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, - *edx = 0; - } - break; -+ case 0x8000001D: -+ *eax = 0; -+ switch (count) { -+ case 0: /* L1 dcache info */ -+ if (env->cache_info.valid && !cpu->legacy_cache) { -+ encode_cache_cpuid8000001d(&env->cache_info.l1d_cache, -+ cs->nr_threads, -+ eax, ebx, ecx, edx); -+ } else { -+ encode_cache_cpuid8000001d(&l1d_cache_amd, cs->nr_threads, -+ eax, ebx, ecx, edx); -+ } -+ break; -+ case 1: /* L1 icache info */ -+ if (env->cache_info.valid && !cpu->legacy_cache) { -+ encode_cache_cpuid8000001d(&env->cache_info.l1i_cache, -+ cs->nr_threads, -+ eax, ebx, ecx, edx); -+ } else { -+ encode_cache_cpuid8000001d(&l1i_cache_amd, -+ cs->nr_threads, -+ eax, ebx, ecx, edx); -+ } -+ break; -+ case 2: /* L2 cache info */ -+ if (env->cache_info.valid && !cpu->legacy_cache) { -+ encode_cache_cpuid8000001d(&env->cache_info.l2_cache, -+ cs->nr_threads, -+ eax, ebx, ecx, edx); -+ } else { -+ encode_cache_cpuid8000001d(&l2_cache_amd, cs->nr_threads, -+ eax, ebx, ecx, edx); -+ } -+ break; -+ case 3: /* L3 cache info */ -+ if (env->cache_info.valid && !cpu->legacy_cache) { -+ encode_cache_cpuid8000001d(&env->cache_info.l3_cache, -+ cs->nr_threads, -+ eax, ebx, ecx, edx); -+ } else { -+ encode_cache_cpuid8000001d(&l3_cache, cs->nr_threads, -+ eax, ebx, ecx, edx); -+ } -+ break; -+ default: /* end of info */ -+ *eax = *ebx = *ecx = *edx = 0; -+ break; -+ } -+ break; - case 0xC0000000: - *eax = env->cpuid_xlevel2; - *ebx = 0; -diff --git a/target/i386/kvm.c b/target/i386/kvm.c -index 6c49954..6e66f9c 100644 ---- a/target/i386/kvm.c -+++ b/target/i386/kvm.c -@@ -967,9 +967,32 @@ int kvm_arch_init_vcpu(CPUState *cs) - } - c = &cpuid_data.entries[cpuid_i++]; - -- c->function = i; -- c->flags = 0; -- cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx); -+ switch (i) { -+ case 0x8000001d: -+ /* Query for all AMD cache information leaves */ -+ for (j = 0; ; j++) { -+ c->function = i; -+ c->flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX; -+ c->index = j; -+ cpu_x86_cpuid(env, i, j, &c->eax, &c->ebx, &c->ecx, &c->edx); -+ -+ if (c->eax == 0) { -+ break; -+ } -+ if (cpuid_i == KVM_MAX_CPUID_ENTRIES) { -+ fprintf(stderr, "cpuid_data is full, no space for " -+ "cpuid(eax:0x%x,ecx:0x%x)\n", i, j); -+ abort(); -+ } -+ c = &cpuid_data.entries[cpuid_i++]; -+ } -+ break; -+ default: -+ c->function = i; -+ c->flags = 0; -+ cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx); -+ break; -+ } - } - - /* Call Centaur's CPUID instructions they are supported. */ -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 1024b09..1b15023 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -315,6 +315,12 @@ static uint32_t encode_cache_cpuid80000005(CPUCacheInfo *cache) - (((CORES_IN_CMPLX - 1) * 2) + 1) : \ - (CORES_IN_CMPLX - 1)) - -+/* Definitions used on CPUID Leaf 0x8000001E */ -+#define EXTENDED_APIC_ID(threads, socket_id, core_id, thread_id) \ -+ ((threads) ? \ -+ ((socket_id << 6) | (core_id << 1) | thread_id) : \ -+ ((socket_id << 6) | core_id)) -+ - /* - * Encode cache info for CPUID[0x80000006].ECX and CPUID[0x80000006].EDX - * @l3 can be NULL. -@@ -4105,6 +4111,14 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, - break; - } - break; -+ case 0x8000001E: -+ assert(cpu->core_id <= 255); -+ *eax = EXTENDED_APIC_ID((cs->nr_threads - 1), -+ cpu->socket_id, cpu->core_id, cpu->thread_id); -+ *ebx = (cs->nr_threads - 1) << 8 | cpu->core_id; -+ *ecx = cpu->socket_id; -+ *edx = 0; -+ break; - case 0xC0000000: - *eax = env->cpuid_xlevel2; - *ebx = 0; -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 1b15023..6ebbef2 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -2334,7 +2334,8 @@ static X86CPUDefinition builtin_x86_defs[] = { - .features[FEAT_8000_0001_ECX] = - CPUID_EXT3_OSVW | CPUID_EXT3_3DNOWPREFETCH | - CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | -- CPUID_EXT3_CR8LEG | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM, -+ CPUID_EXT3_CR8LEG | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM | -+ CPUID_EXT3_TOPOEXT, - .features[FEAT_7_0_EBX] = - CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_AVX2 | - CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_RDSEED | -@@ -2426,7 +2427,8 @@ static X86CPUDefinition builtin_x86_defs[] = { - .features[FEAT_8000_0001_ECX] = - CPUID_EXT3_OSVW | CPUID_EXT3_3DNOWPREFETCH | - CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | -- CPUID_EXT3_CR8LEG | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM, -+ CPUID_EXT3_CR8LEG | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM | -+ CPUID_EXT3_TOPOEXT, - .features[FEAT_8000_0008_EBX] = - CPUID_8000_0008_EBX_IBPB, - .features[FEAT_7_0_EBX] = -@@ -4580,6 +4582,11 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp) - x86_cpu_adjust_level(cpu, &env->cpuid_min_xlevel, 0x8000000A); - } - -+ /* TOPOEXT feature requires 0x8000001E */ -+ if (env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_TOPOEXT) { -+ x86_cpu_adjust_level(cpu, &env->cpuid_min_xlevel, 0x8000001E); -+ } -+ - /* SEV requires CPUID[0x8000001F] */ - if (sev_enabled()) { - x86_cpu_adjust_level(cpu, &env->cpuid_min_xlevel, 0x8000001F); -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 6ebbef2..54d908f 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -4830,17 +4830,20 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) - - qemu_init_vcpu(cs); - -- /* Only Intel CPUs support hyperthreading. Even though QEMU fixes this -- * issue by adjusting CPUID_0000_0001_EBX and CPUID_8000_0008_ECX -- * based on inputs (sockets,cores,threads), it is still better to gives -+ /* Most Intel and certain AMD CPUs support hyperthreading. Even though QEMU -+ * fixes this issue by adjusting CPUID_0000_0001_EBX and CPUID_8000_0008_ECX -+ * based on inputs (sockets,cores,threads), it is still better to give - * users a warning. - * - * NOTE: the following code has to follow qemu_init_vcpu(). Otherwise - * cs->nr_threads hasn't be populated yet and the checking is incorrect. - */ -- if (!IS_INTEL_CPU(env) && cs->nr_threads > 1 && !ht_warned) { -- error_report("AMD CPU doesn't support hyperthreading. Please configure" -- " -smp options properly."); -+ if (IS_AMD_CPU(env) && -+ !(env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_TOPOEXT) && -+ cs->nr_threads > 1 && !ht_warned) { -+ error_report("This family of AMD CPU doesn't support " -+ "hyperthreading. Please configure -smp " -+ "options properly."); - ht_warned = true; - } - diff --git a/audio-improvements.patch b/pa-fixes.patch index d51a053a642b..65d046502c92 100644 --- a/audio-improvements.patch +++ b/pa-fixes.patch @@ -1,8 +1,20 @@ -diff --git audio/audio.c audio/audio.c -index 6eccdb17ee..4eb190a18f 100644 ---- audio/audio.c -+++ audio/audio.c -@@ -2097,3 +2097,8 @@ void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol) +From fa5f68de47d120b4f6a5f973f21567ef389b42ac Mon Sep 17 00:00:00 2001 +From: Geoffrey McRae <geoff@hostfission.com> +Date: Tue, 8 May 2018 02:59:17 +1000 +Subject: [PATCH] PA fixes + +--- + audio/audio.c | 5 + + audio/audio_int.h | 2 + + audio/paaudio.c | 635 +++++++++++++++++-------------------------- + hw/audio/hda-codec.c | 2 + + 4 files changed, 264 insertions(+), 380 deletions(-) + +diff --git a/audio/audio.c b/audio/audio.c +index 1ace47f510..253e470d12 100644 +--- a/audio/audio.c ++++ b/audio/audio.c +@@ -2118,3 +2118,8 @@ void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol) } } } @@ -11,10 +23,10 @@ index 6eccdb17ee..4eb190a18f 100644 +{ + return conf.period.ticks; +} -diff --git audio/audio_int.h audio/audio_int.h +diff --git a/audio/audio_int.h b/audio/audio_int.h index 244b454012..19ba2d7aa4 100644 ---- audio/audio_int.h -+++ audio/audio_int.h +--- a/audio/audio_int.h ++++ b/audio/audio_int.h @@ -210,6 +210,8 @@ extern const struct mixeng_volume nominal_volume; void audio_driver_register(audio_driver *drv); audio_driver *audio_driver_lookup(const char *name); @@ -24,10 +36,10 @@ index 244b454012..19ba2d7aa4 100644 void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as); void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len); -diff --git audio/paaudio.c audio/paaudio.c -index 949769774d..cfa200fa96 100644 ---- audio/paaudio.c -+++ audio/paaudio.c +diff --git a/audio/paaudio.c b/audio/paaudio.c +index 949769774d..bd5a1781bf 100644 +--- a/audio/paaudio.c ++++ b/audio/paaudio.c @@ -1,16 +1,22 @@ /* public domain */ #include "qemu/osdep.h" @@ -87,21 +99,10 @@ index 949769774d..cfa200fa96 100644 } PAVoiceIn; static void qpa_audio_fini(void *opaque); -@@ -89,7 +85,7 @@ static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x) - } \ - goto label; \ - } \ -- } while (0) -+ } while (0); - - #define CHECK_DEAD_GOTO(c, stream, rerror, label) \ - do { \ -@@ -107,184 +103,61 @@ static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x) - } \ - goto label; \ +@@ -109,182 +105,59 @@ static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x) } \ -- } while (0) -- + } while (0) + -static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror) -{ - paaudio *g = p->g; @@ -150,8 +151,7 @@ index 949769774d..cfa200fa96 100644 - - pa_threaded_mainloop_unlock (g->mainloop); - return 0; -+ } while (0); - +- -unlock_and_fail: - pa_threaded_mainloop_unlock (g->mainloop); - return -1; @@ -840,10 +840,10 @@ index 949769774d..cfa200fa96 100644 }, { .name = "SERVER", -diff --git hw/audio/hda-codec.c hw/audio/hda-codec.c -index e8aa7842e6..e68830490f 100644 ---- hw/audio/hda-codec.c -+++ hw/audio/hda-codec.c +diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c +index 617a1c1016..6627c5cbfd 100644 +--- a/hw/audio/hda-codec.c ++++ b/hw/audio/hda-codec.c @@ -18,6 +18,7 @@ */ @@ -852,286 +852,14 @@ index e8aa7842e6..e68830490f 100644 #include "hw/hw.h" #include "hw/pci/pci.h" #include "intel-hda.h" -@@ -126,6 +127,11 @@ static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as) - #define PARAM nomixemu +@@ -128,6 +129,7 @@ static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as) #include "hda-codec-common.h" -+#define HDA_TIMER_TICKS (SCALE_MS) + #define HDA_TIMER_TICKS (SCALE_MS) +#define MAX_CORR (SCALE_US * 100) -+#define B_SIZE sizeof(st->buf) -+#define B_MASK (sizeof(st->buf) - 1) -+ - /* -------------------------------------------------------------------------- */ - - static const char *fmt2name[] = { -@@ -154,8 +160,13 @@ struct HDAAudioStream { - SWVoiceIn *in; - SWVoiceOut *out; - } voice; -- uint8_t buf[HDA_BUFFER_SIZE]; -- uint32_t bpos; -+ uint8_t compat_buf[HDA_BUFFER_SIZE]; -+ uint32_t compat_bpos; -+ uint8_t buf[8192]; /* size must be power of two */ -+ int64_t rpos; -+ int64_t wpos; -+ QEMUTimer *buft; -+ int64_t buft_start; - }; - - #define TYPE_HDA_AUDIO "hda-audio" -@@ -176,53 +187,146 @@ struct HDAAudioState { - bool mixer; - }; - -+static inline int64_t hda_bytes_per_second(HDAAudioStream *st) -+{ -+ return 2 * st->as.nchannels * st->as.freq; -+} -+ -+static inline void hda_timer_sync_adjust(HDAAudioStream *st, int64_t target_pos) -+{ -+ int64_t corr = -+ NANOSECONDS_PER_SECOND * target_pos / hda_bytes_per_second(st); -+ if (corr > MAX_CORR) { -+ corr = MAX_CORR; -+ } else if (corr < -MAX_CORR) { -+ corr = -MAX_CORR; -+ } -+ atomic_fetch_add(&st->buft_start, corr); -+} -+ -+static void hda_audio_input_timer(void *opaque) -+{ -+ HDAAudioStream *st = opaque; -+ -+ int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); -+ -+ int64_t buft_start = atomic_fetch_add(&st->buft_start, 0); -+ int64_t wpos = atomic_fetch_add(&st->wpos, 0); -+ int64_t rpos = atomic_fetch_add(&st->rpos, 0); -+ -+ int64_t wanted_rpos = hda_bytes_per_second(st) * (now - buft_start) -+ / NANOSECONDS_PER_SECOND; -+ wanted_rpos &= -4; /* IMPORTANT! clip to frames */ -+ -+ if (wanted_rpos <= rpos) { -+ /* we already transmitted the data */ -+ goto out_timer; -+ } -+ -+ int64_t to_transfer = audio_MIN(wpos - rpos, wanted_rpos - rpos); -+ while (to_transfer) { -+ uint32_t start = (rpos & B_MASK); -+ uint32_t chunk = audio_MIN(B_SIZE - start, to_transfer); -+ int rc = hda_codec_xfer( -+ &st->state->hda, st->stream, false, st->buf + start, chunk); -+ if (!rc) { -+ break; -+ } -+ rpos += chunk; -+ to_transfer -= chunk; -+ atomic_fetch_add(&st->rpos, chunk); -+ } -+ -+out_timer: -+ -+ if (st->running) { -+ timer_mod_anticipate_ns(st->buft, now + HDA_TIMER_TICKS); -+ } -+} -+ - static void hda_audio_input_cb(void *opaque, int avail) - { - HDAAudioStream *st = opaque; -- int recv = 0; -- int len; -- bool rc; -- -- while (avail - recv >= sizeof(st->buf)) { -- if (st->bpos != sizeof(st->buf)) { -- len = AUD_read(st->voice.in, st->buf + st->bpos, -- sizeof(st->buf) - st->bpos); -- st->bpos += len; -- recv += len; -- if (st->bpos != sizeof(st->buf)) { -- break; -- } -+ -+ int64_t wpos = atomic_fetch_add(&st->wpos, 0); -+ int64_t rpos = atomic_fetch_add(&st->rpos, 0); -+ -+ int64_t to_transfer = audio_MIN(B_SIZE - (wpos - rpos), avail); -+ -+ hda_timer_sync_adjust(st, -((wpos - rpos) + to_transfer - (B_SIZE >> 1))); -+ -+ while (to_transfer) { -+ uint32_t start = (uint32_t) (wpos & B_MASK); -+ uint32_t chunk = (uint32_t) audio_MIN(B_SIZE - start, to_transfer); -+ uint32_t read = AUD_read(st->voice.in, st->buf + start, chunk); -+ wpos += read; -+ to_transfer -= read; -+ atomic_fetch_add(&st->wpos, read); -+ if (chunk != read) { -+ break; - } -- rc = hda_codec_xfer(&st->state->hda, st->stream, false, -- st->buf, sizeof(st->buf)); -+ } -+} -+ -+static void hda_audio_output_timer(void *opaque) -+{ -+ HDAAudioStream *st = opaque; -+ -+ int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); -+ -+ int64_t buft_start = atomic_fetch_add(&st->buft_start, 0); -+ int64_t wpos = atomic_fetch_add(&st->wpos, 0); -+ int64_t rpos = atomic_fetch_add(&st->rpos, 0); -+ -+ int64_t wanted_wpos = hda_bytes_per_second(st) * (now - buft_start) -+ / NANOSECONDS_PER_SECOND; -+ wanted_wpos &= -4; /* IMPORTANT! clip to frames */ -+ -+ if (wanted_wpos <= wpos) { -+ /* we already received the data */ -+ goto out_timer; -+ } -+ -+ int64_t to_transfer = audio_MIN(B_SIZE - (wpos - rpos), wanted_wpos - wpos); -+ while (to_transfer) { -+ uint32_t start = (wpos & B_MASK); -+ uint32_t chunk = audio_MIN(B_SIZE - start, to_transfer); -+ int rc = hda_codec_xfer( -+ &st->state->hda, st->stream, true, st->buf + start, chunk); - if (!rc) { - break; - } -- st->bpos = 0; -+ wpos += chunk; -+ to_transfer -= chunk; -+ atomic_fetch_add(&st->wpos, chunk); -+ } -+ -+out_timer: -+ -+ if (st->running) { -+ timer_mod_anticipate_ns(st->buft, now + HDA_TIMER_TICKS); - } - } - - static void hda_audio_output_cb(void *opaque, int avail) - { - HDAAudioStream *st = opaque; -- int sent = 0; -- int len; -- bool rc; -- -- while (avail - sent >= sizeof(st->buf)) { -- if (st->bpos == sizeof(st->buf)) { -- rc = hda_codec_xfer(&st->state->hda, st->stream, true, -- st->buf, sizeof(st->buf)); -- if (!rc) { -- break; -- } -- st->bpos = 0; -- } -- len = AUD_write(st->voice.out, st->buf + st->bpos, -- sizeof(st->buf) - st->bpos); -- st->bpos += len; -- sent += len; -- if (st->bpos != sizeof(st->buf)) { -+ -+ int64_t wpos = atomic_fetch_add(&st->wpos, 0); -+ int64_t rpos = atomic_fetch_add(&st->rpos, 0); -+ -+ int64_t to_transfer = audio_MIN(wpos - rpos, avail); -+ -+ hda_timer_sync_adjust(st, (wpos - rpos) - to_transfer - (B_SIZE >> 1)); -+ -+ while (to_transfer) { -+ uint32_t start = (uint32_t) (rpos & B_MASK); -+ uint32_t chunk = (uint32_t) audio_MIN(B_SIZE - start, to_transfer); -+ uint32_t written = AUD_write(st->voice.out, st->buf + start, chunk); -+ rpos += written; -+ to_transfer -= written; -+ atomic_fetch_add(&st->rpos, written); -+ if (chunk != written) { - break; - } - } -@@ -239,6 +343,15 @@ static void hda_audio_set_running(HDAAudioStream *st, bool running) - st->running = running; - dprint(st->state, 1, "%s: %s (stream %d)\n", st->node->name, - st->running ? "on" : "off", st->stream); -+ if (running) { -+ int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); -+ st->rpos = 0; -+ st->wpos = 0; -+ st->buft_start = now; -+ timer_mod_anticipate_ns(st->buft, now + HDA_TIMER_TICKS); -+ } else { -+ timer_del(st->buft); -+ } - if (st->output) { - AUD_set_active_out(st->voice.out, st->running); - } else { -@@ -286,10 +399,12 @@ static void hda_audio_setup(HDAAudioStream *st) - st->voice.out = AUD_open_out(&st->state->card, st->voice.out, - st->node->name, st, - hda_audio_output_cb, &st->as); -+ st->buft = timer_new_ns(QEMU_CLOCK_VIRTUAL, hda_audio_output_timer, st); - } else { - st->voice.in = AUD_open_in(&st->state->card, st->voice.in, - st->node->name, st, - hda_audio_input_cb, &st->as); -+ st->buft = timer_new_ns(QEMU_CLOCK_VIRTUAL, hda_audio_input_timer, st); - } - } - -@@ -505,7 +620,6 @@ static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc) - /* unmute output by default */ - st->gain_left = QEMU_HDA_AMP_STEPS; - st->gain_right = QEMU_HDA_AMP_STEPS; -- st->bpos = sizeof(st->buf); - st->output = true; - } else { - st->output = false; -@@ -532,6 +646,7 @@ static void hda_audio_exit(HDACodecDevice *hda) - if (st->node == NULL) { - continue; - } -+ timer_del(st->buft); - if (st->output) { - AUD_close_out(&a->card, st->voice.out); - } else { -@@ -592,8 +707,8 @@ static const VMStateDescription vmstate_hda_audio_stream = { - VMSTATE_UINT32(gain_right, HDAAudioStream), - VMSTATE_BOOL(mute_left, HDAAudioStream), - VMSTATE_BOOL(mute_right, HDAAudioStream), -- VMSTATE_UINT32(bpos, HDAAudioStream), -- VMSTATE_BUFFER(buf, HDAAudioStream), -+ VMSTATE_UINT32(compat_bpos, HDAAudioStream), -+ VMSTATE_BUFFER(compat_buf, HDAAudioStream), - VMSTATE_END_OF_LIST() - } - }; -diff --git hw/audio/intel-hda.c hw/audio/intel-hda.c -index 948268afd8..23a2cf6484 100644 ---- hw/audio/intel-hda.c -+++ hw/audio/intel-hda.c -@@ -407,13 +407,6 @@ static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, - if (st->bpl == NULL) { - return false; - } -- if (st->ctl & (1 << 26)) { -- /* -- * Wait with the next DMA xfer until the guest -- * has acked the buffer completion interrupt -- */ -- return false; -- } + #define B_SIZE sizeof(st->buf) + #define B_MASK (sizeof(st->buf) - 1) - left = len; - s = st->bentries; +-- +2.18.0 + diff --git a/ps2-fixes-v2.patch b/ps2-fixes-v2.patch deleted file mode 100644 index 3aa3f90ed5ae..000000000000 --- a/ps2-fixes-v2.patch +++ /dev/null @@ -1,315 +0,0 @@ -This allows guest's to correctly reinitialize and identify the mouse -should the guest decide to re-scan or reset during mouse input events. - -When the guest sends the "Identify" command, due to the PC's hardware -architecutre it is impossible to reliably determine the response from -the command amongst other streaming data, such as mouse or keyboard -events. Standard practice is for the guest to disable the device and -then issue the identify command, so this must be obeyed. - -Signed-off-by: Geoffrey McRae <address@hidden> ---- - hw/input/ps2.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/hw/input/ps2.c b/hw/input/ps2.c -index 06f5d2ac4a..f84a8f5179 100644 ---- a/hw/input/ps2.c -+++ b/hw/input/ps2.c -@@ -232,6 +232,9 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, - uint16_t keycode = 0; - int mod; - -+ if (!s->scan_enabled) -+ return; -+ - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); - assert(evt->type == INPUT_EVENT_KIND_KEY); - qcode = qemu_input_key_value_to_qcode(key->key); -@@ -673,6 +676,9 @@ static void ps2_mouse_sync(DeviceState *dev) - { - PS2MouseState *s = (PS2MouseState *)dev; - -+ if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) -+ return; -+ - if (s->mouse_buttons) { - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); - } -@@ -776,6 +782,7 @@ void ps2_write_mouse(void *opaque, int val) - s->mouse_resolution = 2; - s->mouse_status = 0; - s->mouse_type = 0; -+ ps2_reset_queue(&s->common); - ps2_queue(&s->common, AUX_ACK); - ps2_queue(&s->common, 0xaa); - ps2_queue(&s->common, s->mouse_type); --- -2.14.2 - -This fixes an issue by adding bounds checking to multi-byte packets -where the PS/2 mouse data stream may become corrupted due to data being -discarded when the PS/2 ringbuffer is full. - -Interrupts for Multi-byte responses are postponed until the final byte -has been queued. - -These changes fix a bug where windows guests drop the mouse device -entirely requring the guest to be restarted. - -Signed-off-by: Geoffrey McRae <address@hidden> ---- - hw/input/ps2.c | 120 +++++++++++++++++++++++++++++++++++++------------ - include/hw/input/ps2.h | 5 +++ - 2 files changed, 96 insertions(+), 29 deletions(-) - -diff --git a/hw/input/ps2.c b/hw/input/ps2.c -index f84a8f5179..0580ca0700 100644 ---- a/hw/input/ps2.c -+++ b/hw/input/ps2.c -@@ -188,16 +188,60 @@ static void ps2_reset_queue(PS2State *s) - q->count = 0; - } - --void ps2_queue(PS2State *s, int b) -+void ps2_queue_noirq(PS2State *s, int b) - { - PS2Queue *q = &s->queue; - -- if (q->count >= PS2_QUEUE_SIZE - 1) -+ if (q->count == PS2_QUEUE_SIZE) - return; -+ - q->data[q->wptr] = b; - if (++q->wptr == PS2_QUEUE_SIZE) - q->wptr = 0; - q->count++; -+} -+ -+void ps2_raise_irq(PS2State *s) -+{ -+ s->update_irq(s->update_arg, 1); -+} -+ -+void ps2_queue(PS2State *s, int b) -+{ -+ ps2_queue_noirq(s, b); -+ s->update_irq(s->update_arg, 1); -+} -+ -+void ps2_queue_2(PS2State *s, int b1, int b2) -+{ -+ if (PS2_QUEUE_SIZE - s->queue.count < 2) -+ return; -+ -+ ps2_queue_noirq(s, b1); -+ ps2_queue_noirq(s, b2); -+ s->update_irq(s->update_arg, 1); -+} -+ -+void ps2_queue_3(PS2State *s, int b1, int b2, int b3) -+{ -+ if (PS2_QUEUE_SIZE - s->queue.count < 3) -+ return; -+ -+ ps2_queue_noirq(s, b1); -+ ps2_queue_noirq(s, b2); -+ ps2_queue_noirq(s, b3); -+ s->update_irq(s->update_arg, 1); -+} -+ -+void ps2_queue_4(PS2State *s, int b1, int b2, int b3, int b4) -+{ -+ if (PS2_QUEUE_SIZE - s->queue.count < 4) -+ return; -+ -+ ps2_queue_noirq(s, b1); -+ ps2_queue_noirq(s, b2); -+ ps2_queue_noirq(s, b3); -+ ps2_queue_noirq(s, b4); - s->update_irq(s->update_arg, 1); - } - -@@ -499,13 +543,17 @@ void ps2_write_keyboard(void *opaque, int val) - ps2_queue(&s->common, KBD_REPLY_RESEND); - break; - case KBD_CMD_GET_ID: -- ps2_queue(&s->common, KBD_REPLY_ACK); - /* We emulate a MF2 AT keyboard here */ -- ps2_queue(&s->common, KBD_REPLY_ID); - if (s->translate) -- ps2_queue(&s->common, 0x41); -+ ps2_queue_3(&s->common, -+ KBD_REPLY_ACK, -+ KBD_REPLY_ID, -+ 0x41); - else -- ps2_queue(&s->common, 0x83); -+ ps2_queue_3(&s->common, -+ KBD_REPLY_ACK, -+ KBD_REPLY_ID, -+ 0x83); - break; - case KBD_CMD_ECHO: - ps2_queue(&s->common, KBD_CMD_ECHO); -@@ -532,8 +580,9 @@ void ps2_write_keyboard(void *opaque, int val) - break; - case KBD_CMD_RESET: - ps2_reset_keyboard(s); -- ps2_queue(&s->common, KBD_REPLY_ACK); -- ps2_queue(&s->common, KBD_REPLY_POR); -+ ps2_queue_2(&s->common, -+ KBD_REPLY_ACK, -+ KBD_REPLY_POR); - break; - default: - ps2_queue(&s->common, KBD_REPLY_RESEND); -@@ -542,8 +591,11 @@ void ps2_write_keyboard(void *opaque, int val) - break; - case KBD_CMD_SCANCODE: - if (val == 0) { -- ps2_queue(&s->common, KBD_REPLY_ACK); -- ps2_put_keycode(s, s->scancode_set); -+ if (s->common.queue.count <= PS2_QUEUE_SIZE - 2) -+ { -+ ps2_queue(&s->common, KBD_REPLY_ACK); -+ ps2_put_keycode(s, s->scancode_set); -+ } - } else if (val >= 1 && val <= 3) { - s->scancode_set = val; - ps2_queue(&s->common, KBD_REPLY_ACK); -@@ -575,11 +627,15 @@ void ps2_keyboard_set_translation(void *opaque, int mode) - s->translate = mode; - } - --static void ps2_mouse_send_packet(PS2MouseState *s) -+static int ps2_mouse_send_packet(PS2MouseState *s) - { - unsigned int b; - int dx1, dy1, dz1; - -+ const int needed = 3 + (s->mouse_type - 2); -+ if (PS2_QUEUE_SIZE - s->common.queue.count < needed) -+ return 0; -+ - dx1 = s->mouse_dx; - dy1 = s->mouse_dy; - dz1 = s->mouse_dz; -@@ -593,9 +649,9 @@ static void ps2_mouse_send_packet(PS2MouseState *s) - else if (dy1 < -127) - dy1 = -127; - b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); -- ps2_queue(&s->common, b); -- ps2_queue(&s->common, dx1 & 0xff); -- ps2_queue(&s->common, dy1 & 0xff); -+ ps2_queue_noirq(&s->common, b); -+ ps2_queue_noirq(&s->common, dx1 & 0xff); -+ ps2_queue_noirq(&s->common, dy1 & 0xff); - /* extra byte for IMPS/2 or IMEX */ - switch(s->mouse_type) { - default: -@@ -605,7 +661,7 @@ static void ps2_mouse_send_packet(PS2MouseState *s) - dz1 = 127; - else if (dz1 < -127) - dz1 = -127; -- ps2_queue(&s->common, dz1 & 0xff); -+ ps2_queue_noirq(&s->common, dz1 & 0xff); - break; - case 4: - if (dz1 > 7) -@@ -613,15 +669,19 @@ static void ps2_mouse_send_packet(PS2MouseState *s) - else if (dz1 < -7) - dz1 = -7; - b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); -- ps2_queue(&s->common, b); -+ ps2_queue_noirq(&s->common, b); - break; - } - -+ ps2_raise_irq(&s->common); -+ - trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b); - /* update deltas */ - s->mouse_dx -= dx1; - s->mouse_dy -= dy1; - s->mouse_dz -= dz1; -+ -+ return 1; - } - - static void ps2_mouse_event(DeviceState *dev, QemuConsole *src, -@@ -683,10 +743,9 @@ static void ps2_mouse_sync(DeviceState *dev) - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); - } - if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) { -- while (s->common.queue.count < PS2_QUEUE_SIZE - 4) { -- /* if not remote, send event. Multiple events are sent if -- too big deltas */ -- ps2_mouse_send_packet(s); -+ /* if not remote, send event. Multiple events are sent if -+ too big deltas */ -+ while(ps2_mouse_send_packet(s)) { - if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) - break; - } -@@ -745,8 +804,9 @@ void ps2_write_mouse(void *opaque, int val) - ps2_queue(&s->common, AUX_ACK); - break; - case AUX_GET_TYPE: -- ps2_queue(&s->common, AUX_ACK); -- ps2_queue(&s->common, s->mouse_type); -+ ps2_queue_2(&s->common, -+ AUX_ACK, -+ s->mouse_type); - break; - case AUX_SET_RES: - case AUX_SET_SAMPLE: -@@ -754,10 +814,11 @@ void ps2_write_mouse(void *opaque, int val) - ps2_queue(&s->common, AUX_ACK); - break; - case AUX_GET_SCALE: -- ps2_queue(&s->common, AUX_ACK); -- ps2_queue(&s->common, s->mouse_status); -- ps2_queue(&s->common, s->mouse_resolution); -- ps2_queue(&s->common, s->mouse_sample_rate); -+ ps2_queue_4(&s->common, -+ AUX_ACK, -+ s->mouse_status, -+ s->mouse_resolution, -+ s->mouse_sample_rate); - break; - case AUX_POLL: - ps2_queue(&s->common, AUX_ACK); -@@ -783,9 +844,10 @@ void ps2_write_mouse(void *opaque, int val) - s->mouse_status = 0; - s->mouse_type = 0; - ps2_reset_queue(&s->common); -- ps2_queue(&s->common, AUX_ACK); -- ps2_queue(&s->common, 0xaa); -- ps2_queue(&s->common, s->mouse_type); -+ ps2_queue_3(&s->common, -+ AUX_ACK, -+ 0xaa, -+ s->mouse_type); - break; - default: - break; -diff --git a/include/hw/input/ps2.h b/include/hw/input/ps2.h -index 94709b8502..213aa16aa3 100644 ---- a/include/hw/input/ps2.h -+++ b/include/hw/input/ps2.h -@@ -37,7 +37,12 @@ void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg); - void ps2_write_mouse(void *, int val); - void ps2_write_keyboard(void *, int val); - uint32_t ps2_read_data(PS2State *s); -+void ps2_queue_noirq(PS2State *s, int b); -+void ps2_raise_irq(PS2State *s); - void ps2_queue(PS2State *s, int b); -+void ps2_queue_2(PS2State *s, int b1, int b2); -+void ps2_queue_3(PS2State *s, int b1, int b2, int b3); -+void ps2_queue_4(PS2State *s, int b1, int b2, int b3, int b4); - void ps2_keyboard_set_translation(void *opaque, int mode); - void ps2_mouse_fake_event(void *opaque); - --- -2.14.2 |