From 5d360b45dff7ba369c7beadcd9e28f64e2dd5963 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Apr 10 2018 05:13:18 +0000 Subject: import qemu-kvm-1.5.3-156.el7 --- diff --git a/SOURCES/kvm-Avoid-embedding-struct-mbuf-in-other-structures.patch b/SOURCES/kvm-Avoid-embedding-struct-mbuf-in-other-structures.patch new file mode 100644 index 0000000..1d22bf3 --- /dev/null +++ b/SOURCES/kvm-Avoid-embedding-struct-mbuf-in-other-structures.patch @@ -0,0 +1,248 @@ +From fba60972ebac4bd02238c9ecb101b24b1e7a8a51 Mon Sep 17 00:00:00 2001 +From: Xiao Wang +Date: Mon, 27 Nov 2017 07:07:55 +0100 +Subject: [PATCH 4/9] Avoid embedding struct mbuf in other structures + +RH-Author: Xiao Wang +Message-id: <1511766477-29559-3-git-send-email-jasowang@redhat.com> +Patchwork-id: 77900 +O-Subject: [RHEL7.5 qemu-kvm PATCH 2/4] Avoid embedding struct mbuf in other structures +Bugzilla: 1508745 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: wexu@redhat.com +RH-Acked-by: Miroslav Rezanina + +From: Samuel Thibault + +struct mbuf uses a C99 open char array to allow inlining data. Inlining +this in another structure is however a GNU extension. The inlines used +so far in struct Slirp were actually only needed as head of struct +mbuf lists. This replaces these inline with mere struct quehead, +and use casts as appropriate. + +Signed-off-by: Samuel Thibault +Reviewed-by: Peter Maydell +(cherry picked from commit 67e3eee45460129cbc5a90fb9f74eb52594281cd) +Signed-off-by: Miroslav Rezanina +--- + slirp/if.c | 27 ++++++++++++++------------- + slirp/mbuf.c | 19 ++++++++++--------- + slirp/misc.c | 5 ----- + slirp/misc.h | 5 +++++ + slirp/slirp.h | 8 +++++--- + 5 files changed, 34 insertions(+), 30 deletions(-) + +diff --git a/slirp/if.c b/slirp/if.c +index dcd5faf..5e14761 100644 +--- a/slirp/if.c ++++ b/slirp/if.c +@@ -27,9 +27,9 @@ ifs_remque(struct mbuf *ifm) + void + if_init(Slirp *slirp) + { +- slirp->if_fastq.ifq_next = slirp->if_fastq.ifq_prev = &slirp->if_fastq; +- slirp->if_batchq.ifq_next = slirp->if_batchq.ifq_prev = &slirp->if_batchq; +- slirp->next_m = &slirp->if_batchq; ++ slirp->if_fastq.qh_link = slirp->if_fastq.qh_rlink = &slirp->if_fastq; ++ slirp->if_batchq.qh_link = slirp->if_batchq.qh_rlink = &slirp->if_batchq; ++ slirp->next_m = (struct mbuf *) &slirp->if_batchq; + } + + /* +@@ -73,7 +73,8 @@ if_output(struct socket *so, struct mbuf *ifm) + * We mustn't put this packet back on the fastq (or we'll send it out of order) + * XXX add cache here? + */ +- for (ifq = slirp->if_batchq.ifq_prev; ifq != &slirp->if_batchq; ++ for (ifq = (struct mbuf *) slirp->if_batchq.qh_rlink; ++ (struct quehead *) ifq != &slirp->if_batchq; + ifq = ifq->ifq_prev) { + if (so == ifq->ifq_so) { + /* A match! */ +@@ -85,7 +86,7 @@ if_output(struct socket *so, struct mbuf *ifm) + + /* No match, check which queue to put it on */ + if (so && (so->so_iptos & IPTOS_LOWDELAY)) { +- ifq = slirp->if_fastq.ifq_prev; ++ ifq = (struct mbuf *) slirp->if_fastq.qh_rlink; + on_fastq = 1; + /* + * Check if this packet is a part of the last +@@ -97,9 +98,9 @@ if_output(struct socket *so, struct mbuf *ifm) + goto diddit; + } + } else { +- ifq = slirp->if_batchq.ifq_prev; ++ ifq = (struct mbuf *) slirp->if_batchq.qh_rlink; + /* Set next_m if the queue was empty so far */ +- if (slirp->next_m == &slirp->if_batchq) { ++ if ((struct quehead *) slirp->next_m == &slirp->if_batchq) { + slirp->next_m = ifm; + } + } +@@ -165,10 +166,10 @@ void if_start(Slirp *slirp) + } + slirp->if_start_busy = true; + +- if (slirp->if_fastq.ifq_next != &slirp->if_fastq) { +- ifm_next = slirp->if_fastq.ifq_next; ++ if (slirp->if_fastq.qh_link != &slirp->if_fastq) { ++ ifm_next = (struct mbuf *) slirp->if_fastq.qh_link; + next_from_batchq = false; +- } else if (slirp->next_m != &slirp->if_batchq) { ++ } else if ((struct quehead *) slirp->next_m != &slirp->if_batchq) { + /* Nothing on fastq, pick up from batchq via next_m */ + ifm_next = slirp->next_m; + next_from_batchq = true; +@@ -181,12 +182,12 @@ void if_start(Slirp *slirp) + from_batchq = next_from_batchq; + + ifm_next = ifm->ifq_next; +- if (ifm_next == &slirp->if_fastq) { ++ if ((struct quehead *) ifm_next == &slirp->if_fastq) { + /* No more packets in fastq, switch to batchq */ + ifm_next = slirp->next_m; + next_from_batchq = true; + } +- if (ifm_next == &slirp->if_batchq) { ++ if ((struct quehead *) ifm_next == &slirp->if_batchq) { + /* end of batchq */ + ifm_next = NULL; + } +@@ -217,7 +218,7 @@ void if_start(Slirp *slirp) + /* Next packet in fastq is from the same session */ + ifm_next = next; + next_from_batchq = false; +- } else if (slirp->next_m == &slirp->if_batchq) { ++ } else if ((struct quehead *) slirp->next_m == &slirp->if_batchq) { + /* Set next_m and ifm_next if the session packet is now the + * only one on batchq */ + slirp->next_m = ifm_next = next; +diff --git a/slirp/mbuf.c b/slirp/mbuf.c +index 4fefb04..5565fd1 100644 +--- a/slirp/mbuf.c ++++ b/slirp/mbuf.c +@@ -28,16 +28,16 @@ + void + m_init(Slirp *slirp) + { +- slirp->m_freelist.m_next = slirp->m_freelist.m_prev = &slirp->m_freelist; +- slirp->m_usedlist.m_next = slirp->m_usedlist.m_prev = &slirp->m_usedlist; ++ slirp->m_freelist.qh_link = slirp->m_freelist.qh_rlink = &slirp->m_freelist; ++ slirp->m_usedlist.qh_link = slirp->m_usedlist.qh_rlink = &slirp->m_usedlist; + } + + void m_cleanup(Slirp *slirp) + { + struct mbuf *m, *next; + +- m = slirp->m_usedlist.m_next; +- while (m != &slirp->m_usedlist) { ++ m = (struct mbuf *) slirp->m_usedlist.qh_link; ++ while ((struct quehead *) m != &slirp->m_usedlist) { + next = m->m_next; + if (m->m_flags & M_EXT) { + free(m->m_ext); +@@ -45,8 +45,8 @@ void m_cleanup(Slirp *slirp) + free(m); + m = next; + } +- m = slirp->m_freelist.m_next; +- while (m != &slirp->m_freelist) { ++ m = (struct mbuf *) slirp->m_freelist.qh_link; ++ while ((struct quehead *) m != &slirp->m_freelist) { + next = m->m_next; + free(m); + m = next; +@@ -69,7 +69,7 @@ m_get(Slirp *slirp) + + DEBUG_CALL("m_get"); + +- if (slirp->m_freelist.m_next == &slirp->m_freelist) { ++ if (slirp->m_freelist.qh_link == &slirp->m_freelist) { + m = (struct mbuf *)malloc(SLIRP_MSIZE); + if (m == NULL) goto end_error; + slirp->mbuf_alloced++; +@@ -77,7 +77,7 @@ m_get(Slirp *slirp) + flags = M_DOFREE; + m->slirp = slirp; + } else { +- m = slirp->m_freelist.m_next; ++ m = (struct mbuf *) slirp->m_freelist.qh_link; + remque(m); + } + +@@ -224,7 +224,8 @@ dtom(Slirp *slirp, void *dat) + DEBUG_ARG("dat = %lx", (long )dat); + + /* bug corrected for M_EXT buffers */ +- for (m = slirp->m_usedlist.m_next; m != &slirp->m_usedlist; ++ for (m = (struct mbuf *) slirp->m_usedlist.qh_link; ++ (struct quehead *) m != &slirp->m_usedlist; + m = m->m_next) { + if (m->m_flags & M_EXT) { + if( (char *)dat>=m->m_ext && (char *)dat<(m->m_ext + m->m_size) ) +diff --git a/slirp/misc.c b/slirp/misc.c +index 8ecced5..d353d08 100644 +--- a/slirp/misc.c ++++ b/slirp/misc.c +@@ -14,11 +14,6 @@ + int slirp_debug = DBG_CALL|DBG_MISC|DBG_ERROR; + #endif + +-struct quehead { +- struct quehead *qh_link; +- struct quehead *qh_rlink; +-}; +- + inline void + insque(void *a, void *b) + { +diff --git a/slirp/misc.h b/slirp/misc.h +index ba8beb1..eb451c4 100644 +--- a/slirp/misc.h ++++ b/slirp/misc.h +@@ -49,6 +49,11 @@ struct emu_t { + struct emu_t *next; + }; + ++struct slirp_quehead { ++ struct slirp_quehead *qh_link; ++ struct slirp_quehead *qh_rlink; ++}; ++ + void slirp_insque(void *, void *); + void slirp_remque(void *); + int add_exec(struct ex_list **, int, char *, struct in_addr, int); +diff --git a/slirp/slirp.h b/slirp/slirp.h +index fe0e65d..d050ede 100644 +--- a/slirp/slirp.h ++++ b/slirp/slirp.h +@@ -126,6 +126,7 @@ void free(void *ptr); + have different prototypes. */ + #define insque slirp_insque + #define remque slirp_remque ++#define quehead slirp_quehead + + #ifdef HAVE_SYS_STROPTS_H + #include +@@ -218,12 +219,13 @@ struct Slirp { + struct ex_list *exec_list; + + /* mbuf states */ +- struct mbuf m_freelist, m_usedlist; ++ struct quehead m_freelist; ++ struct quehead m_usedlist; + int mbuf_alloced; + + /* if states */ +- struct mbuf if_fastq; /* fast queue (for interactive data) */ +- struct mbuf if_batchq; /* queue for non-interactive data */ ++ struct quehead if_fastq; /* fast queue (for interactive data) */ ++ struct quehead if_batchq; /* queue for non-interactive data */ + struct mbuf *next_m; /* pointer to next mbuf to output */ + bool if_start_busy; /* avoid if_start recursion */ + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-DumpState-adding-total_size-and-written_size-fields.patch b/SOURCES/kvm-DumpState-adding-total_size-and-written_size-fields.patch new file mode 100644 index 0000000..cc00535 --- /dev/null +++ b/SOURCES/kvm-DumpState-adding-total_size-and-written_size-fields.patch @@ -0,0 +1,131 @@ +From 60e8f031af3ca219ac6344c6028fe009eddf8c19 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:59 +0100 +Subject: [PATCH 28/41] DumpState: adding total_size and written_size fields +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-29-marcandre.lureau@redhat.com> +Patchwork-id: 78382 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 28/41] DumpState: adding total_size and written_size fields +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: Peter Xu + +Here, total_size is the size in bytes to be dumped (raw data, which +means before compression), while written_size are bytes handled (raw +size too). + +Signed-off-by: Peter Xu +Message-Id: <1455772616-8668-9-git-send-email-peterx@redhat.com> +Signed-off-by: Paolo Bonzini + +(cherry picked from commit 2264c2c96e0a1f0913412da73e9bcaf9f8fa4427) + +RHEL: minor conflict due to "detach" mode not being backported. + +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + dump.c | 32 ++++++++++++++++++++++++++++++++ + include/sysemu/dump.h | 8 ++++++++ + 2 files changed, 40 insertions(+) + +diff --git a/dump.c b/dump.c +index 8618230..008a722 100644 +--- a/dump.c ++++ b/dump.c +@@ -336,6 +336,8 @@ static void write_data(DumpState *s, void *buf, int length, Error **errp) + ret = fd_write_vmcore(buf, length, s); + if (ret < 0) { + error_setg(errp, "dump: failed to save memory"); ++ } else { ++ s->written_size += length; + } + } + +@@ -1329,6 +1331,7 @@ static void write_dump_pages(DumpState *s, Error **errp) + goto out; + } + } ++ s->written_size += s->dump_info.page_size; + } + + ret = write_cache(&page_desc, NULL, 0, true); +@@ -1461,6 +1464,30 @@ bool dump_in_progress(void) + return (state->status == DUMP_STATUS_ACTIVE); + } + ++/* calculate total size of memory to be dumped (taking filter into ++ * acoount.) */ ++static int64_t dump_calculate_size(DumpState *s) ++{ ++ GuestPhysBlock *block; ++ int64_t size = 0, total = 0, left = 0, right = 0; ++ ++ QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) { ++ if (s->has_filter) { ++ /* calculate the overlapped region. */ ++ left = MAX(s->begin, block->target_start); ++ right = MIN(s->begin + s->length, block->target_end); ++ size = right - left; ++ size = size > 0 ? size : 0; ++ } else { ++ /* count the whole region in */ ++ size = (block->target_end - block->target_start); ++ } ++ total += size; ++ } ++ ++ return total; ++} ++ + static void dump_init(DumpState *s, int fd, bool has_format, + DumpGuestMemoryFormat format, bool paging, bool has_filter, + int64_t begin, int64_t length, Error **errp) +@@ -1472,6 +1499,7 @@ static void dump_init(DumpState *s, int fd, bool has_format, + + s->has_format = has_format; + s->format = format; ++ s->written_size = 0; + + /* kdump-compressed is conflict with paging and filter */ + if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) { +@@ -1503,6 +1531,10 @@ static void dump_init(DumpState *s, int fd, bool has_format, + + guest_phys_blocks_init(&s->guest_phys_blocks); + guest_phys_blocks_append(&s->guest_phys_blocks); ++ s->total_size = dump_calculate_size(s); ++#ifdef DEBUG_DUMP_GUEST_MEMORY ++ fprintf(stderr, "DUMP: total memory to dump: %lu\n", s->total_size); ++#endif + + s->start = get_start_block(s); + if (s->start == -1) { +diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h +index 1da3ddb..b5ebb0a 100644 +--- a/include/sysemu/dump.h ++++ b/include/sysemu/dump.h +@@ -181,6 +181,14 @@ typedef struct DumpState { + + bool has_format; /* whether format is provided */ + DumpGuestMemoryFormat format; /* valid only if has_format == true */ ++ int64_t total_size; /* total memory size (in bytes) to ++ * be dumped. When filter is ++ * enabled, this will only count ++ * those to be written. */ ++ int64_t written_size; /* written memory size (in bytes), ++ * this could be used to calculate ++ * how much work we have ++ * finished. */ + } DumpState; + + uint16_t cpu_to_dump16(DumpState *s, uint16_t val); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Enable-fw_cfg-DMA-interface-for-x86.patch b/SOURCES/kvm-Enable-fw_cfg-DMA-interface-for-x86.patch new file mode 100644 index 0000000..6c33e65 --- /dev/null +++ b/SOURCES/kvm-Enable-fw_cfg-DMA-interface-for-x86.patch @@ -0,0 +1,68 @@ +From f7572e4bdfc5c0c57d6a37712c6f5b79cc86e063 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:39 +0100 +Subject: [PATCH 08/41] Enable fw_cfg DMA interface for x86 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-9-marcandre.lureau@redhat.com> +Patchwork-id: 78357 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 08/41] Enable fw_cfg DMA interface for x86 +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: Marc Marí + +Enable the fw_cfg DMA interface for all the x86 platforms. + +Based on Gerd Hoffman's initial implementation. + +Signed-off-by: Marc Marí +Reviewed-by: Laszlo Ersek +Signed-off-by: Gerd Hoffmann + +(cherry picked from commit c886fc4c20ff8456b2f788a1404dd321b8b59243) +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + hw/i386/pc.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/hw/i386/pc.c b/hw/i386/pc.c +index 29d6588..e2fd732 100644 +--- a/hw/i386/pc.c ++++ b/hw/i386/pc.c +@@ -600,7 +600,7 @@ static unsigned int pc_apic_id_limit(unsigned int max_cpus) + return x86_cpu_apic_id_from_index(max_cpus - 1) + 1; + } + +-static FWCfgState *bochs_bios_init(void) ++static FWCfgState *bochs_bios_init(AddressSpace *as) + { + FWCfgState *fw_cfg; + uint8_t *smbios_table; +@@ -609,7 +609,7 @@ static FWCfgState *bochs_bios_init(void) + int i, j; + unsigned int apic_id_limit = pc_apic_id_limit(max_cpus); + +- fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0); ++ fw_cfg = fw_cfg_init_io_dma(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 4, as); + /* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86: + * + * SeaBIOS needs FW_CFG_MAX_CPUS for CPU hotplug, but the CPU hotplug +@@ -1172,7 +1172,7 @@ FWCfgState *pc_memory_init(MemoryRegion *system_memory, + option_rom_mr, + 1); + +- fw_cfg = bochs_bios_init(); ++ fw_cfg = bochs_bios_init(&address_space_memory); + rom_set_fw(fw_cfg); + + if (linux_boot) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Fix-typo-in-variable-name-found-and-fixed-by-codespe.patch b/SOURCES/kvm-Fix-typo-in-variable-name-found-and-fixed-by-codespe.patch new file mode 100644 index 0000000..59de7a3 --- /dev/null +++ b/SOURCES/kvm-Fix-typo-in-variable-name-found-and-fixed-by-codespe.patch @@ -0,0 +1,203 @@ +From aabe8208c6a3989910d5ab210eba9b7938bdf526 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:39:09 +0100 +Subject: [PATCH 38/41] Fix typo in variable name (found and fixed by + codespell) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-39-marcandre.lureau@redhat.com> +Patchwork-id: 78388 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 38/41] Fix typo in variable name (found and fixed by codespell) +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: Stefan Weil + +Signed-off-by: Stefan Weil +Reviewed-by: Fam Zheng +Signed-off-by: Michael Tokarev + +(cherry picked from commit 1d817db3a07774999606f62aa2d8772a82363551) + +RHEL: backported to avoid conflicts in following patch + +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + scripts/dump-guest-memory.py | 64 ++++++++++++++++++++++---------------------- + 1 file changed, 32 insertions(+), 32 deletions(-) + +diff --git a/scripts/dump-guest-memory.py b/scripts/dump-guest-memory.py +index 308cfca..03d692d 100644 +--- a/scripts/dump-guest-memory.py ++++ b/scripts/dump-guest-memory.py +@@ -56,44 +56,44 @@ class ELF(object): + self.notes = [] + self.segments = [] + self.notes_size = 0 +- self.endianess = None ++ self.endianness = None + self.elfclass = ELFCLASS64 + + if arch == 'aarch64-le': +- self.endianess = ELFDATA2LSB ++ self.endianness = ELFDATA2LSB + self.elfclass = ELFCLASS64 +- self.ehdr = get_arch_ehdr(self.endianess, self.elfclass) ++ self.ehdr = get_arch_ehdr(self.endianness, self.elfclass) + self.ehdr.e_machine = EM_AARCH + + elif arch == 'aarch64-be': +- self.endianess = ELFDATA2MSB +- self.ehdr = get_arch_ehdr(self.endianess, self.elfclass) ++ self.endianness = ELFDATA2MSB ++ self.ehdr = get_arch_ehdr(self.endianness, self.elfclass) + self.ehdr.e_machine = EM_AARCH + + elif arch == 'X86_64': +- self.endianess = ELFDATA2LSB +- self.ehdr = get_arch_ehdr(self.endianess, self.elfclass) ++ self.endianness = ELFDATA2LSB ++ self.ehdr = get_arch_ehdr(self.endianness, self.elfclass) + self.ehdr.e_machine = EM_X86_64 + + elif arch == '386': +- self.endianess = ELFDATA2LSB ++ self.endianness = ELFDATA2LSB + self.elfclass = ELFCLASS32 +- self.ehdr = get_arch_ehdr(self.endianess, self.elfclass) ++ self.ehdr = get_arch_ehdr(self.endianness, self.elfclass) + self.ehdr.e_machine = EM_386 + + elif arch == 's390': +- self.endianess = ELFDATA2MSB +- self.ehdr = get_arch_ehdr(self.endianess, self.elfclass) ++ self.endianness = ELFDATA2MSB ++ self.ehdr = get_arch_ehdr(self.endianness, self.elfclass) + self.ehdr.e_machine = EM_S390 + + elif arch == 'ppc64-le': +- self.endianess = ELFDATA2LSB +- self.ehdr = get_arch_ehdr(self.endianess, self.elfclass) ++ self.endianness = ELFDATA2LSB ++ self.ehdr = get_arch_ehdr(self.endianness, self.elfclass) + self.ehdr.e_machine = EM_PPC64 + + elif arch == 'ppc64-be': +- self.endianess = ELFDATA2MSB +- self.ehdr = get_arch_ehdr(self.endianess, self.elfclass) ++ self.endianness = ELFDATA2MSB ++ self.ehdr = get_arch_ehdr(self.endianness, self.elfclass) + self.ehdr.e_machine = EM_PPC64 + + else: +@@ -107,7 +107,7 @@ class ELF(object): + def add_note(self, n_name, n_desc, n_type): + """Adds a note to the ELF.""" + +- note = get_arch_note(self.endianess, len(n_name), len(n_desc)) ++ note = get_arch_note(self.endianness, len(n_name), len(n_desc)) + note.n_namesz = len(n_name) + 1 + note.n_descsz = len(n_desc) + note.n_name = n_name.encode() +@@ -126,7 +126,7 @@ class ELF(object): + def add_segment(self, p_type, p_paddr, p_size): + """Adds a segment to the elf.""" + +- phdr = get_arch_phdr(self.endianess, self.elfclass) ++ phdr = get_arch_phdr(self.endianness, self.elfclass) + phdr.p_type = p_type + phdr.p_paddr = p_paddr + phdr.p_filesz = p_size +@@ -158,10 +158,10 @@ class ELF(object): + elf_file.write(note) + + +-def get_arch_note(endianess, len_name, len_desc): +- """Returns a Note class with the specified endianess.""" ++def get_arch_note(endianness, len_name, len_desc): ++ """Returns a Note class with the specified endianness.""" + +- if endianess == ELFDATA2LSB: ++ if endianness == ELFDATA2LSB: + superclass = ctypes.LittleEndianStructure + else: + superclass = ctypes.BigEndianStructure +@@ -193,20 +193,20 @@ class Ident(ctypes.Structure): + ('ei_abiversion', ctypes.c_ubyte), + ('ei_pad', ctypes.c_ubyte * 7)] + +- def __init__(self, endianess, elfclass): ++ def __init__(self, endianness, elfclass): + self.ei_mag0 = 0x7F + self.ei_mag1 = ord('E') + self.ei_mag2 = ord('L') + self.ei_mag3 = ord('F') + self.ei_class = elfclass +- self.ei_data = endianess ++ self.ei_data = endianness + self.ei_version = EV_CURRENT + + +-def get_arch_ehdr(endianess, elfclass): +- """Returns a EHDR64 class with the specified endianess.""" ++def get_arch_ehdr(endianness, elfclass): ++ """Returns a EHDR64 class with the specified endianness.""" + +- if endianess == ELFDATA2LSB: ++ if endianness == ELFDATA2LSB: + superclass = ctypes.LittleEndianStructure + else: + superclass = ctypes.BigEndianStructure +@@ -231,12 +231,12 @@ def get_arch_ehdr(endianess, elfclass): + + def __init__(self): + super(superclass, self).__init__() +- self.e_ident = Ident(endianess, elfclass) ++ self.e_ident = Ident(endianness, elfclass) + self.e_type = ET_CORE + self.e_version = EV_CURRENT + self.e_ehsize = ctypes.sizeof(self) + self.e_phoff = ctypes.sizeof(self) +- self.e_phentsize = ctypes.sizeof(get_arch_phdr(endianess, elfclass)) ++ self.e_phentsize = ctypes.sizeof(get_arch_phdr(endianness, elfclass)) + self.e_phnum = 0 + + +@@ -260,12 +260,12 @@ def get_arch_ehdr(endianess, elfclass): + + def __init__(self): + super(superclass, self).__init__() +- self.e_ident = Ident(endianess, elfclass) ++ self.e_ident = Ident(endianness, elfclass) + self.e_type = ET_CORE + self.e_version = EV_CURRENT + self.e_ehsize = ctypes.sizeof(self) + self.e_phoff = ctypes.sizeof(self) +- self.e_phentsize = ctypes.sizeof(get_arch_phdr(endianess, elfclass)) ++ self.e_phentsize = ctypes.sizeof(get_arch_phdr(endianness, elfclass)) + self.e_phnum = 0 + + # End get_arch_ehdr +@@ -275,10 +275,10 @@ def get_arch_ehdr(endianess, elfclass): + return EHDR32() + + +-def get_arch_phdr(endianess, elfclass): +- """Returns a 32 or 64 bit PHDR class with the specified endianess.""" ++def get_arch_phdr(endianness, elfclass): ++ """Returns a 32 or 64 bit PHDR class with the specified endianness.""" + +- if endianess == ELFDATA2LSB: ++ if endianness == ELFDATA2LSB: + superclass = ctypes.LittleEndianStructure + else: + superclass = ctypes.BigEndianStructure +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Implement-fw_cfg-DMA-interface.patch b/SOURCES/kvm-Implement-fw_cfg-DMA-interface.patch new file mode 100644 index 0000000..c32d06f --- /dev/null +++ b/SOURCES/kvm-Implement-fw_cfg-DMA-interface.patch @@ -0,0 +1,437 @@ +From 96c218d6936795b087ceb493413221d5058118bc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:36 +0100 +Subject: [PATCH 05/41] Implement fw_cfg DMA interface +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-6-marcandre.lureau@redhat.com> +Patchwork-id: 78358 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 05/41] Implement fw_cfg DMA interface +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: Marc Marí + +Based on the specifications on docs/specs/fw_cfg.txt + +This interface is an addon. The old interface can still be used as usual. + +Based on Gerd Hoffman's initial implementation. + +Signed-off-by: Marc Marí +Reviewed-by: Laszlo Ersek +Signed-off-by: Gerd Hoffmann + +(cherry picked from commit a4c0d1deb785611c96a455f65ec032976b00b36f) + +RHEL: major rewrite due to lack of seperation between the MMIO & IO + introduced in upstream commit + 5712db6ae5101db645f71edc393368cd59bfd314 and following commits. + +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + hw/nvram/fw_cfg.c | 223 ++++++++++++++++++++++++++++++++++++++++++++-- + include/hw/nvram/fw_cfg.h | 12 +++ + tests/fw_cfg-test.c | 3 +- + 3 files changed, 230 insertions(+), 8 deletions(-) + +diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c +index 01d4566..85e950c 100644 +--- a/hw/nvram/fw_cfg.c ++++ b/hw/nvram/fw_cfg.c +@@ -23,6 +23,7 @@ + */ + #include "hw/hw.h" + #include "sysemu/sysemu.h" ++#include "sysemu/dma.h" + #include "hw/isa/isa.h" + #include "hw/nvram/fw_cfg.h" + #include "hw/sysbus.h" +@@ -30,12 +31,22 @@ + #include "qemu/error-report.h" + #include "qemu/config-file.h" + +-#define FW_CFG_SIZE 2 ++#define FW_CFG_CTL_SIZE 2 + #define FW_CFG_DATA_SIZE 1 + #define TYPE_FW_CFG "fw_cfg" + #define FW_CFG_NAME "fw_cfg" + #define FW_CFG_PATH "/machine/" FW_CFG_NAME + ++/* FW_CFG_VERSION bits */ ++#define FW_CFG_VERSION 0x01 ++#define FW_CFG_VERSION_DMA 0x02 ++ ++/* FW_CFG_DMA_CONTROL bits */ ++#define FW_CFG_DMA_CTL_ERROR 0x01 ++#define FW_CFG_DMA_CTL_READ 0x02 ++#define FW_CFG_DMA_CTL_SKIP 0x04 ++#define FW_CFG_DMA_CTL_SELECT 0x08 ++ + typedef struct FWCfgEntry { + uint32_t len; + uint8_t *data; +@@ -46,12 +57,17 @@ typedef struct FWCfgEntry { + struct FWCfgState { + SysBusDevice busdev; + MemoryRegion ctl_iomem, data_iomem, comb_iomem; +- uint32_t ctl_iobase, data_iobase; ++ uint32_t ctl_iobase, data_iobase, dma_iobase; + FWCfgEntry entries[2][FW_CFG_MAX_ENTRY]; + FWCfgFiles *files; + uint16_t cur_entry; + uint32_t cur_offset; + Notifier machine_ready; ++ ++ bool dma_enabled; ++ dma_addr_t dma_addr; ++ DMAContext *dma; ++ MemoryRegion dma_iomem; + }; + + #define JPG_FILE 0 +@@ -257,6 +273,124 @@ static void fw_cfg_data_mem_write(void *opaque, hwaddr addr, + fw_cfg_write(opaque, (uint8_t)value); + } + ++static void fw_cfg_dma_transfer(FWCfgState *s) ++{ ++ dma_addr_t len; ++ FWCfgDmaAccess dma; ++ int arch; ++ FWCfgEntry *e; ++ int read; ++ dma_addr_t dma_addr; ++ ++ /* Reset the address before the next access */ ++ dma_addr = s->dma_addr; ++ s->dma_addr = 0; ++ ++ if (dma_memory_read(s->dma, dma_addr, &dma, sizeof(dma))) { ++ stl_be_dma(s->dma, dma_addr + offsetof(FWCfgDmaAccess, control), ++ FW_CFG_DMA_CTL_ERROR); ++ return; ++ } ++ ++ dma.address = be64_to_cpu(dma.address); ++ dma.length = be32_to_cpu(dma.length); ++ dma.control = be32_to_cpu(dma.control); ++ ++ if (dma.control & FW_CFG_DMA_CTL_SELECT) { ++ fw_cfg_select(s, dma.control >> 16); ++ } ++ ++ arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL); ++ e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK]; ++ ++ if (dma.control & FW_CFG_DMA_CTL_READ) { ++ read = 1; ++ } else if (dma.control & FW_CFG_DMA_CTL_SKIP) { ++ read = 0; ++ } else { ++ dma.length = 0; ++ } ++ ++ dma.control = 0; ++ ++ while (dma.length > 0 && !(dma.control & FW_CFG_DMA_CTL_ERROR)) { ++ if (s->cur_entry == FW_CFG_INVALID || !e->data || ++ s->cur_offset >= e->len) { ++ len = dma.length; ++ ++ /* If the access is not a read access, it will be a skip access, ++ * tested before. ++ */ ++ if (read) { ++ if (dma_memory_set(s->dma, dma.address, 0, len)) { ++ dma.control |= FW_CFG_DMA_CTL_ERROR; ++ } ++ } ++ ++ } else { ++ if (dma.length <= (e->len - s->cur_offset)) { ++ len = dma.length; ++ } else { ++ len = (e->len - s->cur_offset); ++ } ++ ++ if (e->read_callback) { ++ e->read_callback(e->callback_opaque, s->cur_offset); ++ } ++ ++ /* If the access is not a read access, it will be a skip access, ++ * tested before. ++ */ ++ if (read) { ++ if (dma_memory_write(s->dma, dma.address, ++ &e->data[s->cur_offset], len)) { ++ dma.control |= FW_CFG_DMA_CTL_ERROR; ++ } ++ } ++ ++ s->cur_offset += len; ++ } ++ ++ dma.address += len; ++ dma.length -= len; ++ ++ } ++ ++ stl_be_dma(s->dma, dma_addr + offsetof(FWCfgDmaAccess, control), ++ dma.control); ++ ++ trace_fw_cfg_read(s, 0); ++} ++ ++static void fw_cfg_dma_mem_write(void *opaque, hwaddr addr, ++ uint64_t value, unsigned size) ++{ ++ FWCfgState *s = opaque; ++ ++ if (size == 4) { ++ value = be32_to_cpu(value); ++ if (addr == 0) { ++ /* FWCfgDmaAccess high address */ ++ s->dma_addr = value << 32; ++ } else if (addr == 4) { ++ /* FWCfgDmaAccess low address */ ++ s->dma_addr |= value; ++ fw_cfg_dma_transfer(s); ++ } ++ } else if (size == 8 && addr == 0) { ++ value = be64_to_cpu(value); ++ s->dma_addr = value; ++ fw_cfg_dma_transfer(s); ++ } ++} ++ ++static bool fw_cfg_dma_mem_valid(void *opaque, hwaddr addr, ++ unsigned size, bool is_write) ++{ ++ return is_write && ((size == 4 && (addr == 0 || addr == 4)) || ++ (size == 8 && addr == 0)); ++} ++ + static void fw_cfg_ctl_mem_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) + { +@@ -317,6 +451,14 @@ static const MemoryRegionOps fw_cfg_comb_mem_ops = { + .valid.accepts = fw_cfg_comb_valid, + }; + ++static const MemoryRegionOps fw_cfg_dma_mem_ops = { ++ .write = fw_cfg_dma_mem_write, ++ .endianness = DEVICE_NATIVE_ENDIAN, ++ .valid.accepts = fw_cfg_dma_mem_valid, ++ .valid.max_access_size = 8, ++ .impl.max_access_size = 8, ++}; ++ + static void fw_cfg_reset(DeviceState *d) + { + FWCfgState *s = DO_UPCAST(FWCfgState, busdev.qdev, d); +@@ -357,6 +499,21 @@ static bool is_version_1(void *opaque, int version_id) + return version_id == 1; + } + ++static bool fw_cfg_dma_enabled(void *opaque) ++{ ++ FWCfgState *s = opaque; ++ ++ return s->dma_enabled; ++} ++ ++static const VMStateDescription vmstate_fw_cfg_dma = { ++ .name = "fw_cfg/dma", ++ .fields = (VMStateField[]) { ++ VMSTATE_UINT64(dma_addr, FWCfgState), ++ VMSTATE_END_OF_LIST() ++ }, ++}; ++ + static const VMStateDescription vmstate_fw_cfg = { + .name = "fw_cfg", + .version_id = 2, +@@ -367,6 +524,14 @@ static const VMStateDescription vmstate_fw_cfg = { + VMSTATE_UINT16_HACK(cur_offset, FWCfgState, is_version_1), + VMSTATE_UINT32_V(cur_offset, FWCfgState, 2), + VMSTATE_END_OF_LIST() ++ }, ++ .subsections = (const VMStateSubsection[]) { ++ { ++ .vmsd = &vmstate_fw_cfg_dma, ++ .needed = fw_cfg_dma_enabled, ++ }, { ++ /* empty */ ++ } + } + }; + +@@ -478,16 +643,24 @@ static void fw_cfg_machine_ready(struct Notifier *n, void *data) + fw_cfg_add_file(s, "bootorder", (uint8_t*)bootindex, len); + } + +-FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port, +- hwaddr ctl_addr, hwaddr data_addr) ++static FWCfgState * ++fw_cfg_init_dma(uint32_t ctl_port, uint32_t data_port, ++ uint32_t dma_port, ++ hwaddr ctl_addr, hwaddr data_addr, hwaddr dma_addr, ++ AddressSpace *dma_as) + { + DeviceState *dev; + SysBusDevice *d; + FWCfgState *s; ++ uint32_t version = FW_CFG_VERSION; ++ bool dma_enabled = dma_port && dma_as; + + dev = qdev_create(NULL, "fw_cfg"); + qdev_prop_set_uint32(dev, "ctl_iobase", ctl_port); + qdev_prop_set_uint32(dev, "data_iobase", data_port); ++ qdev_prop_set_uint32(dev, "dma_iobase", dma_port); ++ qdev_prop_set_bit(dev, "dma_enabled", dma_enabled); ++ + d = SYS_BUS_DEVICE(dev); + + s = DO_UPCAST(FWCfgState, busdev.qdev, dev); +@@ -505,8 +678,19 @@ FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port, + if (data_addr) { + sysbus_mmio_map(d, 1, data_addr); + } ++ if (dma_enabled) { ++ /* 64 bits for the address field */ ++ s->dma = &dma_context_memory; ++ s->dma_addr = 0; ++ ++ version |= FW_CFG_VERSION_DMA; ++ if (dma_addr) { ++ sysbus_mmio_map(d, 2, dma_addr); ++ } ++ } ++ + fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4); +- fw_cfg_add_i32(s, FW_CFG_ID, 1); ++ fw_cfg_add_i32(s, FW_CFG_ID, version); + fw_cfg_add_bytes(s, FW_CFG_UUID, qemu_uuid, 16); + fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)(display_type == DT_NOGRAPHIC)); + fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus); +@@ -520,19 +704,37 @@ FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port, + return s; + } + ++FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port, ++ hwaddr ctl_addr, hwaddr data_addr) ++{ ++ return fw_cfg_init_dma(ctl_port, data_addr, 0, ctl_addr, data_addr, 0, NULL); ++} ++ ++FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase, ++ AddressSpace *dma_as) ++{ ++ return fw_cfg_init_dma(iobase, iobase + 1, dma_iobase, 0, 0, 0, dma_as); ++} ++ + static int fw_cfg_init1(SysBusDevice *dev) + { + FWCfgState *s = FROM_SYSBUS(FWCfgState, dev); + + memory_region_init_io(&s->ctl_iomem, &fw_cfg_ctl_mem_ops, s, +- "fwcfg.ctl", FW_CFG_SIZE); ++ "fwcfg.ctl", FW_CFG_CTL_SIZE); + sysbus_init_mmio(dev, &s->ctl_iomem); + memory_region_init_io(&s->data_iomem, &fw_cfg_data_mem_ops, s, + "fwcfg.data", FW_CFG_DATA_SIZE); + sysbus_init_mmio(dev, &s->data_iomem); + /* In case ctl and data overlap: */ + memory_region_init_io(&s->comb_iomem, &fw_cfg_comb_mem_ops, s, +- "fwcfg", FW_CFG_SIZE); ++ "fwcfg", FW_CFG_CTL_SIZE); ++ ++ if (s->dma_enabled) { ++ memory_region_init_io(&s->dma_iomem, &fw_cfg_dma_mem_ops, s, ++ "fwcfg.dma", sizeof(dma_addr_t)); ++ sysbus_init_mmio(dev, &s->dma_iomem); ++ } + + if (s->ctl_iobase + 1 == s->data_iobase) { + sysbus_add_io(dev, s->ctl_iobase, &s->comb_iomem); +@@ -544,12 +746,19 @@ static int fw_cfg_init1(SysBusDevice *dev) + sysbus_add_io(dev, s->data_iobase, &s->data_iomem); + } + } ++ ++ if (s->dma_iobase) { ++ sysbus_add_io(dev, s->dma_iobase, &s->dma_iomem); ++ } ++ + return 0; + } + + static Property fw_cfg_properties[] = { + DEFINE_PROP_HEX32("ctl_iobase", FWCfgState, ctl_iobase, -1), + DEFINE_PROP_HEX32("data_iobase", FWCfgState, data_iobase, -1), ++ DEFINE_PROP_HEX32("dma_iobase", FWCfgState, dma_iobase, -1), ++ DEFINE_PROP_BOOL("dma_enabled", FWCfgState, dma_enabled, false), + DEFINE_PROP_END_OF_LIST(), + }; + +diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h +index aa5f351..b193e38 100644 +--- a/include/hw/nvram/fw_cfg.h ++++ b/include/hw/nvram/fw_cfg.h +@@ -7,6 +7,7 @@ + + #include "exec/hwaddr.h" + #include "qemu/typedefs.h" ++#include "qemu/compiler.h" + #endif + + #define FW_CFG_SIGNATURE 0x00 +@@ -61,6 +62,15 @@ typedef struct FWCfgFiles { + FWCfgFile f[]; + } FWCfgFiles; + ++/* Control as first field allows for different structures selected by this ++ * field, which might be useful in the future ++ */ ++typedef struct FWCfgDmaAccess { ++ uint32_t control; ++ uint32_t length; ++ uint64_t address; ++} QEMU_PACKED FWCfgDmaAccess; ++ + typedef void (*FWCfgCallback)(void *opaque, uint8_t *data); + typedef void (*FWCfgReadCallback)(void *opaque, uint32_t offset); + +@@ -76,6 +86,8 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, + void *data, size_t len); + FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port, + hwaddr crl_addr, hwaddr data_addr); ++FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase, ++ AddressSpace *dma_as); + + FWCfgState *fw_cfg_find(void); + +diff --git a/tests/fw_cfg-test.c b/tests/fw_cfg-test.c +index 3428dca..24b8a28 100644 +--- a/tests/fw_cfg-test.c ++++ b/tests/fw_cfg-test.c +@@ -38,7 +38,8 @@ static void test_fw_cfg_signature(void) + + static void test_fw_cfg_id(void) + { +- g_assert_cmpint(qfw_cfg_get_u32(fw_cfg, FW_CFG_ID), ==, 1); ++ uint32_t id = qfw_cfg_get_u32(fw_cfg, FW_CFG_ID); ++ g_assert((id == 1) || (id == 3)); + } + + static void test_fw_cfg_uuid(void) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Workaround-rhel6-ctrl_guest_offloads-machine-type-mi.patch b/SOURCES/kvm-Workaround-rhel6-ctrl_guest_offloads-machine-type-mi.patch index 241c8a3..6475561 100644 --- a/SOURCES/kvm-Workaround-rhel6-ctrl_guest_offloads-machine-type-mi.patch +++ b/SOURCES/kvm-Workaround-rhel6-ctrl_guest_offloads-machine-type-mi.patch @@ -1,14 +1,14 @@ -From fa7ee2210a7da964b111b8d8e7a2639ad6219041 Mon Sep 17 00:00:00 2001 +From aa757665c90914e69db3f16b11753c6d936b9bf0 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 17 Aug 2017 09:45:36 +0200 -Subject: [PATCH 2/2] Workaround rhel6 ctrl_guest_offloads machine type +Subject: [PATCH 3/4] Workaround rhel6 ctrl_guest_offloads machine type mismatch RH-Author: Dr. David Alan Gilbert Message-id: <20170817094536.12740-3-dgilbert@redhat.com> Patchwork-id: 76022 O-Subject: [RHEL-7.5/7.4.z/7.3.z/7.2.z qemu-kvm PATCH v2 2/2] Workaround rhel6 ctrl_guest_offloads machine type mismatch -Bugzilla: 1482468 +Bugzilla: 1480428 RH-Acked-by: Eduardo Habkost RH-Acked-by: Michael S. Tsirkin RH-Acked-by: Thomas Huth diff --git a/SOURCES/kvm-block-Limit-multiwrite-merge-downstream-only.patch b/SOURCES/kvm-block-Limit-multiwrite-merge-downstream-only.patch new file mode 100644 index 0000000..2ed4a7c --- /dev/null +++ b/SOURCES/kvm-block-Limit-multiwrite-merge-downstream-only.patch @@ -0,0 +1,68 @@ +From b72ee3ebf0f00962872c69ad3576e1c8c0a208d9 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Thu, 21 Sep 2017 14:23:45 -0300 +Subject: [PATCH] block: Limit multiwrite merge (downstream only) + +RH-Author: Fam Zheng +Message-id: <20170921142345.22892-1-famz@redhat.com> +Patchwork-id: 76502 +O-Subject: [RHEL-7.4 qemu-kvm PATCH] block: Limit multiwrite merge (downstream only) +Bugzilla: 1492559 +RH-Acked-by: Max Reitz +RH-Acked-by: John Snow +RH-Acked-by: Stefan Hajnoczi + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1492559 +Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=14090140 +Upstream: Fixed since 2.3, see below. + +We don't limit the size of the final request of multiwrite_merge. The BZ +has a relatively stable reproducer: Attach an iscsi:// lun as +virtio-blk, then mkfs.ext4. When the guest kernel flushes the page +cache, iscsi driver gets two huge requests that are rejected by the LIO +iscsi target, then reports EIO. + +Upstream QEMU and qemu-kvm-rhev don't have this problem because of two +things: + +1) multiread feature in virtio-blk added in 2.3 (95f7142abc8). + +2) request fragmentation in block layer I/O in 2.7 (04ed95f484 and + 1a62d0accd). + +For 1), we cannot do a faithful backport because it is a new feature, +and is invasive. The change of this patch can be seen as doing a small +part from it, though the implementation is totally different. + +For 2), we would have a serious context conflict because upstream has a +lot of intermediate changes. The patch could possibly be rewritten in +downstream but is on the one hand much more risky than this patch as it +touches the very center of the block I/O code, and on the other hand +loses the meaning because the diff will completely deviate from +upstream. + +Signed-off-by: Fam Zheng +Signed-off-by: Wainer dos Santos Moschetta +--- + block.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/block.c b/block.c +index bdcd741389..b0373d0c16 100644 +--- a/block.c ++++ b/block.c +@@ -4303,6 +4303,11 @@ static int multiwrite_merge(BlockDriverState *bs, BlockRequest *reqs, + merge = 0; + } + ++ if (reqs[outidx].qiov->size + reqs[i].qiov->size >= ++ bs->bl.max_transfer_length * BDRV_SECTOR_SIZE) { ++ merge = 0; ++ } ++ + if (merge) { + size_t size; + QEMUIOVector *qiov = g_malloc0(sizeof(*qiov)); +-- +2.13.5 + diff --git a/SOURCES/kvm-block-linux-aio-fix-memory-and-fd-leak.patch b/SOURCES/kvm-block-linux-aio-fix-memory-and-fd-leak.patch new file mode 100644 index 0000000..12fe94d --- /dev/null +++ b/SOURCES/kvm-block-linux-aio-fix-memory-and-fd-leak.patch @@ -0,0 +1,89 @@ +From 7adcfacf9057c216beb99286e5f233e868865eae Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Tue, 21 Nov 2017 03:21:44 +0100 +Subject: [PATCH 1/9] block/linux-aio: fix memory and fd leak + +RH-Author: Fam Zheng +Message-id: <20171121032145.5681-2-famz@redhat.com> +Patchwork-id: 77766 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v2 1/2] block/linux-aio: fix memory and fd leak +Bugzilla: 1491434 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: John Snow +RH-Acked-by: Laurent Vivier + +From: Stefan Hajnoczi + +Hot unplugging -drive aio=native,file=test.img,format=raw images leaves +the Linux AIO event notifier and struct qemu_laio_state allocated. +Luckily nothing will use the event notifier after the BlockDriverState +has been closed so the handler function is never called. + +It's still worth fixing this resource leak. + +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit abd269b7cf1f084a067731acb8f3272c193cb5f0) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina + +Conflicts: + block/linux-aio.c +* Context is different: downstream we don't have raw_detach_aio_context() + in raw_close(). +* Downstream uses eventfd(2) instead of EventNotifier, so do close() + directly here as well. +--- + block/linux-aio.c | 9 +++++++++ + block/raw-aio.h | 1 + + block/raw-posix.c | 6 ++++++ + 3 files changed, 16 insertions(+) + +diff --git a/block/linux-aio.c b/block/linux-aio.c +index 40041d1..43f14f3 100644 +--- a/block/linux-aio.c ++++ b/block/linux-aio.c +@@ -225,3 +225,12 @@ out_free_state: + g_free(s); + return NULL; + } ++ ++void laio_cleanup(void *s_) ++{ ++ struct qemu_laio_state *s = s_; ++ ++ qemu_aio_set_fd_handler(s->efd, NULL, NULL, NULL, NULL); ++ close(s->efd); ++ g_free(s); ++} +diff --git a/block/raw-aio.h b/block/raw-aio.h +index 7ad0a8a..2dba2c6 100644 +--- a/block/raw-aio.h ++++ b/block/raw-aio.h +@@ -34,6 +34,7 @@ + /* linux-aio.c - Linux native implementation */ + #ifdef CONFIG_LINUX_AIO + void *laio_init(void); ++void laio_cleanup(void *s); + BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd, + int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque, int type); +diff --git a/block/raw-posix.c b/block/raw-posix.c +index ed97bd4..c2b1be2 100644 +--- a/block/raw-posix.c ++++ b/block/raw-posix.c +@@ -1081,6 +1081,12 @@ static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs, + static void raw_close(BlockDriverState *bs) + { + BDRVRawState *s = bs->opaque; ++ ++#ifdef CONFIG_LINUX_AIO ++ if (s->use_aio) { ++ laio_cleanup(s->aio_ctx); ++ } ++#endif + if (s->fd >= 0) { + qemu_close(s->fd); + s->fd = -1; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-ssh-Use-QemuOpts-for-runtime-options.patch b/SOURCES/kvm-block-ssh-Use-QemuOpts-for-runtime-options.patch new file mode 100644 index 0000000..935b40e --- /dev/null +++ b/SOURCES/kvm-block-ssh-Use-QemuOpts-for-runtime-options.patch @@ -0,0 +1,167 @@ +From 1f5e04965db81bea1eac402110166290bfc774db Mon Sep 17 00:00:00 2001 +From: Jeffrey Cody +Date: Sun, 1 Oct 2017 03:55:19 +0200 +Subject: [PATCH 4/4] block/ssh: Use QemuOpts for runtime options + +RH-Author: Jeffrey Cody +Message-id: <798f4a5f4498382bd5764a5e7889595a36aab78c.1506829990.git.jcody@redhat.com> +Patchwork-id: 76786 +O-Subject: [RHEL-7.5 1/1] block/ssh: Use QemuOpts for runtime options +Bugzilla: 1461672 +RH-Acked-by: Thomas Huth +RH-Acked-by: Markus Armbruster +RH-Acked-by: Max Reitz + +From: Max Reitz + +Using QemuOpts will prevent qemu from crashing if the input options have +not been validated (which is the case when they are specified on the +command line or in a json: filename) and some have the wrong type. + +Signed-off-by: Max Reitz +Signed-off-by: Kevin Wolf +(cherry picked from commit 8a6a80896d6af03b8ee0c17cdf37219eca2588a7) +Signed-off-by: Jeff Cody +Signed-off-by: Miroslav Rezanina +--- + block/ssh.c | 79 ++++++++++++++++++++++++++++++++++++++++++------------------- + 1 file changed, 55 insertions(+), 24 deletions(-) + +diff --git a/block/ssh.c b/block/ssh.c +index b00ff7f..a9341b8 100644 +--- a/block/ssh.c ++++ b/block/ssh.c +@@ -510,36 +510,73 @@ static int authenticate(BDRVSSHState *s, const char *user, Error **errp) + return ret; + } + ++static QemuOptsList ssh_runtime_opts = { ++ .name = "ssh", ++ .head = QTAILQ_HEAD_INITIALIZER(ssh_runtime_opts.head), ++ .desc = { ++ { ++ .name = "host", ++ .type = QEMU_OPT_STRING, ++ .help = "Host to connect to", ++ }, ++ { ++ .name = "port", ++ .type = QEMU_OPT_NUMBER, ++ .help = "Port to connect to", ++ }, ++ { ++ .name = "path", ++ .type = QEMU_OPT_STRING, ++ .help = "Path of the image on the host", ++ }, ++ { ++ .name = "user", ++ .type = QEMU_OPT_STRING, ++ .help = "User as which to connect", ++ }, ++ { ++ .name = "host_key_check", ++ .type = QEMU_OPT_STRING, ++ .help = "Defines how and what to check the host key against", ++ }, ++ }, ++}; ++ + static int connect_to_ssh(BDRVSSHState *s, QDict *options, + int ssh_flags, int creat_mode, Error **errp) + { + int r, ret; ++ QemuOpts *opts = NULL; ++ Error *local_err = NULL; + const char *host, *user, *path, *host_key_check; + int port; + +- if (!qdict_haskey(options, "host")) { ++ opts = qemu_opts_create(&ssh_runtime_opts, NULL, 0, &error_abort); ++ qemu_opts_absorb_qdict(opts, options, &local_err); ++ if (local_err) { + ret = -EINVAL; +- error_setg(errp, "No hostname was specified"); ++ error_propagate(errp, local_err); + goto err; + } +- host = qdict_get_str(options, "host"); + +- if (qdict_haskey(options, "port")) { +- port = qdict_get_int(options, "port"); +- } else { +- port = 22; ++ host = qemu_opt_get(opts, "host"); ++ if (!host) { ++ ret = -EINVAL; ++ error_setg(errp, "No hostname was specified"); ++ goto err; + } + +- if (!qdict_haskey(options, "path")) { ++ port = qemu_opt_get_number(opts, "port", 22); ++ ++ path = qemu_opt_get(opts, "path"); ++ if (!path) { + ret = -EINVAL; + error_setg(errp, "No path was specified"); + goto err; + } +- path = qdict_get_str(options, "path"); + +- if (qdict_haskey(options, "user")) { +- user = qdict_get_str(options, "user"); +- } else { ++ user = qemu_opt_get(opts, "user"); ++ if (!user) { + user = g_get_user_name(); + if (!user) { + error_setg_errno(errp, errno, "Can't get user name"); +@@ -548,9 +585,8 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options, + } + } + +- if (qdict_haskey(options, "host_key_check")) { +- host_key_check = qdict_get_str(options, "host_key_check"); +- } else { ++ host_key_check = qemu_opt_get(opts, "host_key_check"); ++ if (!host_key_check) { + host_key_check = "yes"; + } + +@@ -614,21 +650,14 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options, + goto err; + } + ++ qemu_opts_del(opts); ++ + r = libssh2_sftp_fstat(s->sftp_handle, &s->attrs); + if (r < 0) { + sftp_error_setg(errp, s, "failed to read file attributes"); + return -EINVAL; + } + +- /* Delete the options we've used; any not deleted will cause the +- * block layer to give an error about unused options. +- */ +- qdict_del(options, "host"); +- qdict_del(options, "port"); +- qdict_del(options, "user"); +- qdict_del(options, "path"); +- qdict_del(options, "host_key_check"); +- + return 0; + + err: +@@ -648,6 +677,8 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options, + } + s->session = NULL; + ++ qemu_opts_del(opts); ++ + return ret; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-bswap.h-Remove-cpu_to_32wu.patch b/SOURCES/kvm-bswap.h-Remove-cpu_to_32wu.patch index 9b5425a..daf374c 100644 --- a/SOURCES/kvm-bswap.h-Remove-cpu_to_32wu.patch +++ b/SOURCES/kvm-bswap.h-Remove-cpu_to_32wu.patch @@ -1,13 +1,13 @@ -From 613e443ae29ae5f64d7f4f6cd4d583316df332c0 Mon Sep 17 00:00:00 2001 +From b718e298552cbecd1737c9401dc3ea613d6cd63b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 5 Oct 2017 14:51:13 +0200 -Subject: [PATCH 01/11] bswap.h: Remove cpu_to_32wu() +Subject: [PATCH 17/27] bswap.h: Remove cpu_to_32wu() RH-Author: Gerd Hoffmann Message-id: <20171005145119.15277-2-kraxel@redhat.com> Patchwork-id: 76821 O-Subject: [RHEL-7.5 qemu-kvm PATCH 1/7] bswap.h: Remove cpu_to_32wu() -Bugzilla: 1501294 +Bugzilla: 1486642 RH-Acked-by: Dr. David Alan Gilbert RH-Acked-by: Thomas Huth RH-Acked-by: Miroslav Rezanina diff --git a/SOURCES/kvm-buffer-add-buffer_move.patch b/SOURCES/kvm-buffer-add-buffer_move.patch new file mode 100644 index 0000000..528157d --- /dev/null +++ b/SOURCES/kvm-buffer-add-buffer_move.patch @@ -0,0 +1,74 @@ +From e0406c32a13c399b646834089779c39341143253 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:20 +0100 +Subject: [PATCH 06/27] buffer: add buffer_move + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-7-berrange@redhat.com> +Patchwork-id: 78944 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 06/27] buffer: add buffer_move +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +From: Gerd Hoffmann + +Signed-off-by: Gerd Hoffmann +Reviewed-by: Peter Lieven +Reviewed-by: Daniel P. Berrange +Message-id: 1446203414-4013-5-git-send-email-kraxel@redhat.com +(cherry picked from commit 830a9583206a051c240b74c3f688a015dc5d2967) + + Conflicts: + include/qemu/buffer.h + util/buffer.c - APIs are still in vnc.{c,h} + +Signed-off-by: Miroslav Rezanina +--- + ui/vnc.c | 16 ++++++++++++++++ + ui/vnc.h | 1 + + 2 files changed, 17 insertions(+) + +diff --git a/ui/vnc.c b/ui/vnc.c +index b520f58..95457ad 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -530,6 +530,22 @@ void buffer_move_empty(Buffer *to, Buffer *from) + from->buffer = NULL; + } + ++void buffer_move(Buffer *to, Buffer *from) ++{ ++ if (to->offset == 0) { ++ buffer_move_empty(to, from); ++ return; ++ } ++ ++ buffer_reserve(to, from->offset); ++ buffer_append(to, from->buffer, from->offset); ++ ++ g_free(from->buffer); ++ from->offset = 0; ++ from->capacity = 0; ++ from->buffer = NULL; ++} ++ + + static void vnc_desktop_resize(VncState *vs) + { +diff --git a/ui/vnc.h b/ui/vnc.h +index c300660..703fef9 100644 +--- a/ui/vnc.h ++++ b/ui/vnc.h +@@ -549,6 +549,7 @@ void buffer_append(Buffer *buffer, const void *data, size_t len); + void buffer_advance(Buffer *buf, size_t len); + uint8_t *buffer_end(Buffer *buffer); + void buffer_move_empty(Buffer *to, Buffer *from); ++void buffer_move(Buffer *to, Buffer *from); + + + /* Misc helpers */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-buffer-add-buffer_move_empty.patch b/SOURCES/kvm-buffer-add-buffer_move_empty.patch new file mode 100644 index 0000000..8983b1a --- /dev/null +++ b/SOURCES/kvm-buffer-add-buffer_move_empty.patch @@ -0,0 +1,73 @@ +From 4c2f805375c0dc66cdd2a30b29c03021833e02ca Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:19 +0100 +Subject: [PATCH 05/27] buffer: add buffer_move_empty + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-6-berrange@redhat.com> +Patchwork-id: 78934 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 05/27] buffer: add buffer_move_empty +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +From: Gerd Hoffmann + +Signed-off-by: Gerd Hoffmann +Reviewed-by: Peter Lieven +Reviewed-by: Daniel Berrange +Message-id: 1446203414-4013-4-git-send-email-kraxel@redhat.com +(cherry picked from commit 4d1eb5fdb141c9100eb82e1dc7d4547fb1decd8b) + + Conflicts: + include/qemu/buffer.h + util/buffer.c - APIs are still in vnc.{c,h} + +Signed-off-by: Miroslav Rezanina +--- + ui/vnc.c | 15 +++++++++++++++ + ui/vnc.h | 1 + + 2 files changed, 16 insertions(+) + +diff --git a/ui/vnc.c b/ui/vnc.c +index 9047862..b520f58 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -516,6 +516,21 @@ void buffer_advance(Buffer *buf, size_t len) + buf->offset -= len; + } + ++void buffer_move_empty(Buffer *to, Buffer *from) ++{ ++ assert(to->offset == 0); ++ ++ g_free(to->buffer); ++ to->offset = from->offset; ++ to->capacity = from->capacity; ++ to->buffer = from->buffer; ++ ++ from->offset = 0; ++ from->capacity = 0; ++ from->buffer = NULL; ++} ++ ++ + static void vnc_desktop_resize(VncState *vs) + { + if (vs->csock == -1 || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) { +diff --git a/ui/vnc.h b/ui/vnc.h +index d1badbb..c300660 100644 +--- a/ui/vnc.h ++++ b/ui/vnc.h +@@ -548,6 +548,7 @@ void buffer_free(Buffer *buffer); + void buffer_append(Buffer *buffer, const void *data, size_t len); + void buffer_advance(Buffer *buf, size_t len); + uint8_t *buffer_end(Buffer *buffer); ++void buffer_move_empty(Buffer *to, Buffer *from); + + + /* Misc helpers */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-build-sys-restrict-vmcoreinfo-to-fw_cfg-dma-capable-.patch b/SOURCES/kvm-build-sys-restrict-vmcoreinfo-to-fw_cfg-dma-capable-.patch new file mode 100644 index 0000000..83ab55d --- /dev/null +++ b/SOURCES/kvm-build-sys-restrict-vmcoreinfo-to-fw_cfg-dma-capable-.patch @@ -0,0 +1,77 @@ +From bf8a461cbf2030ed4d18aa9b5dc9c23d7a1059df Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:46 +0100 +Subject: [PATCH 15/41] build-sys: restrict vmcoreinfo to fw_cfg+dma capable + targets +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-16-marcandre.lureau@redhat.com> +Patchwork-id: 78365 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 15/41] build-sys: restrict vmcoreinfo to fw_cfg+dma capable targets +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +vmcoreinfo is built for all targets. However, it requires fw_cfg with +DMA operations support (write operation). Restrict vmcoreinfo exposure +to x86 architectures that are supporting FW_CFG_DMA. + +Signed-off-by: Marc-André Lureau +Reviewed-by: Thomas Huth +Reviewed-by: Daniel Henrique Barboza +Tested-by: Daniel Henrique Barboza +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin + +(cherry picked from commit f865da7c369fa00b2ccaf6bce158ad2701b2a27c) + +RHEL: minor build-sys conflicts. + +Removed unsupport architectures, update commit message. + +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + default-configs/i386-softmmu.mak | 1 + + default-configs/x86_64-softmmu.mak | 1 + + hw/misc/Makefile.objs | 2 +- + 3 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak +index fb84f80..aeeac4e 100644 +--- a/default-configs/i386-softmmu.mak ++++ b/default-configs/i386-softmmu.mak +@@ -45,3 +45,4 @@ CONFIG_APIC=y + CONFIG_IOAPIC=y + CONFIG_ICC_BUS=y + CONFIG_PVPANIC=y ++CONFIG_FW_CFG_DMA=y +diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak +index a6fdf84..19667bf 100644 +--- a/default-configs/x86_64-softmmu.mak ++++ b/default-configs/x86_64-softmmu.mak +@@ -38,3 +38,4 @@ CONFIG_APIC=y + CONFIG_IOAPIC=y + CONFIG_ICC_BUS=y + CONFIG_PVPANIC=y ++CONFIG_FW_CFG_DMA=y +diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs +index 39b6593..f692fcd 100644 +--- a/hw/misc/Makefile.objs ++++ b/hw/misc/Makefile.objs +@@ -5,7 +5,7 @@ common-obj-$(CONFIG_ISA_DEBUG) += debugexit.o + common-obj-$(CONFIG_SGA) += sga.o + common-obj-$(CONFIG_ISA_TESTDEV) += pc-testdev.o + common-obj-$(CONFIG_PCI_TESTDEV) += pci-testdev.o +-common-obj-y += vmcoreinfo.o ++common-obj-$(CONFIG_FW_CFG_DMA) += vmcoreinfo.o + + obj-$(CONFIG_VMPORT) += vmport.o + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-cirrus-fix-oob-access-in-mode4and5-write-functions.patch b/SOURCES/kvm-cirrus-fix-oob-access-in-mode4and5-write-functions.patch index 4df0e5d..715c8fe 100644 --- a/SOURCES/kvm-cirrus-fix-oob-access-in-mode4and5-write-functions.patch +++ b/SOURCES/kvm-cirrus-fix-oob-access-in-mode4and5-write-functions.patch @@ -1,13 +1,13 @@ -From bdbdf577ba7c4de8b815510ec7024dc287538d26 Mon Sep 17 00:00:00 2001 +From 6420a8c59712cce74ad689c0d692982665a785b0 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 20 Oct 2017 11:06:19 +0200 -Subject: [PATCH 11/11] cirrus: fix oob access in mode4and5 write functions +Subject: [PATCH 4/7] cirrus: fix oob access in mode4and5 write functions RH-Author: Gerd Hoffmann Message-id: <20171020110619.2541-12-kraxel@redhat.com> Patchwork-id: 77403 O-Subject: [RHEL-7.5 qemu-kvm PATCH 11/11] cirrus: fix oob access in mode4and5 write functions -Bugzilla: 1501294 +Bugzilla: 1501295 RH-Acked-by: Stefan Hajnoczi RH-Acked-by: Dr. David Alan Gilbert RH-Acked-by: Miroslav Rezanina diff --git a/SOURCES/kvm-dump-Fix-dump-guest-memory-termination-and-use-after.patch b/SOURCES/kvm-dump-Fix-dump-guest-memory-termination-and-use-after.patch new file mode 100644 index 0000000..a5d0686 --- /dev/null +++ b/SOURCES/kvm-dump-Fix-dump-guest-memory-termination-and-use-after.patch @@ -0,0 +1,85 @@ +From a32c9e8da011b25ba9a056bc41c990694b730566 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:51 +0100 +Subject: [PATCH 20/41] dump: Fix dump-guest-memory termination and + use-after-close +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-21-marcandre.lureau@redhat.com> +Patchwork-id: 78374 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 20/41] dump: Fix dump-guest-memory termination and use-after-close +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: Gonglei + +dump_iterate() dumps blocks in a loop. Eventually, get_next_block() +returns "no more". We then call dump_completed(). But we neglect to +break the loop! Broken in commit 4c7e251a. + +Because of that, we dump the last block again. This attempts to write +to s->fd, which fails if we're lucky. The error makes dump_iterate() +return failure. It's the only way it can ever return. + +Theoretical: if we're not so lucky, something else has opened something +for writing and got the same fd. dump_iterate() then keeps looping, +messing up the something else's output, until a write fails, or the +process mercifully terminates. + +The obvious fix is to restore the return lost in commit 4c7e251a. But +the root cause of the bug is needlessly opaque loop control. Replace it +by a clean do ... while loop. + +This makes the badly chosen return values of get_next_block() more +visible. Cleaning that up is outside the scope of this bug fix. + +Signed-off-by: Gonglei +Signed-off-by: Markus Armbruster +Signed-off-by: Michael Tokarev + +(cherry picked from commit 08a655be71d0a130a5d9bf7816d096ec31c4f055) +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + dump.c | 11 ++++------- + 1 file changed, 4 insertions(+), 7 deletions(-) + +diff --git a/dump.c b/dump.c +index 099346a..83b6d20 100644 +--- a/dump.c ++++ b/dump.c +@@ -610,10 +610,9 @@ static void dump_iterate(DumpState *s, Error **errp) + { + GuestPhysBlock *block; + int64_t size; +- int ret; + Error *local_err = NULL; + +- while (1) { ++ do { + block = s->next_block; + + size = block->target_end - block->target_start; +@@ -629,11 +628,9 @@ static void dump_iterate(DumpState *s, Error **errp) + return; + } + +- ret = get_next_block(s, block); +- if (ret == 1) { +- dump_completed(s); +- } +- } ++ } while (!get_next_block(s, block)); ++ ++ dump_completed(s); + } + + static void create_vmcore(DumpState *s, Error **errp) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-dump-Make-DumpState-and-endian-conversion-routines-a.patch b/SOURCES/kvm-dump-Make-DumpState-and-endian-conversion-routines-a.patch new file mode 100644 index 0000000..f8739e9 --- /dev/null +++ b/SOURCES/kvm-dump-Make-DumpState-and-endian-conversion-routines-a.patch @@ -0,0 +1,635 @@ +From 36cd1b1bdc56da8e18d69df82731fb79a2ed01dd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:47 +0100 +Subject: [PATCH 16/41] dump: Make DumpState and endian conversion routines + available for arch-specific dump code +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-17-marcandre.lureau@redhat.com> +Patchwork-id: 78366 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 16/41] dump: Make DumpState and endian conversion routines available for arch-specific dump code +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: Bharata B Rao + +Make DumpState and endian conversion routines available for arch-specific dump +code by moving into dump.h. DumpState will be needed by arch-specific dump +code to access target endian information from DumpState->ArchDumpInfo. Also +break the dependency of dump.h from stubs/dump.c by creating a separate +dump-arch.h. + +This patch doesn't change any functionality. + +Signed-off-by: Bharata B Rao +[ rebased on top of current master branch, + renamed endian helpers to cpu_to_dump{16,32,64}, + pass a DumpState * argument to endian helpers, + Greg Kurz ] +Signed-off-by: Greg Kurz +[agraf: fix to apply] +Signed-off-by: Alexander Graf + +(cherry picked from commit acb0ef5801fc0caafdcfd34ae62e48d276866a1b) +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + dump.c | 231 ++++++++++++++++++--------------------------- + include/sysemu/dump-arch.h | 28 ++++++ + include/sysemu/dump.h | 45 +++++++-- + stubs/dump.c | 2 +- + 4 files changed, 154 insertions(+), 152 deletions(-) + create mode 100644 include/sysemu/dump-arch.h + +diff --git a/dump.c b/dump.c +index e9bd237..c902944 100644 +--- a/dump.c ++++ b/dump.c +@@ -36,9 +36,9 @@ + #define ELF_MACHINE_UNAME "Unknown" + #endif + +-static uint16_t cpu_convert_to_target16(uint16_t val, int endian) ++uint16_t cpu_to_dump16(DumpState *s, uint16_t val) + { +- if (endian == ELFDATA2LSB) { ++ if (s->dump_info.d_endian == ELFDATA2LSB) { + val = cpu_to_le16(val); + } else { + val = cpu_to_be16(val); +@@ -47,9 +47,9 @@ static uint16_t cpu_convert_to_target16(uint16_t val, int endian) + return val; + } + +-static uint32_t cpu_convert_to_target32(uint32_t val, int endian) ++uint32_t cpu_to_dump32(DumpState *s, uint32_t val) + { +- if (endian == ELFDATA2LSB) { ++ if (s->dump_info.d_endian == ELFDATA2LSB) { + val = cpu_to_le32(val); + } else { + val = cpu_to_be32(val); +@@ -58,9 +58,9 @@ static uint32_t cpu_convert_to_target32(uint32_t val, int endian) + return val; + } + +-static uint64_t cpu_convert_to_target64(uint64_t val, int endian) ++uint64_t cpu_to_dump64(DumpState *s, uint64_t val) + { +- if (endian == ELFDATA2LSB) { ++ if (s->dump_info.d_endian == ELFDATA2LSB) { + val = cpu_to_le64(val); + } else { + val = cpu_to_be64(val); +@@ -69,36 +69,6 @@ static uint64_t cpu_convert_to_target64(uint64_t val, int endian) + return val; + } + +-typedef struct DumpState { +- GuestPhysBlockList guest_phys_blocks; +- ArchDumpInfo dump_info; +- MemoryMappingList list; +- uint16_t phdr_num; +- uint32_t sh_info; +- bool have_section; +- bool resume; +- ssize_t note_size; +- hwaddr memory_offset; +- int fd; +- +- GuestPhysBlock *next_block; +- ram_addr_t start; +- bool has_filter; +- int64_t begin; +- int64_t length; +- +- uint8_t *note_buf; /* buffer for notes */ +- size_t note_buf_offset; /* the writing place in note_buf */ +- uint32_t nr_cpus; /* number of guest's cpu */ +- uint64_t max_mapnr; /* the biggest guest's phys-mem's number */ +- size_t len_dump_bitmap; /* the size of the place used to store +- dump_bitmap in vmcore */ +- off_t offset_dump_bitmap; /* offset of dump_bitmap part in vmcore */ +- off_t offset_page; /* offset of page part in vmcore */ +- size_t num_dumpable; /* number of page that can be dumped */ +- uint32_t flag_compress; /* indicate the compression format */ +-} DumpState; +- + static int dump_cleanup(DumpState *s) + { + int ret = 0; +@@ -137,29 +107,25 @@ static int write_elf64_header(DumpState *s) + { + Elf64_Ehdr elf_header; + int ret; +- int endian = s->dump_info.d_endian; + + memset(&elf_header, 0, sizeof(Elf64_Ehdr)); + memcpy(&elf_header, ELFMAG, SELFMAG); + elf_header.e_ident[EI_CLASS] = ELFCLASS64; + elf_header.e_ident[EI_DATA] = s->dump_info.d_endian; + elf_header.e_ident[EI_VERSION] = EV_CURRENT; +- elf_header.e_type = cpu_convert_to_target16(ET_CORE, endian); +- elf_header.e_machine = cpu_convert_to_target16(s->dump_info.d_machine, +- endian); +- elf_header.e_version = cpu_convert_to_target32(EV_CURRENT, endian); +- elf_header.e_ehsize = cpu_convert_to_target16(sizeof(elf_header), endian); +- elf_header.e_phoff = cpu_convert_to_target64(sizeof(Elf64_Ehdr), endian); +- elf_header.e_phentsize = cpu_convert_to_target16(sizeof(Elf64_Phdr), +- endian); +- elf_header.e_phnum = cpu_convert_to_target16(s->phdr_num, endian); ++ elf_header.e_type = cpu_to_dump16(s, ET_CORE); ++ elf_header.e_machine = cpu_to_dump16(s, s->dump_info.d_machine); ++ elf_header.e_version = cpu_to_dump32(s, EV_CURRENT); ++ elf_header.e_ehsize = cpu_to_dump16(s, sizeof(elf_header)); ++ elf_header.e_phoff = cpu_to_dump64(s, sizeof(Elf64_Ehdr)); ++ elf_header.e_phentsize = cpu_to_dump16(s, sizeof(Elf64_Phdr)); ++ elf_header.e_phnum = cpu_to_dump16(s, s->phdr_num); + if (s->have_section) { + uint64_t shoff = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) * s->sh_info; + +- elf_header.e_shoff = cpu_convert_to_target64(shoff, endian); +- elf_header.e_shentsize = cpu_convert_to_target16(sizeof(Elf64_Shdr), +- endian); +- elf_header.e_shnum = cpu_convert_to_target16(1, endian); ++ elf_header.e_shoff = cpu_to_dump64(s, shoff); ++ elf_header.e_shentsize = cpu_to_dump16(s, sizeof(Elf64_Shdr)); ++ elf_header.e_shnum = cpu_to_dump16(s, 1); + } + + ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s); +@@ -175,29 +141,25 @@ static int write_elf32_header(DumpState *s) + { + Elf32_Ehdr elf_header; + int ret; +- int endian = s->dump_info.d_endian; + + memset(&elf_header, 0, sizeof(Elf32_Ehdr)); + memcpy(&elf_header, ELFMAG, SELFMAG); + elf_header.e_ident[EI_CLASS] = ELFCLASS32; +- elf_header.e_ident[EI_DATA] = endian; ++ elf_header.e_ident[EI_DATA] = s->dump_info.d_endian; + elf_header.e_ident[EI_VERSION] = EV_CURRENT; +- elf_header.e_type = cpu_convert_to_target16(ET_CORE, endian); +- elf_header.e_machine = cpu_convert_to_target16(s->dump_info.d_machine, +- endian); +- elf_header.e_version = cpu_convert_to_target32(EV_CURRENT, endian); +- elf_header.e_ehsize = cpu_convert_to_target16(sizeof(elf_header), endian); +- elf_header.e_phoff = cpu_convert_to_target32(sizeof(Elf32_Ehdr), endian); +- elf_header.e_phentsize = cpu_convert_to_target16(sizeof(Elf32_Phdr), +- endian); +- elf_header.e_phnum = cpu_convert_to_target16(s->phdr_num, endian); ++ elf_header.e_type = cpu_to_dump16(s, ET_CORE); ++ elf_header.e_machine = cpu_to_dump16(s, s->dump_info.d_machine); ++ elf_header.e_version = cpu_to_dump32(s, EV_CURRENT); ++ elf_header.e_ehsize = cpu_to_dump16(s, sizeof(elf_header)); ++ elf_header.e_phoff = cpu_to_dump32(s, sizeof(Elf32_Ehdr)); ++ elf_header.e_phentsize = cpu_to_dump16(s, sizeof(Elf32_Phdr)); ++ elf_header.e_phnum = cpu_to_dump16(s, s->phdr_num); + if (s->have_section) { + uint32_t shoff = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) * s->sh_info; + +- elf_header.e_shoff = cpu_convert_to_target32(shoff, endian); +- elf_header.e_shentsize = cpu_convert_to_target16(sizeof(Elf32_Shdr), +- endian); +- elf_header.e_shnum = cpu_convert_to_target16(1, endian); ++ elf_header.e_shoff = cpu_to_dump32(s, shoff); ++ elf_header.e_shentsize = cpu_to_dump16(s, sizeof(Elf32_Shdr)); ++ elf_header.e_shnum = cpu_to_dump16(s, 1); + } + + ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s); +@@ -215,15 +177,14 @@ static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping, + { + Elf64_Phdr phdr; + int ret; +- int endian = s->dump_info.d_endian; + + memset(&phdr, 0, sizeof(Elf64_Phdr)); +- phdr.p_type = cpu_convert_to_target32(PT_LOAD, endian); +- phdr.p_offset = cpu_convert_to_target64(offset, endian); +- phdr.p_paddr = cpu_convert_to_target64(memory_mapping->phys_addr, endian); +- phdr.p_filesz = cpu_convert_to_target64(filesz, endian); +- phdr.p_memsz = cpu_convert_to_target64(memory_mapping->length, endian); +- phdr.p_vaddr = cpu_convert_to_target64(memory_mapping->virt_addr, endian); ++ phdr.p_type = cpu_to_dump32(s, PT_LOAD); ++ phdr.p_offset = cpu_to_dump64(s, offset); ++ phdr.p_paddr = cpu_to_dump64(s, memory_mapping->phys_addr); ++ phdr.p_filesz = cpu_to_dump64(s, filesz); ++ phdr.p_memsz = cpu_to_dump64(s, memory_mapping->length); ++ phdr.p_vaddr = cpu_to_dump64(s, memory_mapping->virt_addr); + + assert(memory_mapping->length >= filesz); + +@@ -242,15 +203,14 @@ static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping, + { + Elf32_Phdr phdr; + int ret; +- int endian = s->dump_info.d_endian; + + memset(&phdr, 0, sizeof(Elf32_Phdr)); +- phdr.p_type = cpu_convert_to_target32(PT_LOAD, endian); +- phdr.p_offset = cpu_convert_to_target32(offset, endian); +- phdr.p_paddr = cpu_convert_to_target32(memory_mapping->phys_addr, endian); +- phdr.p_filesz = cpu_convert_to_target32(filesz, endian); +- phdr.p_memsz = cpu_convert_to_target32(memory_mapping->length, endian); +- phdr.p_vaddr = cpu_convert_to_target32(memory_mapping->virt_addr, endian); ++ phdr.p_type = cpu_to_dump32(s, PT_LOAD); ++ phdr.p_offset = cpu_to_dump32(s, offset); ++ phdr.p_paddr = cpu_to_dump32(s, memory_mapping->phys_addr); ++ phdr.p_filesz = cpu_to_dump32(s, filesz); ++ phdr.p_memsz = cpu_to_dump32(s, memory_mapping->length); ++ phdr.p_vaddr = cpu_to_dump32(s, memory_mapping->virt_addr); + + assert(memory_mapping->length >= filesz); + +@@ -266,16 +226,15 @@ static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping, + static int write_elf64_note(DumpState *s) + { + Elf64_Phdr phdr; +- int endian = s->dump_info.d_endian; + hwaddr begin = s->memory_offset - s->note_size; + int ret; + + memset(&phdr, 0, sizeof(Elf64_Phdr)); +- phdr.p_type = cpu_convert_to_target32(PT_NOTE, endian); +- phdr.p_offset = cpu_convert_to_target64(begin, endian); ++ phdr.p_type = cpu_to_dump32(s, PT_NOTE); ++ phdr.p_offset = cpu_to_dump64(s, begin); + phdr.p_paddr = 0; +- phdr.p_filesz = cpu_convert_to_target64(s->note_size, endian); +- phdr.p_memsz = cpu_convert_to_target64(s->note_size, endian); ++ phdr.p_filesz = cpu_to_dump64(s, s->note_size); ++ phdr.p_memsz = cpu_to_dump64(s, s->note_size); + phdr.p_vaddr = 0; + + ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s); +@@ -325,15 +284,14 @@ static int write_elf32_note(DumpState *s) + { + hwaddr begin = s->memory_offset - s->note_size; + Elf32_Phdr phdr; +- int endian = s->dump_info.d_endian; + int ret; + + memset(&phdr, 0, sizeof(Elf32_Phdr)); +- phdr.p_type = cpu_convert_to_target32(PT_NOTE, endian); +- phdr.p_offset = cpu_convert_to_target32(begin, endian); ++ phdr.p_type = cpu_to_dump32(s, PT_NOTE); ++ phdr.p_offset = cpu_to_dump32(s, begin); + phdr.p_paddr = 0; +- phdr.p_filesz = cpu_convert_to_target32(s->note_size, endian); +- phdr.p_memsz = cpu_convert_to_target32(s->note_size, endian); ++ phdr.p_filesz = cpu_to_dump32(s, s->note_size); ++ phdr.p_memsz = cpu_to_dump32(s, s->note_size); + phdr.p_vaddr = 0; + + ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s); +@@ -378,7 +336,6 @@ static int write_elf_section(DumpState *s, int type) + { + Elf32_Shdr shdr32; + Elf64_Shdr shdr64; +- int endian = s->dump_info.d_endian; + int shdr_size; + void *shdr; + int ret; +@@ -386,12 +343,12 @@ static int write_elf_section(DumpState *s, int type) + if (type == 0) { + shdr_size = sizeof(Elf32_Shdr); + memset(&shdr32, 0, shdr_size); +- shdr32.sh_info = cpu_convert_to_target32(s->sh_info, endian); ++ shdr32.sh_info = cpu_to_dump32(s, s->sh_info); + shdr = &shdr32; + } else { + shdr_size = sizeof(Elf64_Shdr); + memset(&shdr64, 0, shdr_size); +- shdr64.sh_info = cpu_convert_to_target32(s->sh_info, endian); ++ shdr64.sh_info = cpu_to_dump32(s, s->sh_info); + shdr = &shdr64; + } + +@@ -797,7 +754,6 @@ static int create_header32(DumpState *s) + DiskDumpHeader32 *dh = NULL; + KdumpSubHeader32 *kh = NULL; + size_t size; +- int endian = s->dump_info.d_endian; + uint32_t block_size; + uint32_t sub_hdr_size; + uint32_t bitmap_blocks; +@@ -809,18 +765,17 @@ static int create_header32(DumpState *s) + dh = g_malloc0(size); + + strncpy(dh->signature, KDUMP_SIGNATURE, strlen(KDUMP_SIGNATURE)); +- dh->header_version = cpu_convert_to_target32(6, endian); ++ dh->header_version = cpu_to_dump32(s, 6); + block_size = TARGET_PAGE_SIZE; +- dh->block_size = cpu_convert_to_target32(block_size, endian); ++ dh->block_size = cpu_to_dump32(s, block_size); + sub_hdr_size = sizeof(struct KdumpSubHeader32) + s->note_size; + sub_hdr_size = DIV_ROUND_UP(sub_hdr_size, block_size); +- dh->sub_hdr_size = cpu_convert_to_target32(sub_hdr_size, endian); ++ dh->sub_hdr_size = cpu_to_dump32(s, sub_hdr_size); + /* dh->max_mapnr may be truncated, full 64bit is in kh.max_mapnr_64 */ +- dh->max_mapnr = cpu_convert_to_target32(MIN(s->max_mapnr, UINT_MAX), +- endian); +- dh->nr_cpus = cpu_convert_to_target32(s->nr_cpus, endian); ++ dh->max_mapnr = cpu_to_dump32(s, MIN(s->max_mapnr, UINT_MAX)); ++ dh->nr_cpus = cpu_to_dump32(s, s->nr_cpus); + bitmap_blocks = DIV_ROUND_UP(s->len_dump_bitmap, block_size) * 2; +- dh->bitmap_blocks = cpu_convert_to_target32(bitmap_blocks, endian); ++ dh->bitmap_blocks = cpu_to_dump32(s, bitmap_blocks); + strncpy(dh->utsname.machine, ELF_MACHINE_UNAME, sizeof(dh->utsname.machine)); + + if (s->flag_compress & DUMP_DH_COMPRESSED_ZLIB) { +@@ -836,7 +791,7 @@ static int create_header32(DumpState *s) + status |= DUMP_DH_COMPRESSED_SNAPPY; + } + #endif +- dh->status = cpu_convert_to_target32(status, endian); ++ dh->status = cpu_to_dump32(s, status); + + if (write_buffer(s->fd, 0, dh, size) < 0) { + dump_error(s, "dump: failed to write disk dump header.\n"); +@@ -849,13 +804,13 @@ static int create_header32(DumpState *s) + kh = g_malloc0(size); + + /* 64bit max_mapnr_64 */ +- kh->max_mapnr_64 = cpu_convert_to_target64(s->max_mapnr, endian); +- kh->phys_base = cpu_convert_to_target32(PHYS_BASE, endian); +- kh->dump_level = cpu_convert_to_target32(DUMP_LEVEL, endian); ++ kh->max_mapnr_64 = cpu_to_dump64(s, s->max_mapnr); ++ kh->phys_base = cpu_to_dump32(s, PHYS_BASE); ++ kh->dump_level = cpu_to_dump32(s, DUMP_LEVEL); + + offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size; +- kh->offset_note = cpu_convert_to_target64(offset_note, endian); +- kh->note_size = cpu_convert_to_target32(s->note_size, endian); ++ kh->offset_note = cpu_to_dump64(s, offset_note); ++ kh->note_size = cpu_to_dump32(s, s->note_size); + + if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS * + block_size, kh, size) < 0) { +@@ -904,7 +859,6 @@ static int create_header64(DumpState *s) + DiskDumpHeader64 *dh = NULL; + KdumpSubHeader64 *kh = NULL; + size_t size; +- int endian = s->dump_info.d_endian; + uint32_t block_size; + uint32_t sub_hdr_size; + uint32_t bitmap_blocks; +@@ -916,18 +870,17 @@ static int create_header64(DumpState *s) + dh = g_malloc0(size); + + strncpy(dh->signature, KDUMP_SIGNATURE, strlen(KDUMP_SIGNATURE)); +- dh->header_version = cpu_convert_to_target32(6, endian); ++ dh->header_version = cpu_to_dump32(s, 6); + block_size = TARGET_PAGE_SIZE; +- dh->block_size = cpu_convert_to_target32(block_size, endian); ++ dh->block_size = cpu_to_dump32(s, block_size); + sub_hdr_size = sizeof(struct KdumpSubHeader64) + s->note_size; + sub_hdr_size = DIV_ROUND_UP(sub_hdr_size, block_size); +- dh->sub_hdr_size = cpu_convert_to_target32(sub_hdr_size, endian); ++ dh->sub_hdr_size = cpu_to_dump32(s, sub_hdr_size); + /* dh->max_mapnr may be truncated, full 64bit is in kh.max_mapnr_64 */ +- dh->max_mapnr = cpu_convert_to_target32(MIN(s->max_mapnr, UINT_MAX), +- endian); +- dh->nr_cpus = cpu_convert_to_target32(s->nr_cpus, endian); ++ dh->max_mapnr = cpu_to_dump32(s, MIN(s->max_mapnr, UINT_MAX)); ++ dh->nr_cpus = cpu_to_dump32(s, s->nr_cpus); + bitmap_blocks = DIV_ROUND_UP(s->len_dump_bitmap, block_size) * 2; +- dh->bitmap_blocks = cpu_convert_to_target32(bitmap_blocks, endian); ++ dh->bitmap_blocks = cpu_to_dump32(s, bitmap_blocks); + strncpy(dh->utsname.machine, ELF_MACHINE_UNAME, sizeof(dh->utsname.machine)); + + if (s->flag_compress & DUMP_DH_COMPRESSED_ZLIB) { +@@ -943,7 +896,7 @@ static int create_header64(DumpState *s) + status |= DUMP_DH_COMPRESSED_SNAPPY; + } + #endif +- dh->status = cpu_convert_to_target32(status, endian); ++ dh->status = cpu_to_dump32(s, status); + + if (write_buffer(s->fd, 0, dh, size) < 0) { + dump_error(s, "dump: failed to write disk dump header.\n"); +@@ -956,13 +909,13 @@ static int create_header64(DumpState *s) + kh = g_malloc0(size); + + /* 64bit max_mapnr_64 */ +- kh->max_mapnr_64 = cpu_convert_to_target64(s->max_mapnr, endian); +- kh->phys_base = cpu_convert_to_target64(PHYS_BASE, endian); +- kh->dump_level = cpu_convert_to_target32(DUMP_LEVEL, endian); ++ kh->max_mapnr_64 = cpu_to_dump64(s, s->max_mapnr); ++ kh->phys_base = cpu_to_dump64(s, PHYS_BASE); ++ kh->dump_level = cpu_to_dump32(s, DUMP_LEVEL); + + offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size; +- kh->offset_note = cpu_convert_to_target64(offset_note, endian); +- kh->note_size = cpu_convert_to_target64(s->note_size, endian); ++ kh->offset_note = cpu_to_dump64(s, offset_note); ++ kh->note_size = cpu_to_dump64(s, s->note_size); + + if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS * + block_size, kh, size) < 0) { +@@ -1266,7 +1219,6 @@ static int write_dump_pages(DumpState *s) + off_t offset_desc, offset_data; + PageDescriptor pd, pd_zero; + uint8_t *buf; +- int endian = s->dump_info.d_endian; + GuestPhysBlock *block_iter = NULL; + uint64_t pfn_iter; + +@@ -1291,10 +1243,10 @@ static int write_dump_pages(DumpState *s) + * init zero page's page_desc and page_data, because every zero page + * uses the same page_data + */ +- pd_zero.size = cpu_convert_to_target32(TARGET_PAGE_SIZE, endian); +- pd_zero.flags = cpu_convert_to_target32(0, endian); +- pd_zero.offset = cpu_convert_to_target64(offset_data, endian); +- pd_zero.page_flags = cpu_convert_to_target64(0, endian); ++ pd_zero.size = cpu_to_dump32(s, TARGET_PAGE_SIZE); ++ pd_zero.flags = cpu_to_dump32(s, 0); ++ pd_zero.offset = cpu_to_dump64(s, offset_data); ++ pd_zero.page_flags = cpu_to_dump64(s, 0); + buf = g_malloc0(TARGET_PAGE_SIZE); + ret = write_cache(&page_data, buf, TARGET_PAGE_SIZE, false); + g_free(buf); +@@ -1332,12 +1284,11 @@ static int write_dump_pages(DumpState *s) + */ + size_out = len_buf_out; + if ((s->flag_compress & DUMP_DH_COMPRESSED_ZLIB) && +- (compress2(buf_out, (uLongf *)&size_out, buf, +- TARGET_PAGE_SIZE, Z_BEST_SPEED) == Z_OK) && +- (size_out < TARGET_PAGE_SIZE)) { +- pd.flags = cpu_convert_to_target32(DUMP_DH_COMPRESSED_ZLIB, +- endian); +- pd.size = cpu_convert_to_target32(size_out, endian); ++ (compress2(buf_out, (uLongf *)&size_out, buf, ++ TARGET_PAGE_SIZE, Z_BEST_SPEED) == Z_OK) && ++ (size_out < TARGET_PAGE_SIZE)) { ++ pd.flags = cpu_to_dump32(s, DUMP_DH_COMPRESSED_ZLIB); ++ pd.size = cpu_to_dump32(s, size_out); + + ret = write_cache(&page_data, buf_out, size_out, false); + if (ret < 0) { +@@ -1349,9 +1300,8 @@ static int write_dump_pages(DumpState *s) + (lzo1x_1_compress(buf, TARGET_PAGE_SIZE, buf_out, + (lzo_uint *)&size_out, wrkmem) == LZO_E_OK) && + (size_out < TARGET_PAGE_SIZE)) { +- pd.flags = cpu_convert_to_target32(DUMP_DH_COMPRESSED_LZO, +- endian); +- pd.size = cpu_convert_to_target32(size_out, endian); ++ pd.flags = cpu_to_dump32(s, DUMP_DH_COMPRESSED_LZO); ++ pd.size = cpu_to_dump32(s, size_out); + + ret = write_cache(&page_data, buf_out, size_out, false); + if (ret < 0) { +@@ -1364,9 +1314,8 @@ static int write_dump_pages(DumpState *s) + (snappy_compress((char *)buf, TARGET_PAGE_SIZE, + (char *)buf_out, &size_out) == SNAPPY_OK) && + (size_out < TARGET_PAGE_SIZE)) { +- pd.flags = cpu_convert_to_target32( +- DUMP_DH_COMPRESSED_SNAPPY, endian); +- pd.size = cpu_convert_to_target32(size_out, endian); ++ pd.flags = cpu_to_dump32(s, DUMP_DH_COMPRESSED_SNAPPY); ++ pd.size = cpu_to_dump32(s, size_out); + + ret = write_cache(&page_data, buf_out, size_out, false); + if (ret < 0) { +@@ -1379,9 +1328,9 @@ static int write_dump_pages(DumpState *s) + * fall back to save in plaintext, size_out should be + * assigned TARGET_PAGE_SIZE + */ +- pd.flags = cpu_convert_to_target32(0, endian); ++ pd.flags = cpu_to_dump32(s, 0); + size_out = TARGET_PAGE_SIZE; +- pd.size = cpu_convert_to_target32(size_out, endian); ++ pd.size = cpu_to_dump32(s, size_out); + + ret = write_cache(&page_data, buf, TARGET_PAGE_SIZE, false); + if (ret < 0) { +@@ -1391,8 +1340,8 @@ static int write_dump_pages(DumpState *s) + } + + /* get and write page desc here */ +- pd.page_flags = cpu_convert_to_target64(0, endian); +- pd.offset = cpu_convert_to_target64(offset_data, endian); ++ pd.page_flags = cpu_to_dump64(s, 0); ++ pd.offset = cpu_to_dump64(s, offset_data); + offset_data += size_out; + + ret = write_cache(&page_desc, &pd, sizeof(PageDescriptor), false); +diff --git a/include/sysemu/dump-arch.h b/include/sysemu/dump-arch.h +new file mode 100644 +index 0000000..9c95ced +--- /dev/null ++++ b/include/sysemu/dump-arch.h +@@ -0,0 +1,28 @@ ++/* ++ * QEMU dump ++ * ++ * Copyright Fujitsu, Corp. 2011, 2012 ++ * ++ * Authors: ++ * Wen Congyang ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ */ ++ ++#ifndef DUMP_ARCH_H ++#define DUMP_ARCH_H ++ ++typedef struct ArchDumpInfo { ++ int d_machine; /* Architecture */ ++ int d_endian; /* ELFDATA2LSB or ELFDATA2MSB */ ++ int d_class; /* ELFCLASS32 or ELFCLASS64 */ ++} ArchDumpInfo; ++ ++struct GuestPhysBlockList; /* memory_mapping.h */ ++int cpu_get_dump_info(ArchDumpInfo *info, ++ const struct GuestPhysBlockList *guest_phys_blocks); ++ssize_t cpu_get_note_size(int class, int machine, int nr_cpus); ++ ++#endif +diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h +index 12af557..7e4ec5c 100644 +--- a/include/sysemu/dump.h ++++ b/include/sysemu/dump.h +@@ -43,11 +43,8 @@ + #define PFN_BUFBITMAP (CHAR_BIT * BUFSIZE_BITMAP) + #define BUFSIZE_DATA_CACHE (TARGET_PAGE_SIZE * 4) + +-typedef struct ArchDumpInfo { +- int d_machine; /* Architecture */ +- int d_endian; /* ELFDATA2LSB or ELFDATA2MSB */ +- int d_class; /* ELFCLASS32 or ELFCLASS64 */ +-} ArchDumpInfo; ++#include "sysemu/dump-arch.h" ++#include "sysemu/memory_mapping.h" + + typedef struct QEMU_PACKED MakedumpfileHeader { + char signature[16]; /* = "makedumpfile" */ +@@ -158,9 +155,37 @@ typedef struct QEMU_PACKED PageDescriptor { + uint64_t page_flags; /* page flags */ + } PageDescriptor; + +-struct GuestPhysBlockList; /* memory_mapping.h */ +-int cpu_get_dump_info(ArchDumpInfo *info, +- const struct GuestPhysBlockList *guest_phys_blocks); +-ssize_t cpu_get_note_size(int class, int machine, int nr_cpus); +- ++typedef struct DumpState { ++ GuestPhysBlockList guest_phys_blocks; ++ ArchDumpInfo dump_info; ++ MemoryMappingList list; ++ uint16_t phdr_num; ++ uint32_t sh_info; ++ bool have_section; ++ bool resume; ++ ssize_t note_size; ++ hwaddr memory_offset; ++ int fd; ++ ++ GuestPhysBlock *next_block; ++ ram_addr_t start; ++ bool has_filter; ++ int64_t begin; ++ int64_t length; ++ ++ uint8_t *note_buf; /* buffer for notes */ ++ size_t note_buf_offset; /* the writing place in note_buf */ ++ uint32_t nr_cpus; /* number of guest's cpu */ ++ uint64_t max_mapnr; /* the biggest guest's phys-mem's number */ ++ size_t len_dump_bitmap; /* the size of the place used to store ++ dump_bitmap in vmcore */ ++ off_t offset_dump_bitmap; /* offset of dump_bitmap part in vmcore */ ++ off_t offset_page; /* offset of page part in vmcore */ ++ size_t num_dumpable; /* number of page that can be dumped */ ++ uint32_t flag_compress; /* indicate the compression format */ ++} DumpState; ++ ++uint16_t cpu_to_dump16(DumpState *s, uint16_t val); ++uint32_t cpu_to_dump32(DumpState *s, uint32_t val); ++uint64_t cpu_to_dump64(DumpState *s, uint64_t val); + #endif +diff --git a/stubs/dump.c b/stubs/dump.c +index 370cd96..fac7019 100644 +--- a/stubs/dump.c ++++ b/stubs/dump.c +@@ -12,7 +12,7 @@ + */ + + #include "qemu-common.h" +-#include "sysemu/dump.h" ++#include "sysemu/dump-arch.h" + #include "qapi/qmp/qerror.h" + #include "qmp-commands.h" + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-dump-Propagate-errors-into-qmp_dump_guest_memory.patch b/SOURCES/kvm-dump-Propagate-errors-into-qmp_dump_guest_memory.patch new file mode 100644 index 0000000..0808cfb --- /dev/null +++ b/SOURCES/kvm-dump-Propagate-errors-into-qmp_dump_guest_memory.patch @@ -0,0 +1,692 @@ +From 888eb5bb28377bc392629e34133bf5bc50b0554f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:49 +0100 +Subject: [PATCH 18/41] dump: Propagate errors into qmp_dump_guest_memory() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-19-marcandre.lureau@redhat.com> +Patchwork-id: 78367 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 18/41] dump: Propagate errors into qmp_dump_guest_memory() +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: zhanghailiang + +The code calls dump_error() on error, and even passes it a suitable +message. However, the message is thrown away, and its callers pass +up only success/failure. All qmp_dump_guest_memory() can do is set +a generic error. + +Propagate the errors properly, so qmp_dump_guest_memory() can return +a more useful error. + +Signed-off-by: zhanghailiang +Reviewed-by: Eric Blake +Reviewed-by: Markus Armbruster +Signed-off-by: Luiz Capitulino + +(cherry picked from commit 37917da2d071ab5273703f5169b0b2fefd40cbb5) +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + dump.c | 165 ++++++++++++++++++++++++++++++++--------------------------------- + 1 file changed, 82 insertions(+), 83 deletions(-) + +diff --git a/dump.c b/dump.c +index c709fc2..3718a79 100644 +--- a/dump.c ++++ b/dump.c +@@ -81,9 +81,10 @@ static int dump_cleanup(DumpState *s) + return 0; + } + +-static void dump_error(DumpState *s, const char *reason) ++static void dump_error(DumpState *s, const char *reason, Error **errp) + { + dump_cleanup(s); ++ error_setg(errp, "%s", reason); + } + + static int fd_write_vmcore(const void *buf, size_t size, void *opaque) +@@ -99,7 +100,7 @@ static int fd_write_vmcore(const void *buf, size_t size, void *opaque) + return 0; + } + +-static int write_elf64_header(DumpState *s) ++static int write_elf64_header(DumpState *s, Error **errp) + { + Elf64_Ehdr elf_header; + int ret; +@@ -126,14 +127,14 @@ static int write_elf64_header(DumpState *s) + + ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s); + if (ret < 0) { +- dump_error(s, "dump: failed to write elf header.\n"); ++ dump_error(s, "dump: failed to write elf header", errp); + return -1; + } + + return 0; + } + +-static int write_elf32_header(DumpState *s) ++static int write_elf32_header(DumpState *s, Error **errp) + { + Elf32_Ehdr elf_header; + int ret; +@@ -160,7 +161,7 @@ static int write_elf32_header(DumpState *s) + + ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s); + if (ret < 0) { +- dump_error(s, "dump: failed to write elf header.\n"); ++ dump_error(s, "dump: failed to write elf header", errp); + return -1; + } + +@@ -169,7 +170,7 @@ static int write_elf32_header(DumpState *s) + + static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping, + int phdr_index, hwaddr offset, +- hwaddr filesz) ++ hwaddr filesz, Error **errp) + { + Elf64_Phdr phdr; + int ret; +@@ -186,7 +187,7 @@ static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping, + + ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s); + if (ret < 0) { +- dump_error(s, "dump: failed to write program header table.\n"); ++ dump_error(s, "dump: failed to write program header table", errp); + return -1; + } + +@@ -195,7 +196,7 @@ static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping, + + static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping, + int phdr_index, hwaddr offset, +- hwaddr filesz) ++ hwaddr filesz, Error **errp) + { + Elf32_Phdr phdr; + int ret; +@@ -212,14 +213,14 @@ static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping, + + ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s); + if (ret < 0) { +- dump_error(s, "dump: failed to write program header table.\n"); ++ dump_error(s, "dump: failed to write program header table", errp); + return -1; + } + + return 0; + } + +-static int write_elf64_note(DumpState *s) ++static int write_elf64_note(DumpState *s, Error **errp) + { + Elf64_Phdr phdr; + hwaddr begin = s->memory_offset - s->note_size; +@@ -235,7 +236,7 @@ static int write_elf64_note(DumpState *s) + + ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s); + if (ret < 0) { +- dump_error(s, "dump: failed to write program header table.\n"); ++ dump_error(s, "dump: failed to write program header table", errp); + return -1; + } + +@@ -247,7 +248,8 @@ static inline int cpu_index(CPUState *cpu) + return cpu->cpu_index + 1; + } + +-static int write_elf64_notes(WriteCoreDumpFunction f, DumpState *s) ++static int write_elf64_notes(WriteCoreDumpFunction f, DumpState *s, ++ Error **errp) + { + CPUArchState *env; + CPUState *cpu; +@@ -259,7 +261,7 @@ static int write_elf64_notes(WriteCoreDumpFunction f, DumpState *s) + id = cpu_index(cpu); + ret = cpu_write_elf64_note(f, cpu, id, s); + if (ret < 0) { +- dump_error(s, "dump: failed to write elf notes.\n"); ++ dump_error(s, "dump: failed to write elf notes", errp); + return -1; + } + } +@@ -268,7 +270,7 @@ static int write_elf64_notes(WriteCoreDumpFunction f, DumpState *s) + cpu = ENV_GET_CPU(env); + ret = cpu_write_elf64_qemunote(f, cpu, s); + if (ret < 0) { +- dump_error(s, "dump: failed to write CPU status.\n"); ++ dump_error(s, "dump: failed to write CPU status", errp); + return -1; + } + } +@@ -276,7 +278,7 @@ static int write_elf64_notes(WriteCoreDumpFunction f, DumpState *s) + return 0; + } + +-static int write_elf32_note(DumpState *s) ++static int write_elf32_note(DumpState *s, Error **errp) + { + hwaddr begin = s->memory_offset - s->note_size; + Elf32_Phdr phdr; +@@ -292,14 +294,15 @@ static int write_elf32_note(DumpState *s) + + ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s); + if (ret < 0) { +- dump_error(s, "dump: failed to write program header table.\n"); ++ dump_error(s, "dump: failed to write program header table", errp); + return -1; + } + + return 0; + } + +-static int write_elf32_notes(WriteCoreDumpFunction f, DumpState *s) ++static int write_elf32_notes(WriteCoreDumpFunction f, DumpState *s, ++ Error **errp) + { + CPUArchState *env; + CPUState *cpu; +@@ -311,7 +314,7 @@ static int write_elf32_notes(WriteCoreDumpFunction f, DumpState *s) + id = cpu_index(cpu); + ret = cpu_write_elf32_note(f, cpu, id, s); + if (ret < 0) { +- dump_error(s, "dump: failed to write elf notes.\n"); ++ dump_error(s, "dump: failed to write elf notes", errp); + return -1; + } + } +@@ -320,7 +323,7 @@ static int write_elf32_notes(WriteCoreDumpFunction f, DumpState *s) + cpu = ENV_GET_CPU(env); + ret = cpu_write_elf32_qemunote(f, cpu, s); + if (ret < 0) { +- dump_error(s, "dump: failed to write CPU status.\n"); ++ dump_error(s, "dump: failed to write CPU status", errp); + return -1; + } + } +@@ -328,7 +331,7 @@ static int write_elf32_notes(WriteCoreDumpFunction f, DumpState *s) + return 0; + } + +-static int write_elf_section(DumpState *s, int type) ++static int write_elf_section(DumpState *s, int type, Error **errp) + { + Elf32_Shdr shdr32; + Elf64_Shdr shdr64; +@@ -350,20 +353,20 @@ static int write_elf_section(DumpState *s, int type) + + ret = fd_write_vmcore(&shdr, shdr_size, s); + if (ret < 0) { +- dump_error(s, "dump: failed to write section header table.\n"); ++ dump_error(s, "dump: failed to write section header table", errp); + return -1; + } + + return 0; + } + +-static int write_data(DumpState *s, void *buf, int length) ++static int write_data(DumpState *s, void *buf, int length, Error **errp) + { + int ret; + + ret = fd_write_vmcore(buf, length, s); + if (ret < 0) { +- dump_error(s, "dump: failed to save memory.\n"); ++ dump_error(s, "dump: failed to save memory", errp); + return -1; + } + +@@ -372,14 +375,14 @@ static int write_data(DumpState *s, void *buf, int length) + + /* write the memroy to vmcore. 1 page per I/O. */ + static int write_memory(DumpState *s, GuestPhysBlock *block, ram_addr_t start, +- int64_t size) ++ int64_t size, Error **errp) + { + int64_t i; + int ret; + + for (i = 0; i < size / TARGET_PAGE_SIZE; i++) { + ret = write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE, +- TARGET_PAGE_SIZE); ++ TARGET_PAGE_SIZE, errp); + if (ret < 0) { + return ret; + } +@@ -387,7 +390,7 @@ static int write_memory(DumpState *s, GuestPhysBlock *block, ram_addr_t start, + + if ((size % TARGET_PAGE_SIZE) != 0) { + ret = write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE, +- size % TARGET_PAGE_SIZE); ++ size % TARGET_PAGE_SIZE, errp); + if (ret < 0) { + return ret; + } +@@ -458,7 +461,7 @@ static void get_offset_range(hwaddr phys_addr, + } + } + +-static int write_elf_loads(DumpState *s) ++static int write_elf_loads(DumpState *s, Error **errp) + { + hwaddr offset, filesz; + MemoryMapping *memory_mapping; +@@ -478,10 +481,10 @@ static int write_elf_loads(DumpState *s) + s, &offset, &filesz); + if (s->dump_info.d_class == ELFCLASS64) { + ret = write_elf64_load(s, memory_mapping, phdr_index++, offset, +- filesz); ++ filesz, errp); + } else { + ret = write_elf32_load(s, memory_mapping, phdr_index++, offset, +- filesz); ++ filesz, errp); + } + + if (ret < 0) { +@@ -497,7 +500,7 @@ static int write_elf_loads(DumpState *s) + } + + /* write elf header, PT_NOTE and elf note to vmcore. */ +-static int dump_begin(DumpState *s) ++static int dump_begin(DumpState *s, Error **errp) + { + int ret; + +@@ -527,9 +530,9 @@ static int dump_begin(DumpState *s) + + /* write elf header to vmcore */ + if (s->dump_info.d_class == ELFCLASS64) { +- ret = write_elf64_header(s); ++ ret = write_elf64_header(s, errp); + } else { +- ret = write_elf32_header(s); ++ ret = write_elf32_header(s, errp); + } + if (ret < 0) { + return -1; +@@ -537,47 +540,47 @@ static int dump_begin(DumpState *s) + + if (s->dump_info.d_class == ELFCLASS64) { + /* write PT_NOTE to vmcore */ +- if (write_elf64_note(s) < 0) { ++ if (write_elf64_note(s, errp) < 0) { + return -1; + } + + /* write all PT_LOAD to vmcore */ +- if (write_elf_loads(s) < 0) { ++ if (write_elf_loads(s, errp) < 0) { + return -1; + } + + /* write section to vmcore */ + if (s->have_section) { +- if (write_elf_section(s, 1) < 0) { ++ if (write_elf_section(s, 1, errp) < 0) { + return -1; + } + } + + /* write notes to vmcore */ +- if (write_elf64_notes(fd_write_vmcore, s) < 0) { ++ if (write_elf64_notes(fd_write_vmcore, s, errp) < 0) { + return -1; + } + + } else { + /* write PT_NOTE to vmcore */ +- if (write_elf32_note(s) < 0) { ++ if (write_elf32_note(s, errp) < 0) { + return -1; + } + + /* write all PT_LOAD to vmcore */ +- if (write_elf_loads(s) < 0) { ++ if (write_elf_loads(s, errp) < 0) { + return -1; + } + + /* write section to vmcore */ + if (s->have_section) { +- if (write_elf_section(s, 0) < 0) { ++ if (write_elf_section(s, 0, errp) < 0) { + return -1; + } + } + + /* write notes to vmcore */ +- if (write_elf32_notes(fd_write_vmcore, s) < 0) { ++ if (write_elf32_notes(fd_write_vmcore, s, errp) < 0) { + return -1; + } + } +@@ -620,7 +623,7 @@ static int get_next_block(DumpState *s, GuestPhysBlock *block) + } + + /* write all memory to vmcore */ +-static int dump_iterate(DumpState *s) ++static int dump_iterate(DumpState *s, Error **errp) + { + GuestPhysBlock *block; + int64_t size; +@@ -636,7 +639,7 @@ static int dump_iterate(DumpState *s) + size -= block->target_end - (s->begin + s->length); + } + } +- ret = write_memory(s, block, s->start, size); ++ ret = write_memory(s, block, s->start, size, errp); + if (ret == -1) { + return ret; + } +@@ -649,16 +652,16 @@ static int dump_iterate(DumpState *s) + } + } + +-static int create_vmcore(DumpState *s) ++static int create_vmcore(DumpState *s, Error **errp) + { + int ret; + +- ret = dump_begin(s); ++ ret = dump_begin(s, errp); + if (ret < 0) { + return -1; + } + +- ret = dump_iterate(s); ++ ret = dump_iterate(s, errp); + if (ret < 0) { + return -1; + } +@@ -744,7 +747,7 @@ static int buf_write_note(const void *buf, size_t size, void *opaque) + } + + /* write common header, sub header and elf note to vmcore */ +-static int create_header32(DumpState *s) ++static int create_header32(DumpState *s, Error **errp) + { + int ret = 0; + DiskDumpHeader32 *dh = NULL; +@@ -790,7 +793,7 @@ static int create_header32(DumpState *s) + dh->status = cpu_to_dump32(s, status); + + if (write_buffer(s->fd, 0, dh, size) < 0) { +- dump_error(s, "dump: failed to write disk dump header.\n"); ++ dump_error(s, "dump: failed to write disk dump header", errp); + ret = -1; + goto out; + } +@@ -810,7 +813,7 @@ static int create_header32(DumpState *s) + + if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS * + block_size, kh, size) < 0) { +- dump_error(s, "dump: failed to write kdump sub header.\n"); ++ dump_error(s, "dump: failed to write kdump sub header", errp); + ret = -1; + goto out; + } +@@ -820,14 +823,14 @@ static int create_header32(DumpState *s) + s->note_buf_offset = 0; + + /* use s->note_buf to store notes temporarily */ +- if (write_elf32_notes(buf_write_note, s) < 0) { ++ if (write_elf32_notes(buf_write_note, s, errp) < 0) { + ret = -1; + goto out; + } + + if (write_buffer(s->fd, offset_note, s->note_buf, + s->note_size) < 0) { +- dump_error(s, "dump: failed to write notes"); ++ dump_error(s, "dump: failed to write notes", errp); + ret = -1; + goto out; + } +@@ -849,7 +852,7 @@ out: + } + + /* write common header, sub header and elf note to vmcore */ +-static int create_header64(DumpState *s) ++static int create_header64(DumpState *s, Error **errp) + { + int ret = 0; + DiskDumpHeader64 *dh = NULL; +@@ -895,7 +898,7 @@ static int create_header64(DumpState *s) + dh->status = cpu_to_dump32(s, status); + + if (write_buffer(s->fd, 0, dh, size) < 0) { +- dump_error(s, "dump: failed to write disk dump header.\n"); ++ dump_error(s, "dump: failed to write disk dump header", errp); + ret = -1; + goto out; + } +@@ -915,7 +918,7 @@ static int create_header64(DumpState *s) + + if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS * + block_size, kh, size) < 0) { +- dump_error(s, "dump: failed to write kdump sub header.\n"); ++ dump_error(s, "dump: failed to write kdump sub header", errp); + ret = -1; + goto out; + } +@@ -925,14 +928,14 @@ static int create_header64(DumpState *s) + s->note_buf_offset = 0; + + /* use s->note_buf to store notes temporarily */ +- if (write_elf64_notes(buf_write_note, s) < 0) { ++ if (write_elf64_notes(buf_write_note, s, errp) < 0) { + ret = -1; + goto out; + } + + if (write_buffer(s->fd, offset_note, s->note_buf, + s->note_size) < 0) { +- dump_error(s, "dump: failed to write notes"); ++ dump_error(s, "dump: failed to write notes", errp); + ret = -1; + goto out; + } +@@ -953,12 +956,12 @@ out: + return ret; + } + +-static int write_dump_header(DumpState *s) ++static int write_dump_header(DumpState *s, Error **errp) + { + if (s->dump_info.d_class == ELFCLASS32) { +- return create_header32(s); ++ return create_header32(s, errp); + } else { +- return create_header64(s); ++ return create_header64(s, errp); + } + } + +@@ -1072,7 +1075,7 @@ static bool get_next_page(GuestPhysBlock **blockptr, uint64_t *pfnptr, + return true; + } + +-static int write_dump_bitmap(DumpState *s) ++static int write_dump_bitmap(DumpState *s, Error **errp) + { + int ret = 0; + uint64_t last_pfn, pfn; +@@ -1093,7 +1096,7 @@ static int write_dump_bitmap(DumpState *s) + while (get_next_page(&block_iter, &pfn, NULL, s)) { + ret = set_dump_bitmap(last_pfn, pfn, true, dump_bitmap_buf, s); + if (ret < 0) { +- dump_error(s, "dump: failed to set dump_bitmap.\n"); ++ dump_error(s, "dump: failed to set dump_bitmap", errp); + ret = -1; + goto out; + } +@@ -1111,7 +1114,7 @@ static int write_dump_bitmap(DumpState *s) + ret = set_dump_bitmap(last_pfn, last_pfn + PFN_BUFBITMAP, false, + dump_bitmap_buf, s); + if (ret < 0) { +- dump_error(s, "dump: failed to sync dump_bitmap.\n"); ++ dump_error(s, "dump: failed to sync dump_bitmap", errp); + ret = -1; + goto out; + } +@@ -1203,7 +1206,7 @@ static inline bool is_zero_page(const uint8_t *buf, size_t page_size) + return buffer_is_zero(buf, page_size); + } + +-static int write_dump_pages(DumpState *s) ++static int write_dump_pages(DumpState *s, Error **errp) + { + int ret = 0; + DataCache page_desc, page_data; +@@ -1247,7 +1250,7 @@ static int write_dump_pages(DumpState *s) + ret = write_cache(&page_data, buf, TARGET_PAGE_SIZE, false); + g_free(buf); + if (ret < 0) { +- dump_error(s, "dump: failed to write page data(zero page).\n"); ++ dump_error(s, "dump: failed to write page data (zero page)", errp); + goto out; + } + +@@ -1263,7 +1266,7 @@ static int write_dump_pages(DumpState *s) + ret = write_cache(&page_desc, &pd_zero, sizeof(PageDescriptor), + false); + if (ret < 0) { +- dump_error(s, "dump: failed to write page desc.\n"); ++ dump_error(s, "dump: failed to write page desc", errp); + goto out; + } + } else { +@@ -1288,7 +1291,7 @@ static int write_dump_pages(DumpState *s) + + ret = write_cache(&page_data, buf_out, size_out, false); + if (ret < 0) { +- dump_error(s, "dump: failed to write page data.\n"); ++ dump_error(s, "dump: failed to write page data", errp); + goto out; + } + #ifdef CONFIG_LZO +@@ -1301,7 +1304,7 @@ static int write_dump_pages(DumpState *s) + + ret = write_cache(&page_data, buf_out, size_out, false); + if (ret < 0) { +- dump_error(s, "dump: failed to write page data.\n"); ++ dump_error(s, "dump: failed to write page data", errp); + goto out; + } + #endif +@@ -1315,7 +1318,7 @@ static int write_dump_pages(DumpState *s) + + ret = write_cache(&page_data, buf_out, size_out, false); + if (ret < 0) { +- dump_error(s, "dump: failed to write page data.\n"); ++ dump_error(s, "dump: failed to write page data", errp); + goto out; + } + #endif +@@ -1330,7 +1333,7 @@ static int write_dump_pages(DumpState *s) + + ret = write_cache(&page_data, buf, TARGET_PAGE_SIZE, false); + if (ret < 0) { +- dump_error(s, "dump: failed to write page data.\n"); ++ dump_error(s, "dump: failed to write page data", errp); + goto out; + } + } +@@ -1342,7 +1345,7 @@ static int write_dump_pages(DumpState *s) + + ret = write_cache(&page_desc, &pd, sizeof(PageDescriptor), false); + if (ret < 0) { +- dump_error(s, "dump: failed to write page desc.\n"); ++ dump_error(s, "dump: failed to write page desc", errp); + goto out; + } + } +@@ -1350,12 +1353,12 @@ static int write_dump_pages(DumpState *s) + + ret = write_cache(&page_desc, NULL, 0, true); + if (ret < 0) { +- dump_error(s, "dump: failed to sync cache for page_desc.\n"); ++ dump_error(s, "dump: failed to sync cache for page_desc", errp); + goto out; + } + ret = write_cache(&page_data, NULL, 0, true); + if (ret < 0) { +- dump_error(s, "dump: failed to sync cache for page_data.\n"); ++ dump_error(s, "dump: failed to sync cache for page_data", errp); + goto out; + } + +@@ -1372,7 +1375,7 @@ out: + return ret; + } + +-static int create_kdump_vmcore(DumpState *s) ++static int create_kdump_vmcore(DumpState *s, Error **errp) + { + int ret; + +@@ -1400,28 +1403,28 @@ static int create_kdump_vmcore(DumpState *s) + + ret = write_start_flat_header(s->fd); + if (ret < 0) { +- dump_error(s, "dump: failed to write start flat header.\n"); ++ dump_error(s, "dump: failed to write start flat header", errp); + return -1; + } + +- ret = write_dump_header(s); ++ ret = write_dump_header(s, errp); + if (ret < 0) { + return -1; + } + +- ret = write_dump_bitmap(s); ++ ret = write_dump_bitmap(s, errp); + if (ret < 0) { + return -1; + } + +- ret = write_dump_pages(s); ++ ret = write_dump_pages(s, errp); + if (ret < 0) { + return -1; + } + + ret = write_end_flat_header(s->fd); + if (ret < 0) { +- dump_error(s, "dump: failed to write end flat header.\n"); ++ dump_error(s, "dump: failed to write end flat header", errp); + return -1; + } + +@@ -1705,13 +1708,9 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin, + } + + if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) { +- if (create_kdump_vmcore(s) < 0) { +- error_set(errp, QERR_IO_ERROR); +- } ++ create_kdump_vmcore(s, errp); + } else { +- if (create_vmcore(s) < 0) { +- error_set(errp, QERR_IO_ERROR); +- } ++ create_vmcore(s, errp); + } + + g_free(s); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-dump-Turn-some-functions-to-void-to-make-code-cleane.patch b/SOURCES/kvm-dump-Turn-some-functions-to-void-to-make-code-cleane.patch new file mode 100644 index 0000000..0d77605 --- /dev/null +++ b/SOURCES/kvm-dump-Turn-some-functions-to-void-to-make-code-cleane.patch @@ -0,0 +1,801 @@ +From 4a4865cb64b429fc95d4466be707c812c7f3ee06 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:50 +0100 +Subject: [PATCH 19/41] dump: Turn some functions to void to make code cleaner +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-20-marcandre.lureau@redhat.com> +Patchwork-id: 78368 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 19/41] dump: Turn some functions to void to make code cleaner +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: zhanghailiang + +Functions shouldn't return an error code and an Error object at the same time. +Turn all these functions that returning Error object to void. +We also judge if a function success or fail by reference to the local_err. + +Signed-off-by: zhanghailiang +Reviewed-by: Eric Blake +Signed-off-by: Luiz Capitulino + +(cherry picked from commit 4c7e251ae6d9c328850d62d8aeafa14ca600c858) +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + dump.c | 312 ++++++++++++++++++++++++++++++----------------------------------- + 1 file changed, 142 insertions(+), 170 deletions(-) + +diff --git a/dump.c b/dump.c +index 3718a79..099346a 100644 +--- a/dump.c ++++ b/dump.c +@@ -100,7 +100,7 @@ static int fd_write_vmcore(const void *buf, size_t size, void *opaque) + return 0; + } + +-static int write_elf64_header(DumpState *s, Error **errp) ++static void write_elf64_header(DumpState *s, Error **errp) + { + Elf64_Ehdr elf_header; + int ret; +@@ -128,13 +128,10 @@ static int write_elf64_header(DumpState *s, Error **errp) + ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s); + if (ret < 0) { + dump_error(s, "dump: failed to write elf header", errp); +- return -1; + } +- +- return 0; + } + +-static int write_elf32_header(DumpState *s, Error **errp) ++static void write_elf32_header(DumpState *s, Error **errp) + { + Elf32_Ehdr elf_header; + int ret; +@@ -162,15 +159,12 @@ static int write_elf32_header(DumpState *s, Error **errp) + ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s); + if (ret < 0) { + dump_error(s, "dump: failed to write elf header", errp); +- return -1; + } +- +- return 0; + } + +-static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping, +- int phdr_index, hwaddr offset, +- hwaddr filesz, Error **errp) ++static void write_elf64_load(DumpState *s, MemoryMapping *memory_mapping, ++ int phdr_index, hwaddr offset, ++ hwaddr filesz, Error **errp) + { + Elf64_Phdr phdr; + int ret; +@@ -188,15 +182,12 @@ static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping, + ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s); + if (ret < 0) { + dump_error(s, "dump: failed to write program header table", errp); +- return -1; + } +- +- return 0; + } + +-static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping, +- int phdr_index, hwaddr offset, +- hwaddr filesz, Error **errp) ++static void write_elf32_load(DumpState *s, MemoryMapping *memory_mapping, ++ int phdr_index, hwaddr offset, ++ hwaddr filesz, Error **errp) + { + Elf32_Phdr phdr; + int ret; +@@ -214,13 +205,10 @@ static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping, + ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s); + if (ret < 0) { + dump_error(s, "dump: failed to write program header table", errp); +- return -1; + } +- +- return 0; + } + +-static int write_elf64_note(DumpState *s, Error **errp) ++static void write_elf64_note(DumpState *s, Error **errp) + { + Elf64_Phdr phdr; + hwaddr begin = s->memory_offset - s->note_size; +@@ -237,10 +225,7 @@ static int write_elf64_note(DumpState *s, Error **errp) + ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s); + if (ret < 0) { + dump_error(s, "dump: failed to write program header table", errp); +- return -1; + } +- +- return 0; + } + + static inline int cpu_index(CPUState *cpu) +@@ -248,8 +233,8 @@ static inline int cpu_index(CPUState *cpu) + return cpu->cpu_index + 1; + } + +-static int write_elf64_notes(WriteCoreDumpFunction f, DumpState *s, +- Error **errp) ++static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s, ++ Error **errp) + { + CPUArchState *env; + CPUState *cpu; +@@ -262,7 +247,7 @@ static int write_elf64_notes(WriteCoreDumpFunction f, DumpState *s, + ret = cpu_write_elf64_note(f, cpu, id, s); + if (ret < 0) { + dump_error(s, "dump: failed to write elf notes", errp); +- return -1; ++ return; + } + } + +@@ -271,14 +256,12 @@ static int write_elf64_notes(WriteCoreDumpFunction f, DumpState *s, + ret = cpu_write_elf64_qemunote(f, cpu, s); + if (ret < 0) { + dump_error(s, "dump: failed to write CPU status", errp); +- return -1; ++ return; + } + } +- +- return 0; + } + +-static int write_elf32_note(DumpState *s, Error **errp) ++static void write_elf32_note(DumpState *s, Error **errp) + { + hwaddr begin = s->memory_offset - s->note_size; + Elf32_Phdr phdr; +@@ -295,14 +278,11 @@ static int write_elf32_note(DumpState *s, Error **errp) + ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s); + if (ret < 0) { + dump_error(s, "dump: failed to write program header table", errp); +- return -1; + } +- +- return 0; + } + +-static int write_elf32_notes(WriteCoreDumpFunction f, DumpState *s, +- Error **errp) ++static void write_elf32_notes(WriteCoreDumpFunction f, DumpState *s, ++ Error **errp) + { + CPUArchState *env; + CPUState *cpu; +@@ -315,7 +295,7 @@ static int write_elf32_notes(WriteCoreDumpFunction f, DumpState *s, + ret = cpu_write_elf32_note(f, cpu, id, s); + if (ret < 0) { + dump_error(s, "dump: failed to write elf notes", errp); +- return -1; ++ return; + } + } + +@@ -324,14 +304,12 @@ static int write_elf32_notes(WriteCoreDumpFunction f, DumpState *s, + ret = cpu_write_elf32_qemunote(f, cpu, s); + if (ret < 0) { + dump_error(s, "dump: failed to write CPU status", errp); +- return -1; ++ return; + } + } +- +- return 0; + } + +-static int write_elf_section(DumpState *s, int type, Error **errp) ++static void write_elf_section(DumpState *s, int type, Error **errp) + { + Elf32_Shdr shdr32; + Elf64_Shdr shdr64; +@@ -354,49 +332,43 @@ static int write_elf_section(DumpState *s, int type, Error **errp) + ret = fd_write_vmcore(&shdr, shdr_size, s); + if (ret < 0) { + dump_error(s, "dump: failed to write section header table", errp); +- return -1; + } +- +- return 0; + } + +-static int write_data(DumpState *s, void *buf, int length, Error **errp) ++static void write_data(DumpState *s, void *buf, int length, Error **errp) + { + int ret; + + ret = fd_write_vmcore(buf, length, s); + if (ret < 0) { + dump_error(s, "dump: failed to save memory", errp); +- return -1; + } +- +- return 0; + } + +-/* write the memroy to vmcore. 1 page per I/O. */ +-static int write_memory(DumpState *s, GuestPhysBlock *block, ram_addr_t start, +- int64_t size, Error **errp) ++/* write the memory to vmcore. 1 page per I/O. */ ++static void write_memory(DumpState *s, GuestPhysBlock *block, ram_addr_t start, ++ int64_t size, Error **errp) + { + int64_t i; +- int ret; ++ Error *local_err = NULL; + + for (i = 0; i < size / TARGET_PAGE_SIZE; i++) { +- ret = write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE, +- TARGET_PAGE_SIZE, errp); +- if (ret < 0) { +- return ret; ++ write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE, ++ TARGET_PAGE_SIZE, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; + } + } + + if ((size % TARGET_PAGE_SIZE) != 0) { +- ret = write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE, +- size % TARGET_PAGE_SIZE, errp); +- if (ret < 0) { +- return ret; ++ write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE, ++ size % TARGET_PAGE_SIZE, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; + } + } +- +- return 0; + } + + /* get the memory's offset and size in the vmcore */ +@@ -461,13 +433,13 @@ static void get_offset_range(hwaddr phys_addr, + } + } + +-static int write_elf_loads(DumpState *s, Error **errp) ++static void write_elf_loads(DumpState *s, Error **errp) + { + hwaddr offset, filesz; + MemoryMapping *memory_mapping; + uint32_t phdr_index = 1; +- int ret; + uint32_t max_index; ++ Error *local_err = NULL; + + if (s->have_section) { + max_index = s->sh_info; +@@ -480,29 +452,28 @@ static int write_elf_loads(DumpState *s, Error **errp) + memory_mapping->length, + s, &offset, &filesz); + if (s->dump_info.d_class == ELFCLASS64) { +- ret = write_elf64_load(s, memory_mapping, phdr_index++, offset, +- filesz, errp); ++ write_elf64_load(s, memory_mapping, phdr_index++, offset, ++ filesz, &local_err); + } else { +- ret = write_elf32_load(s, memory_mapping, phdr_index++, offset, +- filesz, errp); ++ write_elf32_load(s, memory_mapping, phdr_index++, offset, ++ filesz, &local_err); + } + +- if (ret < 0) { +- return -1; ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; + } + + if (phdr_index >= max_index) { + break; + } + } +- +- return 0; + } + + /* write elf header, PT_NOTE and elf note to vmcore. */ +-static int dump_begin(DumpState *s, Error **errp) ++static void dump_begin(DumpState *s, Error **errp) + { +- int ret; ++ Error *local_err = NULL; + + /* + * the vmcore's format is: +@@ -530,69 +501,81 @@ static int dump_begin(DumpState *s, Error **errp) + + /* write elf header to vmcore */ + if (s->dump_info.d_class == ELFCLASS64) { +- ret = write_elf64_header(s, errp); ++ write_elf64_header(s, &local_err); + } else { +- ret = write_elf32_header(s, errp); ++ write_elf32_header(s, &local_err); + } +- if (ret < 0) { +- return -1; ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; + } + + if (s->dump_info.d_class == ELFCLASS64) { + /* write PT_NOTE to vmcore */ +- if (write_elf64_note(s, errp) < 0) { +- return -1; ++ write_elf64_note(s, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; + } + + /* write all PT_LOAD to vmcore */ +- if (write_elf_loads(s, errp) < 0) { +- return -1; ++ write_elf_loads(s, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; + } + + /* write section to vmcore */ + if (s->have_section) { +- if (write_elf_section(s, 1, errp) < 0) { +- return -1; ++ write_elf_section(s, 1, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; + } + } + + /* write notes to vmcore */ +- if (write_elf64_notes(fd_write_vmcore, s, errp) < 0) { +- return -1; ++ write_elf64_notes(fd_write_vmcore, s, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; + } +- + } else { + /* write PT_NOTE to vmcore */ +- if (write_elf32_note(s, errp) < 0) { +- return -1; ++ write_elf32_note(s, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; + } + + /* write all PT_LOAD to vmcore */ +- if (write_elf_loads(s, errp) < 0) { +- return -1; ++ write_elf_loads(s, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; + } + + /* write section to vmcore */ + if (s->have_section) { +- if (write_elf_section(s, 0, errp) < 0) { +- return -1; ++ write_elf_section(s, 0, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; + } + } + + /* write notes to vmcore */ +- if (write_elf32_notes(fd_write_vmcore, s, errp) < 0) { +- return -1; ++ write_elf32_notes(fd_write_vmcore, s, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; + } + } +- +- return 0; + } + +-/* write PT_LOAD to vmcore */ +-static int dump_completed(DumpState *s) ++static void dump_completed(DumpState *s) + { + dump_cleanup(s); +- return 0; + } + + static int get_next_block(DumpState *s, GuestPhysBlock *block) +@@ -623,11 +606,12 @@ static int get_next_block(DumpState *s, GuestPhysBlock *block) + } + + /* write all memory to vmcore */ +-static int dump_iterate(DumpState *s, Error **errp) ++static void dump_iterate(DumpState *s, Error **errp) + { + GuestPhysBlock *block; + int64_t size; + int ret; ++ Error *local_err = NULL; + + while (1) { + block = s->next_block; +@@ -639,34 +623,30 @@ static int dump_iterate(DumpState *s, Error **errp) + size -= block->target_end - (s->begin + s->length); + } + } +- ret = write_memory(s, block, s->start, size, errp); +- if (ret == -1) { +- return ret; ++ write_memory(s, block, s->start, size, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; + } + + ret = get_next_block(s, block); + if (ret == 1) { + dump_completed(s); +- return 0; + } + } + } + +-static int create_vmcore(DumpState *s, Error **errp) ++static void create_vmcore(DumpState *s, Error **errp) + { +- int ret; ++ Error *local_err = NULL; + +- ret = dump_begin(s, errp); +- if (ret < 0) { +- return -1; +- } +- +- ret = dump_iterate(s, errp); +- if (ret < 0) { +- return -1; ++ dump_begin(s, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; + } + +- return 0; ++ dump_iterate(s, errp); + } + + static int write_start_flat_header(int fd) +@@ -747,9 +727,8 @@ static int buf_write_note(const void *buf, size_t size, void *opaque) + } + + /* write common header, sub header and elf note to vmcore */ +-static int create_header32(DumpState *s, Error **errp) ++static void create_header32(DumpState *s, Error **errp) + { +- int ret = 0; + DiskDumpHeader32 *dh = NULL; + KdumpSubHeader32 *kh = NULL; + size_t size; +@@ -758,6 +737,7 @@ static int create_header32(DumpState *s, Error **errp) + uint32_t bitmap_blocks; + uint32_t status = 0; + uint64_t offset_note; ++ Error *local_err = NULL; + + /* write common header, the version of kdump-compressed format is 6th */ + size = sizeof(DiskDumpHeader32); +@@ -794,7 +774,6 @@ static int create_header32(DumpState *s, Error **errp) + + if (write_buffer(s->fd, 0, dh, size) < 0) { + dump_error(s, "dump: failed to write disk dump header", errp); +- ret = -1; + goto out; + } + +@@ -814,7 +793,6 @@ static int create_header32(DumpState *s, Error **errp) + if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS * + block_size, kh, size) < 0) { + dump_error(s, "dump: failed to write kdump sub header", errp); +- ret = -1; + goto out; + } + +@@ -823,15 +801,14 @@ static int create_header32(DumpState *s, Error **errp) + s->note_buf_offset = 0; + + /* use s->note_buf to store notes temporarily */ +- if (write_elf32_notes(buf_write_note, s, errp) < 0) { +- ret = -1; ++ write_elf32_notes(buf_write_note, s, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); + goto out; + } +- + if (write_buffer(s->fd, offset_note, s->note_buf, + s->note_size) < 0) { + dump_error(s, "dump: failed to write notes", errp); +- ret = -1; + goto out; + } + +@@ -847,14 +824,11 @@ out: + g_free(dh); + g_free(kh); + g_free(s->note_buf); +- +- return ret; + } + + /* write common header, sub header and elf note to vmcore */ +-static int create_header64(DumpState *s, Error **errp) ++static void create_header64(DumpState *s, Error **errp) + { +- int ret = 0; + DiskDumpHeader64 *dh = NULL; + KdumpSubHeader64 *kh = NULL; + size_t size; +@@ -863,6 +837,7 @@ static int create_header64(DumpState *s, Error **errp) + uint32_t bitmap_blocks; + uint32_t status = 0; + uint64_t offset_note; ++ Error *local_err = NULL; + + /* write common header, the version of kdump-compressed format is 6th */ + size = sizeof(DiskDumpHeader64); +@@ -899,7 +874,6 @@ static int create_header64(DumpState *s, Error **errp) + + if (write_buffer(s->fd, 0, dh, size) < 0) { + dump_error(s, "dump: failed to write disk dump header", errp); +- ret = -1; + goto out; + } + +@@ -919,7 +893,6 @@ static int create_header64(DumpState *s, Error **errp) + if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS * + block_size, kh, size) < 0) { + dump_error(s, "dump: failed to write kdump sub header", errp); +- ret = -1; + goto out; + } + +@@ -928,15 +901,15 @@ static int create_header64(DumpState *s, Error **errp) + s->note_buf_offset = 0; + + /* use s->note_buf to store notes temporarily */ +- if (write_elf64_notes(buf_write_note, s, errp) < 0) { +- ret = -1; ++ write_elf64_notes(buf_write_note, s, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); + goto out; + } + + if (write_buffer(s->fd, offset_note, s->note_buf, + s->note_size) < 0) { + dump_error(s, "dump: failed to write notes", errp); +- ret = -1; + goto out; + } + +@@ -952,16 +925,19 @@ out: + g_free(dh); + g_free(kh); + g_free(s->note_buf); +- +- return ret; + } + +-static int write_dump_header(DumpState *s, Error **errp) ++static void write_dump_header(DumpState *s, Error **errp) + { ++ Error *local_err = NULL; ++ + if (s->dump_info.d_class == ELFCLASS32) { +- return create_header32(s, errp); ++ create_header32(s, &local_err); + } else { +- return create_header64(s, errp); ++ create_header64(s, &local_err); ++ } ++ if (local_err) { ++ error_propagate(errp, local_err); + } + } + +@@ -1075,7 +1051,7 @@ static bool get_next_page(GuestPhysBlock **blockptr, uint64_t *pfnptr, + return true; + } + +-static int write_dump_bitmap(DumpState *s, Error **errp) ++static void write_dump_bitmap(DumpState *s, Error **errp) + { + int ret = 0; + uint64_t last_pfn, pfn; +@@ -1097,7 +1073,6 @@ static int write_dump_bitmap(DumpState *s, Error **errp) + ret = set_dump_bitmap(last_pfn, pfn, true, dump_bitmap_buf, s); + if (ret < 0) { + dump_error(s, "dump: failed to set dump_bitmap", errp); +- ret = -1; + goto out; + } + +@@ -1115,7 +1090,6 @@ static int write_dump_bitmap(DumpState *s, Error **errp) + dump_bitmap_buf, s); + if (ret < 0) { + dump_error(s, "dump: failed to sync dump_bitmap", errp); +- ret = -1; + goto out; + } + } +@@ -1125,8 +1099,6 @@ static int write_dump_bitmap(DumpState *s, Error **errp) + + out: + g_free(dump_bitmap_buf); +- +- return ret; + } + + static void prepare_data_cache(DataCache *data_cache, DumpState *s, +@@ -1206,7 +1178,7 @@ static inline bool is_zero_page(const uint8_t *buf, size_t page_size) + return buffer_is_zero(buf, page_size); + } + +-static int write_dump_pages(DumpState *s, Error **errp) ++static void write_dump_pages(DumpState *s, Error **errp) + { + int ret = 0; + DataCache page_desc, page_data; +@@ -1371,13 +1343,12 @@ out: + #endif + + g_free(buf_out); +- +- return ret; + } + +-static int create_kdump_vmcore(DumpState *s, Error **errp) ++static void create_kdump_vmcore(DumpState *s, Error **errp) + { + int ret; ++ Error *local_err = NULL; + + /* + * the kdump-compressed format is: +@@ -1404,33 +1375,34 @@ static int create_kdump_vmcore(DumpState *s, Error **errp) + ret = write_start_flat_header(s->fd); + if (ret < 0) { + dump_error(s, "dump: failed to write start flat header", errp); +- return -1; ++ return; + } + +- ret = write_dump_header(s, errp); +- if (ret < 0) { +- return -1; ++ write_dump_header(s, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; + } + +- ret = write_dump_bitmap(s, errp); +- if (ret < 0) { +- return -1; ++ write_dump_bitmap(s, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; + } + +- ret = write_dump_pages(s, errp); +- if (ret < 0) { +- return -1; ++ write_dump_pages(s, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; + } + + ret = write_end_flat_header(s->fd); + if (ret < 0) { + dump_error(s, "dump: failed to write end flat header", errp); +- return -1; ++ return; + } + + dump_completed(s); +- +- return 0; + } + + static ram_addr_t get_start_block(DumpState *s) +@@ -1469,9 +1441,9 @@ static void get_max_mapnr(DumpState *s) + s->max_mapnr = paddr_to_pfn(last_block->target_end); + } + +-static int dump_init(DumpState *s, int fd, bool has_format, +- DumpGuestMemoryFormat format, bool paging, bool has_filter, +- int64_t begin, int64_t length, Error **errp) ++static void dump_init(DumpState *s, int fd, bool has_format, ++ DumpGuestMemoryFormat format, bool paging, bool has_filter, ++ int64_t begin, int64_t length, Error **errp) + { + CPUArchState *env; + int nr_cpus; +@@ -1576,7 +1548,7 @@ static int dump_init(DumpState *s, int fd, bool has_format, + s->flag_compress = 0; + } + +- return 0; ++ return; + } + + if (s->has_filter) { +@@ -1625,11 +1597,10 @@ static int dump_init(DumpState *s, int fd, bool has_format, + } + } + +- return 0; ++ return; + + cleanup: + dump_cleanup(s); +- return -1; + } + + void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin, +@@ -1640,7 +1611,7 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin, + const char *p; + int fd = -1; + DumpState *s; +- int ret; ++ Error *local_err = NULL; + + /* + * kdump-compressed format need the whole memory dumped, so paging or +@@ -1700,10 +1671,11 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin, + + s = g_malloc0(sizeof(DumpState)); + +- ret = dump_init(s, fd, has_format, format, paging, has_begin, +- begin, length, errp); +- if (ret < 0) { ++ dump_init(s, fd, has_format, format, paging, has_begin, ++ begin, length, &local_err); ++ if (local_err) { + g_free(s); ++ error_propagate(errp, local_err); + return; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-dump-add-guest-ELF-note.patch b/SOURCES/kvm-dump-add-guest-ELF-note.patch new file mode 100644 index 0000000..1a2f29e --- /dev/null +++ b/SOURCES/kvm-dump-add-guest-ELF-note.patch @@ -0,0 +1,226 @@ +From 693375003f594a1d19acd35df19141b92a5c8822 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:39:01 +0100 +Subject: [PATCH 30/41] dump: add guest ELF note +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-31-marcandre.lureau@redhat.com> +Patchwork-id: 78377 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 30/41] dump: add guest ELF note +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +Read the guest ELF PT_NOTE from guest memory when fw_cfg +etc/vmcoreinfo entry provides the location, and write it as an +additional note in the dump. + +Signed-off-by: Marc-André Lureau +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin + +(cherry picked from commit 903ef7349699dcd932b5981b85c1f1ebe4a4bf2a) + +RHEL: Minor conflicts due to "detach" mode not being backported. + Replace warn_report() with error_report(). + +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + dump.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++ + include/sysemu/dump.h | 2 + + 2 files changed, 108 insertions(+) + +diff --git a/dump.c b/dump.c +index d629c8d..823d1ad 100644 +--- a/dump.c ++++ b/dump.c +@@ -24,6 +24,7 @@ + #include "sysemu/cpus.h" + #include "qapi/error.h" + #include "qmp-commands.h" ++#include "hw/misc/vmcoreinfo.h" + + #include + #ifdef CONFIG_LZO +@@ -36,6 +37,13 @@ + #define ELF_MACHINE_UNAME "Unknown" + #endif + ++#define MAX_GUEST_NOTE_SIZE (1 << 20) /* 1MB should be enough */ ++ ++#define ELF_NOTE_SIZE(hdr_size, name_size, desc_size) \ ++ ((DIV_ROUND_UP((hdr_size), 4) + \ ++ DIV_ROUND_UP((name_size), 4) + \ ++ DIV_ROUND_UP((desc_size), 4)) * 4) ++ + uint16_t cpu_to_dump16(DumpState *s, uint16_t val) + { + if (s->dump_info.d_endian == ELFDATA2LSB) { +@@ -74,6 +82,8 @@ static int dump_cleanup(DumpState *s) + guest_phys_blocks_free(&s->guest_phys_blocks); + memory_mapping_list_free(&s->list); + close(s->fd); ++ g_free(s->guest_note); ++ s->guest_note = NULL; + if (s->resume) { + vm_start(); + } +@@ -227,6 +237,19 @@ static inline int cpu_index(CPUState *cpu) + return cpu->cpu_index + 1; + } + ++static void write_guest_note(WriteCoreDumpFunction f, DumpState *s, ++ Error **errp) ++{ ++ int ret; ++ ++ if (s->guest_note) { ++ ret = f(s->guest_note, s->guest_note_size, s); ++ if (ret < 0) { ++ error_setg(errp, "dump: failed to write guest note"); ++ } ++ } ++} ++ + static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s, + Error **errp) + { +@@ -253,6 +276,8 @@ static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s, + return; + } + } ++ ++ write_guest_note(f, s, errp); + } + + static void write_elf32_note(DumpState *s, Error **errp) +@@ -301,6 +326,8 @@ static void write_elf32_notes(WriteCoreDumpFunction f, DumpState *s, + return; + } + } ++ ++ write_guest_note(f, s, errp); + } + + static void write_elf_section(DumpState *s, int type, Error **errp) +@@ -712,6 +739,44 @@ static int buf_write_note(const void *buf, size_t size, void *opaque) + return 0; + } + ++/* ++ * This function retrieves various sizes from an elf header. ++ * ++ * @note has to be a valid ELF note. The return sizes are unmodified ++ * (not padded or rounded up to be multiple of 4). ++ */ ++static void get_note_sizes(DumpState *s, const void *note, ++ uint64_t *note_head_size, ++ uint64_t *name_size, ++ uint64_t *desc_size) ++{ ++ uint64_t note_head_sz; ++ uint64_t name_sz; ++ uint64_t desc_sz; ++ ++ if (s->dump_info.d_class == ELFCLASS64) { ++ const Elf64_Nhdr *hdr = note; ++ note_head_sz = sizeof(Elf64_Nhdr); ++ name_sz = tswap64(hdr->n_namesz); ++ desc_sz = tswap64(hdr->n_descsz); ++ } else { ++ const Elf32_Nhdr *hdr = note; ++ note_head_sz = sizeof(Elf32_Nhdr); ++ name_sz = tswap32(hdr->n_namesz); ++ desc_sz = tswap32(hdr->n_descsz); ++ } ++ ++ if (note_head_size) { ++ *note_head_size = note_head_sz; ++ } ++ if (name_size) { ++ *name_size = name_sz; ++ } ++ if (desc_size) { ++ *desc_size = desc_sz; ++ } ++} ++ + /* write common header, sub header and elf note to vmcore */ + static void create_header32(DumpState *s, Error **errp) + { +@@ -1493,6 +1558,7 @@ static void dump_init(DumpState *s, int fd, bool has_format, + int64_t begin, int64_t length, Error **errp) + { + CPUArchState *env; ++ VMCoreInfoState *vmci = vmcoreinfo_find(); + int nr_cpus; + Error *err = NULL; + int ret; +@@ -1569,6 +1635,46 @@ static void dump_init(DumpState *s, int fd, bool has_format, + goto cleanup; + } + ++ /* ++ * The goal of this block is to copy the guest note out of ++ * the guest. Failure to do so is not fatal for dumping. ++ */ ++ if (vmci) { ++ uint64_t addr, note_head_size, name_size, desc_size; ++ uint32_t size; ++ uint16_t format; ++ ++ note_head_size = s->dump_info.d_class == ELFCLASS32 ? ++ sizeof(Elf32_Nhdr) : sizeof(Elf64_Nhdr); ++ ++ format = le16_to_cpu(vmci->vmcoreinfo.guest_format); ++ size = le32_to_cpu(vmci->vmcoreinfo.size); ++ addr = le64_to_cpu(vmci->vmcoreinfo.paddr); ++ if (!vmci->has_vmcoreinfo) { ++ error_report("guest note is not present"); ++ } else if (size < note_head_size || size > MAX_GUEST_NOTE_SIZE) { ++ error_report("guest note size is invalid: %" PRIu32, size); ++ } else if (format != VMCOREINFO_FORMAT_ELF) { ++ error_report("guest note format is unsupported: %" PRIu16, format); ++ } else { ++ s->guest_note = g_malloc(size + 1); /* +1 for adding \0 */ ++ cpu_physical_memory_read(addr, s->guest_note, size); ++ ++ get_note_sizes(s, s->guest_note, NULL, &name_size, &desc_size); ++ s->guest_note_size = ELF_NOTE_SIZE(note_head_size, name_size, ++ desc_size); ++ if (name_size > MAX_GUEST_NOTE_SIZE || ++ desc_size > MAX_GUEST_NOTE_SIZE || ++ s->guest_note_size > size) { ++ error_report("Invalid guest note header"); ++ g_free(s->guest_note); ++ s->guest_note = NULL; ++ } else { ++ s->note_size += s->guest_note_size; ++ } ++ } ++ } ++ + /* get memory mapping */ + if (paging) { + qemu_get_guest_memory_mapping(&s->list, &s->guest_phys_blocks, &err); +diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h +index b5ebb0a..343dad4 100644 +--- a/include/sysemu/dump.h ++++ b/include/sysemu/dump.h +@@ -189,6 +189,8 @@ typedef struct DumpState { + * this could be used to calculate + * how much work we have + * finished. */ ++ uint8_t *guest_note; /* ELF note content */ ++ size_t guest_note_size; + } DumpState; + + uint16_t cpu_to_dump16(DumpState *s, uint16_t val); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-dump-allow-target-to-set-the-page-size.patch b/SOURCES/kvm-dump-allow-target-to-set-the-page-size.patch new file mode 100644 index 0000000..badf89f --- /dev/null +++ b/SOURCES/kvm-dump-allow-target-to-set-the-page-size.patch @@ -0,0 +1,434 @@ +From 4e6b46284cde10374bd0660e89958fe9c2477887 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:52 +0100 +Subject: [PATCH 21/41] dump: allow target to set the page size +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-22-marcandre.lureau@redhat.com> +Patchwork-id: 78370 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 21/41] dump: allow target to set the page size +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: Andrew Jones + +This is necessary for targets that don't have TARGET_PAGE_SIZE == +real-target-page-size. The target should set the page size to the +correct one, if known, or, if not known, to the maximum page size +it supports. + +(No functional change.) + +Signed-off-by: Andrew Jones +Reviewed-by: Peter Maydell +Message-id: 1452542185-10914-4-git-send-email-drjones@redhat.com +Signed-off-by: Peter Maydell + +(cherry picked from commit 8161befdd15ddc5a8bb9e807ff1ac5907c594688) +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + dump.c | 127 ++++++++++++++++++++++++++++----------------- + include/sysemu/dump-arch.h | 8 +-- + include/sysemu/dump.h | 10 +--- + 3 files changed, 85 insertions(+), 60 deletions(-) + +diff --git a/dump.c b/dump.c +index 83b6d20..b5d6608 100644 +--- a/dump.c ++++ b/dump.c +@@ -352,18 +352,18 @@ static void write_memory(DumpState *s, GuestPhysBlock *block, ram_addr_t start, + int64_t i; + Error *local_err = NULL; + +- for (i = 0; i < size / TARGET_PAGE_SIZE; i++) { +- write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE, +- TARGET_PAGE_SIZE, &local_err); ++ for (i = 0; i < size / s->dump_info.page_size; i++) { ++ write_data(s, block->host_addr + start + i * s->dump_info.page_size, ++ s->dump_info.page_size, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + } + +- if ((size % TARGET_PAGE_SIZE) != 0) { +- write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE, +- size % TARGET_PAGE_SIZE, &local_err); ++ if ((size % s->dump_info.page_size) != 0) { ++ write_data(s, block->host_addr + start + i * s->dump_info.page_size, ++ size % s->dump_info.page_size, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; +@@ -742,7 +742,7 @@ static void create_header32(DumpState *s, Error **errp) + + strncpy(dh->signature, KDUMP_SIGNATURE, strlen(KDUMP_SIGNATURE)); + dh->header_version = cpu_to_dump32(s, 6); +- block_size = TARGET_PAGE_SIZE; ++ block_size = s->dump_info.page_size; + dh->block_size = cpu_to_dump32(s, block_size); + sub_hdr_size = sizeof(struct KdumpSubHeader32) + s->note_size; + sub_hdr_size = DIV_ROUND_UP(sub_hdr_size, block_size); +@@ -842,7 +842,7 @@ static void create_header64(DumpState *s, Error **errp) + + strncpy(dh->signature, KDUMP_SIGNATURE, strlen(KDUMP_SIGNATURE)); + dh->header_version = cpu_to_dump32(s, 6); +- block_size = TARGET_PAGE_SIZE; ++ block_size = s->dump_info.page_size; + dh->block_size = cpu_to_dump32(s, block_size); + sub_hdr_size = sizeof(struct KdumpSubHeader64) + s->note_size; + sub_hdr_size = DIV_ROUND_UP(sub_hdr_size, block_size); +@@ -938,6 +938,11 @@ static void write_dump_header(DumpState *s, Error **errp) + } + } + ++static size_t dump_bitmap_get_bufsize(DumpState *s) ++{ ++ return s->dump_info.page_size; ++} ++ + /* + * set dump_bitmap sequencely. the bit before last_pfn is not allowed to be + * rewritten, so if need to set the first bit, set last_pfn and pfn to 0. +@@ -951,6 +956,8 @@ static int set_dump_bitmap(uint64_t last_pfn, uint64_t pfn, bool value, + off_t old_offset, new_offset; + off_t offset_bitmap1, offset_bitmap2; + uint32_t byte, bit; ++ size_t bitmap_bufsize = dump_bitmap_get_bufsize(s); ++ size_t bits_per_buf = bitmap_bufsize * CHAR_BIT; + + /* should not set the previous place */ + assert(last_pfn <= pfn); +@@ -961,14 +968,14 @@ static int set_dump_bitmap(uint64_t last_pfn, uint64_t pfn, bool value, + * making new_offset be bigger than old_offset can also sync remained data + * into vmcore. + */ +- old_offset = BUFSIZE_BITMAP * (last_pfn / PFN_BUFBITMAP); +- new_offset = BUFSIZE_BITMAP * (pfn / PFN_BUFBITMAP); ++ old_offset = bitmap_bufsize * (last_pfn / bits_per_buf); ++ new_offset = bitmap_bufsize * (pfn / bits_per_buf); + + while (old_offset < new_offset) { + /* calculate the offset and write dump_bitmap */ + offset_bitmap1 = s->offset_dump_bitmap + old_offset; + if (write_buffer(s->fd, offset_bitmap1, buf, +- BUFSIZE_BITMAP) < 0) { ++ bitmap_bufsize) < 0) { + return -1; + } + +@@ -976,17 +983,17 @@ static int set_dump_bitmap(uint64_t last_pfn, uint64_t pfn, bool value, + offset_bitmap2 = s->offset_dump_bitmap + s->len_dump_bitmap + + old_offset; + if (write_buffer(s->fd, offset_bitmap2, buf, +- BUFSIZE_BITMAP) < 0) { ++ bitmap_bufsize) < 0) { + return -1; + } + +- memset(buf, 0, BUFSIZE_BITMAP); +- old_offset += BUFSIZE_BITMAP; ++ memset(buf, 0, bitmap_bufsize); ++ old_offset += bitmap_bufsize; + } + + /* get the exact place of the bit in the buf, and set it */ +- byte = (pfn % PFN_BUFBITMAP) / CHAR_BIT; +- bit = (pfn % PFN_BUFBITMAP) % CHAR_BIT; ++ byte = (pfn % bits_per_buf) / CHAR_BIT; ++ bit = (pfn % bits_per_buf) % CHAR_BIT; + if (value) { + buf[byte] |= 1u << bit; + } else { +@@ -996,6 +1003,20 @@ static int set_dump_bitmap(uint64_t last_pfn, uint64_t pfn, bool value, + return 0; + } + ++static uint64_t dump_paddr_to_pfn(DumpState *s, uint64_t addr) ++{ ++ int target_page_shift = ctz32(s->dump_info.page_size); ++ ++ return (addr >> target_page_shift) - ARCH_PFN_OFFSET; ++} ++ ++static uint64_t dump_pfn_to_paddr(DumpState *s, uint64_t pfn) ++{ ++ int target_page_shift = ctz32(s->dump_info.page_size); ++ ++ return (pfn + ARCH_PFN_OFFSET) << target_page_shift; ++} ++ + /* + * exam every page and return the page frame number and the address of the page. + * bufptr can be NULL. note: the blocks here is supposed to reflect guest-phys +@@ -1006,16 +1027,16 @@ static bool get_next_page(GuestPhysBlock **blockptr, uint64_t *pfnptr, + uint8_t **bufptr, DumpState *s) + { + GuestPhysBlock *block = *blockptr; +- hwaddr addr; ++ hwaddr addr, target_page_mask = ~((hwaddr)s->dump_info.page_size - 1); + uint8_t *buf; + + /* block == NULL means the start of the iteration */ + if (!block) { + block = QTAILQ_FIRST(&s->guest_phys_blocks.head); + *blockptr = block; +- assert((block->target_start & ~TARGET_PAGE_MASK) == 0); +- assert((block->target_end & ~TARGET_PAGE_MASK) == 0); +- *pfnptr = paddr_to_pfn(block->target_start); ++ assert((block->target_start & ~target_page_mask) == 0); ++ assert((block->target_end & ~target_page_mask) == 0); ++ *pfnptr = dump_paddr_to_pfn(s, block->target_start); + if (bufptr) { + *bufptr = block->host_addr; + } +@@ -1023,10 +1044,10 @@ static bool get_next_page(GuestPhysBlock **blockptr, uint64_t *pfnptr, + } + + *pfnptr = *pfnptr + 1; +- addr = pfn_to_paddr(*pfnptr); ++ addr = dump_pfn_to_paddr(s, *pfnptr); + + if ((addr >= block->target_start) && +- (addr + TARGET_PAGE_SIZE <= block->target_end)) { ++ (addr + s->dump_info.page_size <= block->target_end)) { + buf = block->host_addr + (addr - block->target_start); + } else { + /* the next page is in the next block */ +@@ -1035,9 +1056,9 @@ static bool get_next_page(GuestPhysBlock **blockptr, uint64_t *pfnptr, + if (!block) { + return false; + } +- assert((block->target_start & ~TARGET_PAGE_MASK) == 0); +- assert((block->target_end & ~TARGET_PAGE_MASK) == 0); +- *pfnptr = paddr_to_pfn(block->target_start); ++ assert((block->target_start & ~target_page_mask) == 0); ++ assert((block->target_end & ~target_page_mask) == 0); ++ *pfnptr = dump_paddr_to_pfn(s, block->target_start); + buf = block->host_addr; + } + +@@ -1055,9 +1076,11 @@ static void write_dump_bitmap(DumpState *s, Error **errp) + void *dump_bitmap_buf; + size_t num_dumpable; + GuestPhysBlock *block_iter = NULL; ++ size_t bitmap_bufsize = dump_bitmap_get_bufsize(s); ++ size_t bits_per_buf = bitmap_bufsize * CHAR_BIT; + + /* dump_bitmap_buf is used to store dump_bitmap temporarily */ +- dump_bitmap_buf = g_malloc0(BUFSIZE_BITMAP); ++ dump_bitmap_buf = g_malloc0(bitmap_bufsize); + + num_dumpable = 0; + last_pfn = 0; +@@ -1079,11 +1102,11 @@ static void write_dump_bitmap(DumpState *s, Error **errp) + + /* + * set_dump_bitmap will always leave the recently set bit un-sync. Here we +- * set last_pfn + PFN_BUFBITMAP to 0 and those set but un-sync bit will be +- * synchronized into vmcore. ++ * set the remaining bits from last_pfn to the end of the bitmap buffer to ++ * 0. With those set, the un-sync bit will be synchronized into the vmcore. + */ + if (num_dumpable > 0) { +- ret = set_dump_bitmap(last_pfn, last_pfn + PFN_BUFBITMAP, false, ++ ret = set_dump_bitmap(last_pfn, last_pfn + bits_per_buf, false, + dump_bitmap_buf, s); + if (ret < 0) { + dump_error(s, "dump: failed to sync dump_bitmap", errp); +@@ -1103,8 +1126,8 @@ static void prepare_data_cache(DataCache *data_cache, DumpState *s, + { + data_cache->fd = s->fd; + data_cache->data_size = 0; +- data_cache->buf_size = BUFSIZE_DATA_CACHE; +- data_cache->buf = g_malloc0(BUFSIZE_DATA_CACHE); ++ data_cache->buf_size = 4 * dump_bitmap_get_bufsize(s); ++ data_cache->buf = g_malloc0(data_cache->buf_size); + data_cache->offset = offset; + } + +@@ -1198,7 +1221,7 @@ static void write_dump_pages(DumpState *s, Error **errp) + prepare_data_cache(&page_data, s, offset_data); + + /* prepare buffer to store compressed data */ +- len_buf_out = get_len_buf_out(TARGET_PAGE_SIZE, s->flag_compress); ++ len_buf_out = get_len_buf_out(s->dump_info.page_size, s->flag_compress); + assert(len_buf_out != 0); + + #ifdef CONFIG_LZO +@@ -1211,19 +1234,19 @@ static void write_dump_pages(DumpState *s, Error **errp) + * init zero page's page_desc and page_data, because every zero page + * uses the same page_data + */ +- pd_zero.size = cpu_to_dump32(s, TARGET_PAGE_SIZE); ++ pd_zero.size = cpu_to_dump32(s, s->dump_info.page_size); + pd_zero.flags = cpu_to_dump32(s, 0); + pd_zero.offset = cpu_to_dump64(s, offset_data); + pd_zero.page_flags = cpu_to_dump64(s, 0); +- buf = g_malloc0(TARGET_PAGE_SIZE); +- ret = write_cache(&page_data, buf, TARGET_PAGE_SIZE, false); ++ buf = g_malloc0(s->dump_info.page_size); ++ ret = write_cache(&page_data, buf, s->dump_info.page_size, false); + g_free(buf); + if (ret < 0) { + dump_error(s, "dump: failed to write page data (zero page)", errp); + goto out; + } + +- offset_data += TARGET_PAGE_SIZE; ++ offset_data += s->dump_info.page_size; + + /* + * dump memory to vmcore page by page. zero page will all be resided in the +@@ -1231,7 +1254,7 @@ static void write_dump_pages(DumpState *s, Error **errp) + */ + while (get_next_page(&block_iter, &pfn_iter, &buf, s)) { + /* check zero page */ +- if (is_zero_page(buf, TARGET_PAGE_SIZE)) { ++ if (is_zero_page(buf, s->dump_info.page_size)) { + ret = write_cache(&page_desc, &pd_zero, sizeof(PageDescriptor), + false); + if (ret < 0) { +@@ -1253,8 +1276,8 @@ static void write_dump_pages(DumpState *s, Error **errp) + size_out = len_buf_out; + if ((s->flag_compress & DUMP_DH_COMPRESSED_ZLIB) && + (compress2(buf_out, (uLongf *)&size_out, buf, +- TARGET_PAGE_SIZE, Z_BEST_SPEED) == Z_OK) && +- (size_out < TARGET_PAGE_SIZE)) { ++ s->dump_info.page_size, Z_BEST_SPEED) == Z_OK) && ++ (size_out < s->dump_info.page_size)) { + pd.flags = cpu_to_dump32(s, DUMP_DH_COMPRESSED_ZLIB); + pd.size = cpu_to_dump32(s, size_out); + +@@ -1265,9 +1288,9 @@ static void write_dump_pages(DumpState *s, Error **errp) + } + #ifdef CONFIG_LZO + } else if ((s->flag_compress & DUMP_DH_COMPRESSED_LZO) && +- (lzo1x_1_compress(buf, TARGET_PAGE_SIZE, buf_out, ++ (lzo1x_1_compress(buf, s->dump_info.page_size, buf_out, + (lzo_uint *)&size_out, wrkmem) == LZO_E_OK) && +- (size_out < TARGET_PAGE_SIZE)) { ++ (size_out < s->dump_info.page_size)) { + pd.flags = cpu_to_dump32(s, DUMP_DH_COMPRESSED_LZO); + pd.size = cpu_to_dump32(s, size_out); + +@@ -1279,9 +1302,9 @@ static void write_dump_pages(DumpState *s, Error **errp) + #endif + #ifdef CONFIG_SNAPPY + } else if ((s->flag_compress & DUMP_DH_COMPRESSED_SNAPPY) && +- (snappy_compress((char *)buf, TARGET_PAGE_SIZE, ++ (snappy_compress((char *)buf, s->dump_info.page_size, + (char *)buf_out, &size_out) == SNAPPY_OK) && +- (size_out < TARGET_PAGE_SIZE)) { ++ (size_out < s->dump_info.page_size)) { + pd.flags = cpu_to_dump32(s, DUMP_DH_COMPRESSED_SNAPPY); + pd.size = cpu_to_dump32(s, size_out); + +@@ -1294,13 +1317,14 @@ static void write_dump_pages(DumpState *s, Error **errp) + } else { + /* + * fall back to save in plaintext, size_out should be +- * assigned TARGET_PAGE_SIZE ++ * assigned the target's page size + */ + pd.flags = cpu_to_dump32(s, 0); +- size_out = TARGET_PAGE_SIZE; ++ size_out = s->dump_info.page_size; + pd.size = cpu_to_dump32(s, size_out); + +- ret = write_cache(&page_data, buf, TARGET_PAGE_SIZE, false); ++ ret = write_cache(&page_data, buf, ++ s->dump_info.page_size, false); + if (ret < 0) { + dump_error(s, "dump: failed to write page data", errp); + goto out; +@@ -1435,7 +1459,7 @@ static void get_max_mapnr(DumpState *s) + GuestPhysBlock *last_block; + + last_block = QTAILQ_LAST(&s->guest_phys_blocks.head, GuestPhysBlockHead); +- s->max_mapnr = paddr_to_pfn(last_block->target_end); ++ s->max_mapnr = dump_paddr_to_pfn(s, last_block->target_end); + } + + static void dump_init(DumpState *s, int fd, bool has_format, +@@ -1494,6 +1518,10 @@ static void dump_init(DumpState *s, int fd, bool has_format, + goto cleanup; + } + ++ if (!s->dump_info.page_size) { ++ s->dump_info.page_size = TARGET_PAGE_SIZE; ++ } ++ + s->note_size = cpu_get_note_size(s->dump_info.d_class, + s->dump_info.d_machine, nr_cpus); + if (s->note_size < 0) { +@@ -1517,8 +1545,9 @@ static void dump_init(DumpState *s, int fd, bool has_format, + get_max_mapnr(s); + + uint64_t tmp; +- tmp = DIV_ROUND_UP(DIV_ROUND_UP(s->max_mapnr, CHAR_BIT), TARGET_PAGE_SIZE); +- s->len_dump_bitmap = tmp * TARGET_PAGE_SIZE; ++ tmp = DIV_ROUND_UP(DIV_ROUND_UP(s->max_mapnr, CHAR_BIT), ++ s->dump_info.page_size); ++ s->len_dump_bitmap = tmp * s->dump_info.page_size; + + /* init for kdump-compressed format */ + if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) { +diff --git a/include/sysemu/dump-arch.h b/include/sysemu/dump-arch.h +index 9c95ced..4335839 100644 +--- a/include/sysemu/dump-arch.h ++++ b/include/sysemu/dump-arch.h +@@ -15,9 +15,11 @@ + #define DUMP_ARCH_H + + typedef struct ArchDumpInfo { +- int d_machine; /* Architecture */ +- int d_endian; /* ELFDATA2LSB or ELFDATA2MSB */ +- int d_class; /* ELFCLASS32 or ELFCLASS64 */ ++ int d_machine; /* Architecture */ ++ int d_endian; /* ELFDATA2LSB or ELFDATA2MSB */ ++ int d_class; /* ELFCLASS32 or ELFCLASS64 */ ++ uint32_t page_size; /* The target's page size. If it's variable and ++ * unknown, then this should be the maximum. */ + } ArchDumpInfo; + + struct GuestPhysBlockList; /* memory_mapping.h */ +diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h +index 7e4ec5c..16cbd8d 100644 +--- a/include/sysemu/dump.h ++++ b/include/sysemu/dump.h +@@ -20,12 +20,9 @@ + #define VERSION_FLAT_HEADER (1) /* version of flattened format */ + #define END_FLAG_FLAT_HEADER (-1) + ++#ifndef ARCH_PFN_OFFSET + #define ARCH_PFN_OFFSET (0) +- +-#define paddr_to_pfn(X) \ +- (((unsigned long long)(X) >> TARGET_PAGE_BITS) - ARCH_PFN_OFFSET) +-#define pfn_to_paddr(X) \ +- (((unsigned long long)(X) + ARCH_PFN_OFFSET) << TARGET_PAGE_BITS) ++#endif + + /* + * flag for compressed format +@@ -39,9 +36,6 @@ + #define PHYS_BASE (0) + #define DUMP_LEVEL (1) + #define DISKDUMP_HEADER_BLOCKS (1) +-#define BUFSIZE_BITMAP (TARGET_PAGE_SIZE) +-#define PFN_BUFBITMAP (CHAR_BIT * BUFSIZE_BITMAP) +-#define BUFSIZE_DATA_CACHE (TARGET_PAGE_SIZE * 4) + + #include "sysemu/dump-arch.h" + #include "sysemu/memory_mapping.h" +-- +1.8.3.1 + diff --git a/SOURCES/kvm-dump-allow-target-to-set-the-physical-base.patch b/SOURCES/kvm-dump-allow-target-to-set-the-physical-base.patch new file mode 100644 index 0000000..dc02b9b --- /dev/null +++ b/SOURCES/kvm-dump-allow-target-to-set-the-physical-base.patch @@ -0,0 +1,88 @@ +From 26e8c3574944585f9f02a92b03a6e7097dd3a7dd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:53 +0100 +Subject: [PATCH 22/41] dump: allow target to set the physical base +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-23-marcandre.lureau@redhat.com> +Patchwork-id: 78371 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 22/41] dump: allow target to set the physical base +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: Andrew Jones + +crash assumes the physical base in the kdump subheader of +makedumpfile formatted dumps is correct. Zero is not correct +for all architectures, so allow it to be changed. + +(No functional change.) + +Signed-off-by: Andrew Jones +Reviewed-by: Peter Maydell +Message-id: 1452542185-10914-5-git-send-email-drjones@redhat.com +Signed-off-by: Peter Maydell + +(cherry picked from commit b6e05aa473b52e049654fae834453232e6b6e798) +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + dump.c | 4 ++-- + include/sysemu/dump-arch.h | 1 + + include/sysemu/dump.h | 1 - + 3 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/dump.c b/dump.c +index b5d6608..a359c29 100644 +--- a/dump.c ++++ b/dump.c +@@ -780,7 +780,7 @@ static void create_header32(DumpState *s, Error **errp) + + /* 64bit max_mapnr_64 */ + kh->max_mapnr_64 = cpu_to_dump64(s, s->max_mapnr); +- kh->phys_base = cpu_to_dump32(s, PHYS_BASE); ++ kh->phys_base = cpu_to_dump32(s, s->dump_info.phys_base); + kh->dump_level = cpu_to_dump32(s, DUMP_LEVEL); + + offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size; +@@ -880,7 +880,7 @@ static void create_header64(DumpState *s, Error **errp) + + /* 64bit max_mapnr_64 */ + kh->max_mapnr_64 = cpu_to_dump64(s, s->max_mapnr); +- kh->phys_base = cpu_to_dump64(s, PHYS_BASE); ++ kh->phys_base = cpu_to_dump64(s, s->dump_info.phys_base); + kh->dump_level = cpu_to_dump32(s, DUMP_LEVEL); + + offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size; +diff --git a/include/sysemu/dump-arch.h b/include/sysemu/dump-arch.h +index 4335839..e25b02e 100644 +--- a/include/sysemu/dump-arch.h ++++ b/include/sysemu/dump-arch.h +@@ -20,6 +20,7 @@ typedef struct ArchDumpInfo { + int d_class; /* ELFCLASS32 or ELFCLASS64 */ + uint32_t page_size; /* The target's page size. If it's variable and + * unknown, then this should be the maximum. */ ++ uint64_t phys_base; /* The target's physmem base. */ + } ArchDumpInfo; + + struct GuestPhysBlockList; /* memory_mapping.h */ +diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h +index 16cbd8d..2f04b24 100644 +--- a/include/sysemu/dump.h ++++ b/include/sysemu/dump.h +@@ -33,7 +33,6 @@ + + #define KDUMP_SIGNATURE "KDUMP " + #define SIG_LEN (sizeof(KDUMP_SIGNATURE) - 1) +-#define PHYS_BASE (0) + #define DUMP_LEVEL (1) + #define DISKDUMP_HEADER_BLOCKS (1) + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-dump-do-not-dump-non-existent-guest-memory.patch b/SOURCES/kvm-dump-do-not-dump-non-existent-guest-memory.patch new file mode 100644 index 0000000..cdafef1 --- /dev/null +++ b/SOURCES/kvm-dump-do-not-dump-non-existent-guest-memory.patch @@ -0,0 +1,67 @@ +From 725ecdf6e40eaebbfa8e5328a5ff96163b61637f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:39:00 +0100 +Subject: [PATCH 29/41] dump: do not dump non-existent guest memory +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-30-marcandre.lureau@redhat.com> +Patchwork-id: 78379 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 29/41] dump: do not dump non-existent guest memory +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: Cornelia Huck + +It does not really make sense to dump memory that is not there. + +Moreover, that fixes a segmentation fault when calling dump-guest-memory +with no filter for a machine with no memory defined. + +New behaviour is: + +(qemu) dump-guest-memory /dev/null +dump: no guest memory to dump +(qemu) dump-guest-memory /dev/null 0 4096 +dump: no guest memory to dump + +Signed-off-by: Cornelia Huck +Tested-by: Laurent Vivier +Reviewed-by: Laurent Vivier +Reviewed-by: Greg Kurz +Reviewed-by: Peter Xu +Message-Id: <20170913142036.2469-4-lvivier@redhat.com> +Signed-off-by: Laurent Vivier +Signed-off-by: Dr. David Alan Gilbert + +(cherry picked from commit d1e6994abcd12c7f54aa73ff848fb6215c783898) +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + dump.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/dump.c b/dump.c +index 008a722..d629c8d 100644 +--- a/dump.c ++++ b/dump.c +@@ -1536,6 +1536,12 @@ static void dump_init(DumpState *s, int fd, bool has_format, + fprintf(stderr, "DUMP: total memory to dump: %lu\n", s->total_size); + #endif + ++ /* it does not make sense to dump non-existent memory */ ++ if (!s->total_size) { ++ error_setg(errp, "dump: no guest memory to dump"); ++ goto cleanup; ++ } ++ + s->start = get_start_block(s); + if (s->start == -1) { + error_set(errp, QERR_INVALID_PARAMETER, "begin"); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-dump-guest-memory-add-dump_in_progress-helper-functi.patch b/SOURCES/kvm-dump-guest-memory-add-dump_in_progress-helper-functi.patch new file mode 100644 index 0000000..ce51b89 --- /dev/null +++ b/SOURCES/kvm-dump-guest-memory-add-dump_in_progress-helper-functi.patch @@ -0,0 +1,118 @@ +From 68ed14180549185ab27c37baacd47843ae45511c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:56 +0100 +Subject: [PATCH 25/41] dump-guest-memory: add dump_in_progress() helper + function +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-26-marcandre.lureau@redhat.com> +Patchwork-id: 78376 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 25/41] dump-guest-memory: add dump_in_progress() helper function +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: Peter Xu + +For now, it has no effect. It will be used in dump detach support. + +Signed-off-by: Peter Xu +Reviewed-by: Fam Zheng +Message-Id: <1455772616-8668-5-git-send-email-peterx@redhat.com> +Signed-off-by: Paolo Bonzini + +(cherry picked from commit 65d64f362326a57b590b8b76e3422030a2aa5c44) + +RHEL: minor conflict in function declaration area. + +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + dump.c | 13 +++++++++++++ + include/qemu-common.h | 4 ++++ + qmp.c | 14 ++++++++++++++ + 3 files changed, 31 insertions(+) + +diff --git a/dump.c b/dump.c +index 254c0ba..639d52a 100644 +--- a/dump.c ++++ b/dump.c +@@ -1455,6 +1455,12 @@ static void dump_state_prepare(DumpState *s) + *s = (DumpState) { .status = DUMP_STATUS_ACTIVE }; + } + ++bool dump_in_progress(void) ++{ ++ DumpState *state = &dump_state_global; ++ return (state->status == DUMP_STATUS_ACTIVE); ++} ++ + static void dump_init(DumpState *s, int fd, bool has_format, + DumpGuestMemoryFormat format, bool paging, bool has_filter, + int64_t begin, int64_t length, Error **errp) +@@ -1632,6 +1638,13 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin, + DumpState *s; + Error *local_err = NULL; + ++ /* if there is a dump in background, we should wait until the dump ++ * finished */ ++ if (dump_in_progress()) { ++ error_setg(errp, "There is a dump in process, please wait."); ++ return; ++ } ++ + /* + * kdump-compressed format need the whole memory dumped, so paging or + * filter is not supported here. +diff --git a/include/qemu-common.h b/include/qemu-common.h +index 8c1132c..4569d52 100644 +--- a/include/qemu-common.h ++++ b/include/qemu-common.h +@@ -481,4 +481,8 @@ size_t buffer_find_nonzero_offset(const void *buf, size_t len); + */ + int parse_debug_env(const char *name, int max, int initial); + ++/* returns non-zero if dump is in progress, otherwise zero is ++ * returned. */ ++bool dump_in_progress(void); ++ + #endif +diff --git a/qmp.c b/qmp.c +index 4c149b3..5996056 100644 +--- a/qmp.c ++++ b/qmp.c +@@ -87,6 +87,13 @@ void qmp_quit(Error **err) + + void qmp_stop(Error **errp) + { ++ /* if there is a dump in background, we should wait until the dump ++ * finished */ ++ if (dump_in_progress()) { ++ error_setg(errp, "There is a dump in process, please wait."); ++ return; ++ } ++ + if (runstate_check(RUN_STATE_INMIGRATE)) { + autostart = 0; + } else { +@@ -159,6 +166,13 @@ void qmp_cont(Error **errp) + { + Error *local_err = NULL; + ++ /* if there is a dump in background, we should wait until the dump ++ * finished */ ++ if (dump_in_progress()) { ++ error_setg(errp, "There is a dump in process, please wait."); ++ return; ++ } ++ + if (runstate_needs_reset()) { + error_set(errp, QERR_RESET_REQUIRED); + return; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-dump-guest-memory-cleanup-removing-dump_-error-clean.patch b/SOURCES/kvm-dump-guest-memory-cleanup-removing-dump_-error-clean.patch new file mode 100644 index 0000000..c1db657 --- /dev/null +++ b/SOURCES/kvm-dump-guest-memory-cleanup-removing-dump_-error-clean.patch @@ -0,0 +1,366 @@ +From e105226b0203159f15fc932eac668c67686ec923 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:54 +0100 +Subject: [PATCH 23/41] dump-guest-memory: cleanup: removing + dump_{error|cleanup}(). +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-24-marcandre.lureau@redhat.com> +Patchwork-id: 78372 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 23/41] dump-guest-memory: cleanup: removing dump_{error|cleanup}(). +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: Peter Xu + +It might be a little bit confusing and error prone to do +dump_cleanup() in these two functions. A better way is to do +dump_cleanup() before dump finish, no matter whether dump has +succeeded or not. + +Signed-off-by: Peter Xu +Reviewed-by: Fam Zheng +Message-Id: <1455772616-8668-2-git-send-email-peterx@redhat.com> +Signed-off-by: Paolo Bonzini + +(cherry picked from commit e3517a529913a2a48c12ba8eef4975ad561af97c) +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + dump.c | 78 +++++++++++++++++++++++++++--------------------------------------- + 1 file changed, 32 insertions(+), 46 deletions(-) + +diff --git a/dump.c b/dump.c +index a359c29..790bfe4 100644 +--- a/dump.c ++++ b/dump.c +@@ -81,12 +81,6 @@ static int dump_cleanup(DumpState *s) + return 0; + } + +-static void dump_error(DumpState *s, const char *reason, Error **errp) +-{ +- dump_cleanup(s); +- error_setg(errp, "%s", reason); +-} +- + static int fd_write_vmcore(const void *buf, size_t size, void *opaque) + { + DumpState *s = opaque; +@@ -127,7 +121,7 @@ static void write_elf64_header(DumpState *s, Error **errp) + + ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s); + if (ret < 0) { +- dump_error(s, "dump: failed to write elf header", errp); ++ error_setg(errp, "dump: failed to write elf header"); + } + } + +@@ -158,7 +152,7 @@ static void write_elf32_header(DumpState *s, Error **errp) + + ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s); + if (ret < 0) { +- dump_error(s, "dump: failed to write elf header", errp); ++ error_setg(errp, "dump: failed to write elf header"); + } + } + +@@ -181,7 +175,7 @@ static void write_elf64_load(DumpState *s, MemoryMapping *memory_mapping, + + ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s); + if (ret < 0) { +- dump_error(s, "dump: failed to write program header table", errp); ++ error_setg(errp, "dump: failed to write program header table"); + } + } + +@@ -204,7 +198,7 @@ static void write_elf32_load(DumpState *s, MemoryMapping *memory_mapping, + + ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s); + if (ret < 0) { +- dump_error(s, "dump: failed to write program header table", errp); ++ error_setg(errp, "dump: failed to write program header table"); + } + } + +@@ -224,7 +218,7 @@ static void write_elf64_note(DumpState *s, Error **errp) + + ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s); + if (ret < 0) { +- dump_error(s, "dump: failed to write program header table", errp); ++ error_setg(errp, "dump: failed to write program header table"); + } + } + +@@ -246,7 +240,7 @@ static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s, + id = cpu_index(cpu); + ret = cpu_write_elf64_note(f, cpu, id, s); + if (ret < 0) { +- dump_error(s, "dump: failed to write elf notes", errp); ++ error_setg(errp, "dump: failed to write elf notes"); + return; + } + } +@@ -255,7 +249,7 @@ static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s, + cpu = ENV_GET_CPU(env); + ret = cpu_write_elf64_qemunote(f, cpu, s); + if (ret < 0) { +- dump_error(s, "dump: failed to write CPU status", errp); ++ error_setg(errp, "dump: failed to write CPU status"); + return; + } + } +@@ -277,7 +271,7 @@ static void write_elf32_note(DumpState *s, Error **errp) + + ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s); + if (ret < 0) { +- dump_error(s, "dump: failed to write program header table", errp); ++ error_setg(errp, "dump: failed to write program header table"); + } + } + +@@ -294,7 +288,7 @@ static void write_elf32_notes(WriteCoreDumpFunction f, DumpState *s, + id = cpu_index(cpu); + ret = cpu_write_elf32_note(f, cpu, id, s); + if (ret < 0) { +- dump_error(s, "dump: failed to write elf notes", errp); ++ error_setg(errp, "dump: failed to write elf notes"); + return; + } + } +@@ -303,7 +297,7 @@ static void write_elf32_notes(WriteCoreDumpFunction f, DumpState *s, + cpu = ENV_GET_CPU(env); + ret = cpu_write_elf32_qemunote(f, cpu, s); + if (ret < 0) { +- dump_error(s, "dump: failed to write CPU status", errp); ++ error_setg(errp, "dump: failed to write CPU status"); + return; + } + } +@@ -331,7 +325,7 @@ static void write_elf_section(DumpState *s, int type, Error **errp) + + ret = fd_write_vmcore(&shdr, shdr_size, s); + if (ret < 0) { +- dump_error(s, "dump: failed to write section header table", errp); ++ error_setg(errp, "dump: failed to write section header table"); + } + } + +@@ -341,7 +335,7 @@ static void write_data(DumpState *s, void *buf, int length, Error **errp) + + ret = fd_write_vmcore(buf, length, s); + if (ret < 0) { +- dump_error(s, "dump: failed to save memory", errp); ++ error_setg(errp, "dump: failed to save memory"); + } + } + +@@ -573,11 +567,6 @@ static void dump_begin(DumpState *s, Error **errp) + } + } + +-static void dump_completed(DumpState *s) +-{ +- dump_cleanup(s); +-} +- + static int get_next_block(DumpState *s, GuestPhysBlock *block) + { + while (1) { +@@ -629,8 +618,6 @@ static void dump_iterate(DumpState *s, Error **errp) + } + + } while (!get_next_block(s, block)); +- +- dump_completed(s); + } + + static void create_vmcore(DumpState *s, Error **errp) +@@ -770,7 +757,7 @@ static void create_header32(DumpState *s, Error **errp) + dh->status = cpu_to_dump32(s, status); + + if (write_buffer(s->fd, 0, dh, size) < 0) { +- dump_error(s, "dump: failed to write disk dump header", errp); ++ error_setg(errp, "dump: failed to write disk dump header"); + goto out; + } + +@@ -789,7 +776,7 @@ static void create_header32(DumpState *s, Error **errp) + + if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS * + block_size, kh, size) < 0) { +- dump_error(s, "dump: failed to write kdump sub header", errp); ++ error_setg(errp, "dump: failed to write kdump sub header"); + goto out; + } + +@@ -805,7 +792,7 @@ static void create_header32(DumpState *s, Error **errp) + } + if (write_buffer(s->fd, offset_note, s->note_buf, + s->note_size) < 0) { +- dump_error(s, "dump: failed to write notes", errp); ++ error_setg(errp, "dump: failed to write notes"); + goto out; + } + +@@ -870,7 +857,7 @@ static void create_header64(DumpState *s, Error **errp) + dh->status = cpu_to_dump32(s, status); + + if (write_buffer(s->fd, 0, dh, size) < 0) { +- dump_error(s, "dump: failed to write disk dump header", errp); ++ error_setg(errp, "dump: failed to write disk dump header"); + goto out; + } + +@@ -889,7 +876,7 @@ static void create_header64(DumpState *s, Error **errp) + + if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS * + block_size, kh, size) < 0) { +- dump_error(s, "dump: failed to write kdump sub header", errp); ++ error_setg(errp, "dump: failed to write kdump sub header"); + goto out; + } + +@@ -906,7 +893,7 @@ static void create_header64(DumpState *s, Error **errp) + + if (write_buffer(s->fd, offset_note, s->note_buf, + s->note_size) < 0) { +- dump_error(s, "dump: failed to write notes", errp); ++ error_setg(errp, "dump: failed to write notes"); + goto out; + } + +@@ -1092,7 +1079,7 @@ static void write_dump_bitmap(DumpState *s, Error **errp) + while (get_next_page(&block_iter, &pfn, NULL, s)) { + ret = set_dump_bitmap(last_pfn, pfn, true, dump_bitmap_buf, s); + if (ret < 0) { +- dump_error(s, "dump: failed to set dump_bitmap", errp); ++ error_setg(errp, "dump: failed to set dump_bitmap"); + goto out; + } + +@@ -1109,7 +1096,7 @@ static void write_dump_bitmap(DumpState *s, Error **errp) + ret = set_dump_bitmap(last_pfn, last_pfn + bits_per_buf, false, + dump_bitmap_buf, s); + if (ret < 0) { +- dump_error(s, "dump: failed to sync dump_bitmap", errp); ++ error_setg(errp, "dump: failed to sync dump_bitmap"); + goto out; + } + } +@@ -1242,7 +1229,7 @@ static void write_dump_pages(DumpState *s, Error **errp) + ret = write_cache(&page_data, buf, s->dump_info.page_size, false); + g_free(buf); + if (ret < 0) { +- dump_error(s, "dump: failed to write page data (zero page)", errp); ++ error_setg(errp, "dump: failed to write page data (zero page)"); + goto out; + } + +@@ -1258,7 +1245,7 @@ static void write_dump_pages(DumpState *s, Error **errp) + ret = write_cache(&page_desc, &pd_zero, sizeof(PageDescriptor), + false); + if (ret < 0) { +- dump_error(s, "dump: failed to write page desc", errp); ++ error_setg(errp, "dump: failed to write page desc"); + goto out; + } + } else { +@@ -1283,7 +1270,7 @@ static void write_dump_pages(DumpState *s, Error **errp) + + ret = write_cache(&page_data, buf_out, size_out, false); + if (ret < 0) { +- dump_error(s, "dump: failed to write page data", errp); ++ error_setg(errp, "dump: failed to write page data"); + goto out; + } + #ifdef CONFIG_LZO +@@ -1296,7 +1283,7 @@ static void write_dump_pages(DumpState *s, Error **errp) + + ret = write_cache(&page_data, buf_out, size_out, false); + if (ret < 0) { +- dump_error(s, "dump: failed to write page data", errp); ++ error_setg(errp, "dump: failed to write page data"); + goto out; + } + #endif +@@ -1310,7 +1297,7 @@ static void write_dump_pages(DumpState *s, Error **errp) + + ret = write_cache(&page_data, buf_out, size_out, false); + if (ret < 0) { +- dump_error(s, "dump: failed to write page data", errp); ++ error_setg(errp, "dump: failed to write page data"); + goto out; + } + #endif +@@ -1326,7 +1313,7 @@ static void write_dump_pages(DumpState *s, Error **errp) + ret = write_cache(&page_data, buf, + s->dump_info.page_size, false); + if (ret < 0) { +- dump_error(s, "dump: failed to write page data", errp); ++ error_setg(errp, "dump: failed to write page data"); + goto out; + } + } +@@ -1338,7 +1325,7 @@ static void write_dump_pages(DumpState *s, Error **errp) + + ret = write_cache(&page_desc, &pd, sizeof(PageDescriptor), false); + if (ret < 0) { +- dump_error(s, "dump: failed to write page desc", errp); ++ error_setg(errp, "dump: failed to write page desc"); + goto out; + } + } +@@ -1346,12 +1333,12 @@ static void write_dump_pages(DumpState *s, Error **errp) + + ret = write_cache(&page_desc, NULL, 0, true); + if (ret < 0) { +- dump_error(s, "dump: failed to sync cache for page_desc", errp); ++ error_setg(errp, "dump: failed to sync cache for page_desc"); + goto out; + } + ret = write_cache(&page_data, NULL, 0, true); + if (ret < 0) { +- dump_error(s, "dump: failed to sync cache for page_data", errp); ++ error_setg(errp, "dump: failed to sync cache for page_data"); + goto out; + } + +@@ -1395,7 +1382,7 @@ static void create_kdump_vmcore(DumpState *s, Error **errp) + + ret = write_start_flat_header(s->fd); + if (ret < 0) { +- dump_error(s, "dump: failed to write start flat header", errp); ++ error_setg(errp, "dump: failed to write start flat header"); + return; + } + +@@ -1419,11 +1406,9 @@ static void create_kdump_vmcore(DumpState *s, Error **errp) + + ret = write_end_flat_header(s->fd); + if (ret < 0) { +- dump_error(s, "dump: failed to write end flat header", errp); ++ error_setg(errp, "dump: failed to write end flat header"); + return; + } +- +- dump_completed(s); + } + + static ram_addr_t get_start_block(DumpState *s) +@@ -1711,6 +1696,7 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin, + create_vmcore(s, errp); + } + ++ dump_cleanup(s); + g_free(s); + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-dump-guest-memory-disable-dump-when-in-INMIGRATE-sta.patch b/SOURCES/kvm-dump-guest-memory-disable-dump-when-in-INMIGRATE-sta.patch new file mode 100644 index 0000000..d136b16 --- /dev/null +++ b/SOURCES/kvm-dump-guest-memory-disable-dump-when-in-INMIGRATE-sta.patch @@ -0,0 +1,50 @@ +From 10a4f18fb24f6d005e00828018f38285347b6fd8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:58 +0100 +Subject: [PATCH 27/41] dump-guest-memory: disable dump when in INMIGRATE state +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-28-marcandre.lureau@redhat.com> +Patchwork-id: 78381 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 27/41] dump-guest-memory: disable dump when in INMIGRATE state +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: Peter Xu + +Signed-off-by: Peter Xu +Reviewed-by: Fam Zheng +Message-Id: <1455772616-8668-7-git-send-email-peterx@redhat.com> +Signed-off-by: Paolo Bonzini + +(cherry picked from commit 63e27f28f281986de791f099efa4fa15cc47f4fc) +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + dump.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/dump.c b/dump.c +index 4bce6cf..8618230 100644 +--- a/dump.c ++++ b/dump.c +@@ -1658,6 +1658,11 @@ void qmp_dump_guest_memory(bool paging, const char *file, + DumpState *s; + Error *local_err = NULL; + ++ if (runstate_check(RUN_STATE_INMIGRATE)) { ++ error_setg(errp, "Dump not allowed during incoming migration."); ++ return; ++ } ++ + /* if there is a dump in background, we should wait until the dump + * finished */ + if (dump_in_progress()) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-dump-guest-memory-introduce-dump_process-helper-func.patch b/SOURCES/kvm-dump-guest-memory-introduce-dump_process-helper-func.patch new file mode 100644 index 0000000..efb6d52 --- /dev/null +++ b/SOURCES/kvm-dump-guest-memory-introduce-dump_process-helper-func.patch @@ -0,0 +1,115 @@ +From b67ef65a1f5d8ceb02ca11c0af92d2c06fd006cb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:57 +0100 +Subject: [PATCH 26/41] dump-guest-memory: introduce dump_process() helper + function. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-27-marcandre.lureau@redhat.com> +Patchwork-id: 78375 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 26/41] dump-guest-memory: introduce dump_process() helper function. +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: Peter Xu + +No functional change. Cleanup only. + +Signed-off-by: Peter Xu +Reviewed-by: Fam Zheng +Message-Id: <1455772616-8668-6-git-send-email-peterx@redhat.com> +Signed-off-by: Paolo Bonzini + +(cherry picked from commit ca1fc8c97e9f26690b1ddbbbced5bafb3d65f6b5) + +RHEL: minor conflict due to "detach" mode not being backported. + +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + dump.c | 35 +++++++++++++++++++++++------------ + include/sysemu/dump.h | 3 +++ + 2 files changed, 26 insertions(+), 12 deletions(-) + +diff --git a/dump.c b/dump.c +index 639d52a..4bce6cf 100644 +--- a/dump.c ++++ b/dump.c +@@ -1470,6 +1470,9 @@ static void dump_init(DumpState *s, int fd, bool has_format, + Error *err = NULL; + int ret; + ++ s->has_format = has_format; ++ s->format = format; ++ + /* kdump-compressed is conflict with paging and filter */ + if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) { + assert(!paging && !has_filter); +@@ -1628,8 +1631,25 @@ cleanup: + dump_cleanup(s); + } + +-void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin, +- int64_t begin, bool has_length, ++/* this operation might be time consuming. */ ++static void dump_process(DumpState *s, Error **errp) ++{ ++ Error *local_err = NULL; ++ ++ if (s->has_format && s->format != DUMP_GUEST_MEMORY_FORMAT_ELF) { ++ create_kdump_vmcore(s, &local_err); ++ } else { ++ create_vmcore(s, &local_err); ++ } ++ ++ s->status = (local_err ? DUMP_STATUS_FAILED : DUMP_STATUS_COMPLETED); ++ error_propagate(errp, local_err); ++ ++ dump_cleanup(s); ++} ++ ++void qmp_dump_guest_memory(bool paging, const char *file, ++ bool has_begin, int64_t begin, bool has_length, + int64_t length, bool has_format, + DumpGuestMemoryFormat format, Error **errp) + { +@@ -1712,16 +1732,7 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin, + return; + } + +- if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) { +- create_kdump_vmcore(s, &local_err); +- } else { +- create_vmcore(s, &local_err); +- } +- +- s->status = (local_err ? DUMP_STATUS_FAILED : DUMP_STATUS_COMPLETED); +- error_propagate(errp, local_err); +- +- dump_cleanup(s); ++ dump_process(s, errp); + } + + DumpGuestMemoryCapability *qmp_query_dump_guest_memory_capability(Error **errp) +diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h +index 21fc02d..1da3ddb 100644 +--- a/include/sysemu/dump.h ++++ b/include/sysemu/dump.h +@@ -178,6 +178,9 @@ typedef struct DumpState { + size_t num_dumpable; /* number of page that can be dumped */ + uint32_t flag_compress; /* indicate the compression format */ + DumpStatus status; /* current dump status */ ++ ++ bool has_format; /* whether format is provided */ ++ DumpGuestMemoryFormat format; /* valid only if has_format == true */ + } DumpState; + + uint16_t cpu_to_dump16(DumpState *s, uint16_t val); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-dump-guest-memory-using-static-DumpState-add-DumpSta.patch b/SOURCES/kvm-dump-guest-memory-using-static-DumpState-add-DumpSta.patch new file mode 100644 index 0000000..c24cd7b --- /dev/null +++ b/SOURCES/kvm-dump-guest-memory-using-static-DumpState-add-DumpSta.patch @@ -0,0 +1,143 @@ +From 7924dd9493c5b90bb1a10b3b9ec486fa10d87304 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:55 +0100 +Subject: [PATCH 24/41] dump-guest-memory: using static DumpState, add + DumpStatus +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-25-marcandre.lureau@redhat.com> +Patchwork-id: 78373 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 24/41] dump-guest-memory: using static DumpState, add DumpStatus +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: Peter Xu + +Instead of malloc/free each time for DumpState, make it +static. Added DumpStatus to show status for dump. + +This is to be used for detached dump. + +Signed-off-by: Peter Xu +Reviewed-by: Fam Zheng +Message-Id: <1455772616-8668-4-git-send-email-peterx@redhat.com> +Signed-off-by: Paolo Bonzini + +(cherry picked from commit baf28f57e2dec63eebfcd3c00f8d4dea9fcde21e) +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + dump.c | 21 ++++++++++++++++----- + include/sysemu/dump.h | 2 ++ + qapi-schema.json | 18 ++++++++++++++++++ + 3 files changed, 36 insertions(+), 5 deletions(-) + +diff --git a/dump.c b/dump.c +index 790bfe4..254c0ba 100644 +--- a/dump.c ++++ b/dump.c +@@ -1447,6 +1447,14 @@ static void get_max_mapnr(DumpState *s) + s->max_mapnr = dump_paddr_to_pfn(s, last_block->target_end); + } + ++static DumpState dump_state_global = { .status = DUMP_STATUS_NONE }; ++ ++static void dump_state_prepare(DumpState *s) ++{ ++ /* zero the struct, setting status to active */ ++ *s = (DumpState) { .status = DUMP_STATUS_ACTIVE }; ++} ++ + static void dump_init(DumpState *s, int fd, bool has_format, + DumpGuestMemoryFormat format, bool paging, bool has_filter, + int64_t begin, int64_t length, Error **errp) +@@ -1680,24 +1688,27 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin, + return; + } + +- s = g_malloc0(sizeof(DumpState)); ++ s = &dump_state_global; ++ dump_state_prepare(s); + + dump_init(s, fd, has_format, format, paging, has_begin, + begin, length, &local_err); + if (local_err) { +- g_free(s); + error_propagate(errp, local_err); ++ s->status = DUMP_STATUS_FAILED; + return; + } + + if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) { +- create_kdump_vmcore(s, errp); ++ create_kdump_vmcore(s, &local_err); + } else { +- create_vmcore(s, errp); ++ create_vmcore(s, &local_err); + } + ++ s->status = (local_err ? DUMP_STATUS_FAILED : DUMP_STATUS_COMPLETED); ++ error_propagate(errp, local_err); ++ + dump_cleanup(s); +- g_free(s); + } + + DumpGuestMemoryCapability *qmp_query_dump_guest_memory_capability(Error **errp) +diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h +index 2f04b24..21fc02d 100644 +--- a/include/sysemu/dump.h ++++ b/include/sysemu/dump.h +@@ -38,6 +38,7 @@ + + #include "sysemu/dump-arch.h" + #include "sysemu/memory_mapping.h" ++#include "qapi-types.h" + + typedef struct QEMU_PACKED MakedumpfileHeader { + char signature[16]; /* = "makedumpfile" */ +@@ -176,6 +177,7 @@ typedef struct DumpState { + off_t offset_page; /* offset of page part in vmcore */ + size_t num_dumpable; /* number of page that can be dumped */ + uint32_t flag_compress; /* indicate the compression format */ ++ DumpStatus status; /* current dump status */ + } DumpState; + + uint16_t cpu_to_dump16(DumpState *s, uint16_t val); +diff --git a/qapi-schema.json b/qapi-schema.json +index 5138ed9..7988ae5 100644 +--- a/qapi-schema.json ++++ b/qapi-schema.json +@@ -2646,6 +2646,24 @@ + '*length': 'int', '*format': 'DumpGuestMemoryFormat' } } + + ## ++# @DumpStatus ++# ++# Describe the status of a long-running background guest memory dump. ++# ++# @none: no dump-guest-memory has started yet. ++# ++# @active: there is one dump running in background. ++# ++# @completed: the last dump has finished successfully. ++# ++# @failed: the last dump has failed. ++# ++# Since 2.6 ++## ++{ 'enum': 'DumpStatus', ++ 'data': [ 'none', 'active', 'completed', 'failed' ] } ++ ++## + # @DumpGuestMemoryCapability: + # + # A list of the available formats for dump-guest-memory +-- +1.8.3.1 + diff --git a/SOURCES/kvm-dump-guest-memory.py-fix-No-symbol-vmcoreinfo_find.patch b/SOURCES/kvm-dump-guest-memory.py-fix-No-symbol-vmcoreinfo_find.patch new file mode 100644 index 0000000..182ecf7 --- /dev/null +++ b/SOURCES/kvm-dump-guest-memory.py-fix-No-symbol-vmcoreinfo_find.patch @@ -0,0 +1,65 @@ +From 6d5a6268d535d641147f16a5d0343beadaaab3d9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:39:11 +0100 +Subject: [PATCH 40/41] dump-guest-memory.py: fix No symbol "vmcoreinfo_find" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-41-marcandre.lureau@redhat.com> +Patchwork-id: 78390 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 40/41] dump-guest-memory.py: fix No symbol "vmcoreinfo_find" +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +When qemu is compiled without debug, the dump gdb python script can fail with: + +Error occurred in Python command: No symbol "vmcoreinfo_find" in current context. + +Because vmcoreinfo_find() is inlined and not exported. + +Use the underlying object_resolve_path_type() to get the instance instead. + +Signed-off-by: Marc-André Lureau +Reviewed-by: Laszlo Ersek +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin + +(cherry picked from commit d36d0a9d152316a41e02c2613a71f5859f407da1) +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + scripts/dump-guest-memory.py | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/scripts/dump-guest-memory.py b/scripts/dump-guest-memory.py +index 471aa73..12b9b7d 100644 +--- a/scripts/dump-guest-memory.py ++++ b/scripts/dump-guest-memory.py +@@ -546,13 +546,15 @@ shape and this command should mostly work.""" + return None + + def add_vmcoreinfo(self): +- if not gdb.parse_and_eval("vmcoreinfo_find()") \ +- or not gdb.parse_and_eval("vmcoreinfo_find()->has_vmcoreinfo"): ++ vmci = '(VMCoreInfoState *)' + \ ++ 'object_resolve_path_type("", "vmcoreinfo", 0)' ++ if not gdb.parse_and_eval("%s" % vmci) \ ++ or not gdb.parse_and_eval("(%s)->has_vmcoreinfo" % vmci): + return + +- fmt = gdb.parse_and_eval("vmcoreinfo_find()->vmcoreinfo.guest_format") +- addr = gdb.parse_and_eval("vmcoreinfo_find()->vmcoreinfo.paddr") +- size = gdb.parse_and_eval("vmcoreinfo_find()->vmcoreinfo.size") ++ fmt = gdb.parse_and_eval("(%s)->vmcoreinfo.guest_format" % vmci) ++ addr = gdb.parse_and_eval("(%s)->vmcoreinfo.paddr" % vmci) ++ size = gdb.parse_and_eval("(%s)->vmcoreinfo.size" % vmci) + + fmt = le16_to_cpu(fmt) + addr = le64_to_cpu(addr) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-dump-guest-memory.py-fix-You-can-t-do-that-without-a.patch b/SOURCES/kvm-dump-guest-memory.py-fix-You-can-t-do-that-without-a.patch new file mode 100644 index 0000000..557d5cc --- /dev/null +++ b/SOURCES/kvm-dump-guest-memory.py-fix-You-can-t-do-that-without-a.patch @@ -0,0 +1,91 @@ +From c42ed2abf0e58a0c4cf069f52756bfa412794d15 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:39:12 +0100 +Subject: [PATCH 41/41] dump-guest-memory.py: fix "You can't do that without a + process to debug" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-42-marcandre.lureau@redhat.com> +Patchwork-id: 78391 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 41/41] dump-guest-memory.py: fix "You can't do that without a process to debug" +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +Upstream-status: <20171212172208.13588-1-marcandre.lureau@redhat.com> +(reviewed, pending for release and merge window to open) + +If the script is run with a core (no running process), it produces an +error: + +(gdb) dump-guest-memory /tmp/vmcore X86_64 +guest RAM blocks: +target_start target_end host_addr message count +---------------- ---------------- ---------------- ------- ----- +0000000000000000 00000000000a0000 00007f7935800000 added 1 +00000000000a0000 00000000000b0000 00007f7934200000 added 2 +00000000000c0000 00000000000ca000 00007f79358c0000 added 3 +00000000000ca000 00000000000cd000 00007f79358ca000 joined 3 +00000000000cd000 00000000000e8000 00007f79358cd000 joined 3 +00000000000e8000 00000000000f0000 00007f79358e8000 joined 3 +00000000000f0000 0000000000100000 00007f79358f0000 joined 3 +0000000000100000 0000000080000000 00007f7935900000 joined 3 +00000000fd000000 00000000fe000000 00007f7934200000 added 4 +00000000fffc0000 0000000100000000 00007f7935600000 added 5 +Python Exception You can't do that without a process to debug.: +Error occurred in Python command: You can't do that without a process +to debug. + +Replace the object_resolve_path_type() function call with a local +volatile variable. + +Signed-off-by: Marc-André Lureau +Reviewed-by: Laszlo Ersek +Signed-off-by: Miroslav Rezanina +--- + hw/misc/vmcoreinfo.c | 3 +++ + scripts/dump-guest-memory.py | 3 +-- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/hw/misc/vmcoreinfo.c b/hw/misc/vmcoreinfo.c +index fa5f610..65b5755 100644 +--- a/hw/misc/vmcoreinfo.c ++++ b/hw/misc/vmcoreinfo.c +@@ -35,6 +35,8 @@ static void vmcoreinfo_realize(DeviceState *dev, Error **errp) + { + VMCoreInfoState *s = VMCOREINFO(dev); + FWCfgState *fw_cfg = fw_cfg_find(); ++ /* for gdb script dump-guest-memory.py */ ++ static VMCoreInfoState * volatile vmcoreinfo_state G_GNUC_UNUSED; + + /* Given that this function is executing, there is at least one VMCOREINFO + * device. Check if there are several. +@@ -57,6 +59,7 @@ static void vmcoreinfo_realize(DeviceState *dev, Error **errp) + false); + + qemu_register_reset(vmcoreinfo_reset, dev); ++ vmcoreinfo_state = s; + } + + static const VMStateDescription vmstate_vmcoreinfo = { +diff --git a/scripts/dump-guest-memory.py b/scripts/dump-guest-memory.py +index 12b9b7d..8a13db0 100644 +--- a/scripts/dump-guest-memory.py ++++ b/scripts/dump-guest-memory.py +@@ -546,8 +546,7 @@ shape and this command should mostly work.""" + return None + + def add_vmcoreinfo(self): +- vmci = '(VMCoreInfoState *)' + \ +- 'object_resolve_path_type("", "vmcoreinfo", 0)' ++ vmci = 'vmcoreinfo_realize::vmcoreinfo_state' + if not gdb.parse_and_eval("%s" % vmci) \ + or not gdb.parse_and_eval("(%s)->has_vmcoreinfo" % vmci): + return +-- +1.8.3.1 + diff --git a/SOURCES/kvm-dump-guest-memory.py-fix-python-2-support.patch b/SOURCES/kvm-dump-guest-memory.py-fix-python-2-support.patch new file mode 100644 index 0000000..8007950 --- /dev/null +++ b/SOURCES/kvm-dump-guest-memory.py-fix-python-2-support.patch @@ -0,0 +1,59 @@ +From 8bd9fce5250f9abcca1e80afb5425bcf6e867b28 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Mon, 22 Jan 2018 14:04:40 +0100 +Subject: [PATCH 2/3] dump-guest-memory.py: fix python 2 support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20180122140440.24988-1-marcandre.lureau@redhat.com> +Patchwork-id: 78692 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v2] dump-guest-memory.py: fix python 2 support +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: Stefan Hajnoczi + +Python GDB support may use Python 2 or 3. + +Inferior.read_memory() may return a 'buffer' with Python 2 or a +'memoryview' with Python 3 (see also +https://sourceware.org/gdb/onlinedocs/gdb/Inferiors-In-Python.html) + +The elf.add_vmcoreinfo_note() method expects a "bytes" object. Wrap +the returned memory with bytes(), which works with both 'memoryview' +and 'buffer'. + +Fixes a regression introduced with commit +d23bfa91b7789534d16ede6cb7d925bfac3f3c4c ("add vmcoreinfo"). + +Suggested-by: Peter Maydell +Signed-off-by: Marc-André Lureau +Acked-by: Laszlo Ersek +Reviewed-by: Eric Blake + +(cherry picked from commit 6f49ec4034e55dfb675a56a62c9579384f7fb8cc) +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + scripts/dump-guest-memory.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/scripts/dump-guest-memory.py b/scripts/dump-guest-memory.py +index 8a13db0..adb942e 100644 +--- a/scripts/dump-guest-memory.py ++++ b/scripts/dump-guest-memory.py +@@ -564,7 +564,7 @@ shape and this command should mostly work.""" + + vmcoreinfo = self.phys_memory_read(addr, size) + if vmcoreinfo: +- self.elf.add_vmcoreinfo_note(vmcoreinfo.tobytes()) ++ self.elf.add_vmcoreinfo_note(bytes(vmcoreinfo)) + + def invoke(self, args, from_tty): + """Handles command invocation from gdb.""" +-- +1.8.3.1 + diff --git a/SOURCES/kvm-dump-update-phys_base-header-field-based-on-VMCOREIN.patch b/SOURCES/kvm-dump-update-phys_base-header-field-based-on-VMCOREIN.patch new file mode 100644 index 0000000..c171676 --- /dev/null +++ b/SOURCES/kvm-dump-update-phys_base-header-field-based-on-VMCOREIN.patch @@ -0,0 +1,143 @@ +From 9a2ab369a3685f85dfa7449c31a2267333cb1468 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:39:02 +0100 +Subject: [PATCH 31/41] dump: update phys_base header field based on VMCOREINFO + content +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-32-marcandre.lureau@redhat.com> +Patchwork-id: 78380 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 31/41] dump: update phys_base header field based on VMCOREINFO content +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +If the guest note is VMCOREINFO, try to get phys_base from it. + +Signed-off-by: Marc-André Lureau +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin + +(cherry picked from commit d9feb51772b4ade9700c7fa54529327a6c8183a7) + +RHEL: replace qemu_strotu64() usage, warn_report()->error_report() + +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + docs/specs/vmcoreinfo.txt | 8 +++++++ + dump.c | 57 +++++++++++++++++++++++++++++++++++++++++++++-- + 2 files changed, 63 insertions(+), 2 deletions(-) + +diff --git a/docs/specs/vmcoreinfo.txt b/docs/specs/vmcoreinfo.txt +index 2868a77..8212610 100644 +--- a/docs/specs/vmcoreinfo.txt ++++ b/docs/specs/vmcoreinfo.txt +@@ -39,3 +39,11 @@ qemu dumps. + + The note format/class must be of the target bitness and the size must + be less than 1Mb. ++ ++If the ELF note name is "VMCOREINFO", it is expected to be the Linux ++vmcoreinfo note (see Documentation/ABI/testing/sysfs-kernel-vmcoreinfo ++in Linux source). In this case, qemu dump code will read the content ++as a key=value text file, looking for "NUMBER(phys_base)" key ++value. The value is expected to be more accurate than architecture ++guess of the value. This is useful for KASLR-enabled guest with ++ancient tools not handling the VMCOREINFO note. +diff --git a/dump.c b/dump.c +index 823d1ad..3bce730 100644 +--- a/dump.c ++++ b/dump.c +@@ -777,6 +777,23 @@ static void get_note_sizes(DumpState *s, const void *note, + } + } + ++static bool note_name_equal(DumpState *s, ++ const uint8_t *note, const char *name) ++{ ++ int len = strlen(name) + 1; ++ uint64_t head_size, name_size; ++ ++ get_note_sizes(s, note, &head_size, &name_size, NULL); ++ head_size = ROUND_UP(head_size, 4); ++ ++ if (name_size != len || ++ memcmp(note + head_size, "VMCOREINFO", len)) { ++ return false; ++ } ++ ++ return true; ++} ++ + /* write common header, sub header and elf note to vmcore */ + static void create_header32(DumpState *s, Error **errp) + { +@@ -1553,6 +1570,40 @@ static int64_t dump_calculate_size(DumpState *s) + return total; + } + ++static void vmcoreinfo_update_phys_base(DumpState *s) ++{ ++ uint64_t size, note_head_size, name_size, phys_base; ++ char **lines; ++ uint8_t *vmci; ++ size_t i; ++ ++ if (!note_name_equal(s, s->guest_note, "VMCOREINFO")) { ++ return; ++ } ++ ++ get_note_sizes(s, s->guest_note, ¬e_head_size, &name_size, &size); ++ note_head_size = ROUND_UP(note_head_size, 4); ++ ++ vmci = s->guest_note + note_head_size + ROUND_UP(name_size, 4); ++ *(vmci + size) = '\0'; ++ ++ lines = g_strsplit((char *)vmci, "\n", -1); ++ for (i = 0; lines[i]; i++) { ++ if (g_str_has_prefix(lines[i], "NUMBER(phys_base)=")) { ++ errno = 0; ++ phys_base = strtoull(lines[i] + 18, NULL, 16); ++ if (errno == ERANGE) { ++ error_report("Failed to read NUMBER(phys_base)="); ++ } else { ++ s->dump_info.phys_base = phys_base; ++ } ++ break; ++ } ++ } ++ ++ g_strfreev(lines); ++} ++ + static void dump_init(DumpState *s, int fd, bool has_format, + DumpGuestMemoryFormat format, bool paging, bool has_filter, + int64_t begin, int64_t length, Error **errp) +@@ -1636,8 +1687,9 @@ static void dump_init(DumpState *s, int fd, bool has_format, + } + + /* +- * The goal of this block is to copy the guest note out of +- * the guest. Failure to do so is not fatal for dumping. ++ * The goal of this block is to (a) update the previously guessed ++ * phys_base, (b) copy the guest note out of the guest. ++ * Failure to do so is not fatal for dumping. + */ + if (vmci) { + uint64_t addr, note_head_size, name_size, desc_size; +@@ -1670,6 +1722,7 @@ static void dump_init(DumpState *s, int fd, bool has_format, + g_free(s->guest_note); + s->guest_note = NULL; + } else { ++ vmcoreinfo_update_phys_base(s); + s->note_size += s->guest_note_size; + } + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-dump.c-Fix-memory-leak-issue-in-cleanup-processing-f.patch b/SOURCES/kvm-dump.c-Fix-memory-leak-issue-in-cleanup-processing-f.patch new file mode 100644 index 0000000..ae10136 --- /dev/null +++ b/SOURCES/kvm-dump.c-Fix-memory-leak-issue-in-cleanup-processing-f.patch @@ -0,0 +1,97 @@ +From c3bae9746b9d3995369ba2fa315b42b3faf0efe3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:48 +0100 +Subject: [PATCH 17/41] dump.c: Fix memory leak issue in cleanup processing for + dump_init() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-18-marcandre.lureau@redhat.com> +Patchwork-id: 78369 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 17/41] dump.c: Fix memory leak issue in cleanup processing for dump_init() +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: Chen Gang + +In dump_init(), when failure occurs, need notice about 'fd' and memory +mapping. So call dump_cleanup() for it (need let all initializations at +front). + +Also simplify dump_cleanup(): remove redundant 'ret' and redundant 'fd' +checking. + +Signed-off-by: Chen Gang +Reviewed-by: Laszlo Ersek +Signed-off-by: Luiz Capitulino + +(cherry picked from commit 2928207ac1bb2751a1554ea0f9a9641179f51488) +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + dump.c | 18 +++++------------- + 1 file changed, 5 insertions(+), 13 deletions(-) + +diff --git a/dump.c b/dump.c +index c902944..c709fc2 100644 +--- a/dump.c ++++ b/dump.c +@@ -71,18 +71,14 @@ uint64_t cpu_to_dump64(DumpState *s, uint64_t val) + + static int dump_cleanup(DumpState *s) + { +- int ret = 0; +- + guest_phys_blocks_free(&s->guest_phys_blocks); + memory_mapping_list_free(&s->list); +- if (s->fd != -1) { +- close(s->fd); +- } ++ close(s->fd); + if (s->resume) { + vm_start(); + } + +- return ret; ++ return 0; + } + + static void dump_error(DumpState *s, const char *reason) +@@ -1505,6 +1501,8 @@ static int dump_init(DumpState *s, int fd, bool has_format, + s->begin = begin; + s->length = length; + ++ memory_mapping_list_init(&s->list); ++ + guest_phys_blocks_init(&s->guest_phys_blocks); + guest_phys_blocks_append(&s->guest_phys_blocks); + +@@ -1532,7 +1530,6 @@ static int dump_init(DumpState *s, int fd, bool has_format, + } + + /* get memory mapping */ +- memory_mapping_list_init(&s->list); + if (paging) { + qemu_get_guest_memory_mapping(&s->list, &s->guest_phys_blocks, &err); + if (err != NULL) { +@@ -1628,12 +1625,7 @@ static int dump_init(DumpState *s, int fd, bool has_format, + return 0; + + cleanup: +- guest_phys_blocks_free(&s->guest_phys_blocks); +- +- if (s->resume) { +- vm_start(); +- } +- ++ dump_cleanup(s); + return -1; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-fix-full-frame-updates-for-VNC-clients.patch b/SOURCES/kvm-fix-full-frame-updates-for-VNC-clients.patch new file mode 100644 index 0000000..fee20ea --- /dev/null +++ b/SOURCES/kvm-fix-full-frame-updates-for-VNC-clients.patch @@ -0,0 +1,43 @@ +From ce84fa12f9d9ae751da24638d4437abda26aaece Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:16 +0100 +Subject: [PATCH 02/27] fix full frame updates for VNC clients + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-3-berrange@redhat.com> +Patchwork-id: 78933 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 02/27] fix full frame updates for VNC clients +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +From: Stephan Kulow + +If the client asks for !incremental frame updates, it has lost its content +so dirty doesn't matter - it has to see the full frame, so setting force_update + +Signed-off-by: Stephan Kulow +Signed-off-by: Gerd Hoffmann +Reviewed-by: Peter Lieven +(cherry picked from commit 07535a890200e640517be0ae04fcff28860ecd37) +Signed-off-by: Miroslav Rezanina +--- + ui/vnc.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/ui/vnc.c b/ui/vnc.c +index 29b216c..5226295 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -1777,6 +1777,7 @@ static void framebuffer_update_request(VncState *vs, int incremental, + return; + } + ++ vs->force_update = 1; + vnc_set_area_dirty(vs->dirty, width, height, x, y, w, h); + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-fw-cfg-support-writeable-blobs.patch b/SOURCES/kvm-fw-cfg-support-writeable-blobs.patch new file mode 100644 index 0000000..bc7a8cb --- /dev/null +++ b/SOURCES/kvm-fw-cfg-support-writeable-blobs.patch @@ -0,0 +1,317 @@ +From 1cc1455511ff6ada7f4b3c4e23d8ff82f820f1ff Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:38 +0100 +Subject: [PATCH 07/41] fw-cfg: support writeable blobs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-8-marcandre.lureau@redhat.com> +Patchwork-id: 78356 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 07/41] fw-cfg: support writeable blobs +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: "Michael S. Tsirkin" + +Useful to send guest data back to QEMU. + +Changes from Laszlo Ersek : +- rebase the patch from Michael Tsirkin's original postings at [1] and [2] + to the following patches: + - loader: Allow a custom AddressSpace when loading ROMs + - loader: Add AddressSpace loading support to uImages + - loader: fix handling of custom address spaces when adding ROM blobs +- reject such writes immediately that would exceed the end of the array, + rather than performing a partial write before setting the error bit: see + the (len != dma.length) condition +- document the write interface + +[1] http://lists.nongnu.org/archive/html/qemu-devel/2016-02/msg04968.html +[2] http://lists.nongnu.org/archive/html/qemu-devel/2016-03/msg02735.html + +Cc: "Gabriel L. Somlo" +Cc: "Michael S. Tsirkin" +Cc: Gerd Hoffmann +Cc: Igor Mammedov +Cc: Michael Walle +Cc: Paolo Bonzini +Cc: Peter Maydell +Cc: Shannon Zhao +Cc: qemu-arm@nongnu.org +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Laszlo Ersek +Reviewed-by: Marcel Apfelbaum +Acked-by: Gabriel Somlo +Tested-by: Gabriel Somlo +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Eduardo Habkost + +(cherry picked from commit baf2d5bfbac015b27f4db74feab235e167df0c84) + +RHEL: major conflict due to internal API changes, but functional + changes minor. + +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + hw/core/loader.c | 19 ++++++++++++------- + hw/i386/acpi-build.c | 2 +- + hw/lm32/lm32_hwsetup.h | 3 ++- + hw/nvram/fw_cfg.c | 35 +++++++++++++++++++++++++++++------ + include/hw/loader.h | 5 +++-- + include/hw/nvram/fw_cfg.h | 2 +- + 6 files changed, 48 insertions(+), 18 deletions(-) + +diff --git a/hw/core/loader.c b/hw/core/loader.c +index 9309b8c..c824bc2 100644 +--- a/hw/core/loader.c ++++ b/hw/core/loader.c +@@ -575,13 +575,13 @@ static void rom_insert(Rom *rom) + QTAILQ_INSERT_TAIL(&roms, rom, next); + } + +-static void *rom_set_mr(Rom *rom, const char *name) ++static void *rom_set_mr(Rom *rom, const char *name, bool ro) + { + void *data; + + rom->mr = g_malloc(sizeof(*rom->mr)); + memory_region_init_ram(rom->mr, name, rom->datasize); +- memory_region_set_readonly(rom->mr, true); ++ memory_region_set_readonly(rom->mr, ro); + vmstate_register_ram_global(rom->mr); + + data = memory_region_get_ram_ptr(rom->mr); +@@ -645,7 +645,7 @@ int rom_add_file(const char *file, const char *fw_dir, + snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name); + + if ((!option_rom || option_rom_has_mr) && rom_file_has_mr) { +- data = rom_set_mr(rom, devpath); ++ data = rom_set_mr(rom, devpath, true); + } else { + data = rom->data; + } +@@ -670,7 +670,8 @@ err: + + void *rom_add_blob(const char *name, const void *blob, size_t len, + hwaddr addr, const char *fw_file_name, +- FWCfgReadCallback fw_callback, void *callback_opaque) ++ FWCfgReadCallback fw_callback, void *callback_opaque, ++ bool read_only) + { + Rom *rom; + void *data = NULL; +@@ -686,17 +687,21 @@ void *rom_add_blob(const char *name, const void *blob, size_t len, + if (fw_file_name && fw_cfg) { + char devpath[100]; + +- snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name); ++ if (read_only) { ++ snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name); ++ } else { ++ snprintf(devpath, sizeof(devpath), "/ram@%s", fw_file_name); ++ } + + if (rom_file_has_mr) { +- data = rom_set_mr(rom, devpath); ++ data = rom_set_mr(rom, devpath, read_only); + } else { + data = rom->data; + } + + fw_cfg_add_file_callback(fw_cfg, fw_file_name, + fw_callback, callback_opaque, +- data, rom->romsize); ++ data, rom->romsize, read_only); + } + return data; + } +diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c +index 85291f5..52dd500 100644 +--- a/hw/i386/acpi-build.c ++++ b/hw/i386/acpi-build.c +@@ -1182,7 +1182,7 @@ static void *acpi_add_rom_blob(AcpiBuildState *build_state, GArray *blob, + const char *name) + { + return rom_add_blob(name, blob->data, acpi_data_len(blob), -1, name, +- acpi_build_update, build_state); ++ acpi_build_update, build_state, true); + } + + static const VMStateDescription vmstate_acpi_build = { +diff --git a/hw/lm32/lm32_hwsetup.h b/hw/lm32/lm32_hwsetup.h +index 9fd5e69..92f952f 100644 +--- a/hw/lm32/lm32_hwsetup.h ++++ b/hw/lm32/lm32_hwsetup.h +@@ -73,7 +73,8 @@ static inline void hwsetup_free(HWSetup *hw) + static inline void hwsetup_create_rom(HWSetup *hw, + hwaddr base) + { +- rom_add_blob("hwsetup", hw->data, TARGET_PAGE_SIZE, base, NULL, NULL, NULL); ++ rom_add_blob("hwsetup", hw->data, TARGET_PAGE_SIZE, ++ base, NULL, NULL, NULL, true); + } + + static inline void hwsetup_add_u8(HWSetup *hw, uint8_t u) +diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c +index 1317df7..1789487 100644 +--- a/hw/nvram/fw_cfg.c ++++ b/hw/nvram/fw_cfg.c +@@ -46,9 +46,11 @@ + #define FW_CFG_DMA_CTL_READ 0x02 + #define FW_CFG_DMA_CTL_SKIP 0x04 + #define FW_CFG_DMA_CTL_SELECT 0x08 ++#define FW_CFG_DMA_CTL_WRITE 0x10 + + typedef struct FWCfgEntry { + uint32_t len; ++ bool allow_write; + uint8_t *data; + void *callback_opaque; + FWCfgReadCallback read_callback; +@@ -279,7 +281,7 @@ static void fw_cfg_dma_transfer(FWCfgState *s) + FWCfgDmaAccess dma; + int arch; + FWCfgEntry *e; +- int read; ++ int read = 0, write = 0; + dma_addr_t dma_addr; + + /* Reset the address before the next access */ +@@ -306,8 +308,13 @@ static void fw_cfg_dma_transfer(FWCfgState *s) + + if (dma.control & FW_CFG_DMA_CTL_READ) { + read = 1; ++ write = 0; ++ } else if (dma.control & FW_CFG_DMA_CTL_WRITE) { ++ read = 0; ++ write = 1; + } else if (dma.control & FW_CFG_DMA_CTL_SKIP) { + read = 0; ++ write = 0; + } else { + dma.length = 0; + } +@@ -328,6 +335,9 @@ static void fw_cfg_dma_transfer(FWCfgState *s) + } + } + ++ if (write) { ++ dma.control |= FW_CFG_DMA_CTL_ERROR; ++ } + } else { + if (dma.length <= (e->len - s->cur_offset)) { + len = dma.length; +@@ -349,6 +359,16 @@ static void fw_cfg_dma_transfer(FWCfgState *s) + } + } + ++ if (write) { ++ if (!e->allow_write || ++ len != dma.length || ++ dma_memory_read(s->dma, dma.address, ++ &e->data[s->cur_offset], len)) { ++ dma.control |= FW_CFG_DMA_CTL_ERROR; ++ } ++ } ++ ++ + s->cur_offset += len; + } + +@@ -539,7 +559,8 @@ static const VMStateDescription vmstate_fw_cfg = { + static void fw_cfg_add_bytes_read_callback(FWCfgState *s, uint16_t key, + FWCfgReadCallback callback, + void *callback_opaque, +- void *data, size_t len) ++ void *data, size_t len, ++ bool read_only) + { + int arch = !!(key & FW_CFG_ARCH_LOCAL); + +@@ -552,11 +573,12 @@ static void fw_cfg_add_bytes_read_callback(FWCfgState *s, uint16_t key, + s->entries[arch][key].len = (uint32_t)len; + s->entries[arch][key].read_callback = callback; + s->entries[arch][key].callback_opaque = callback_opaque; ++ s->entries[arch][key].allow_write = !read_only; + } + + void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len) + { +- fw_cfg_add_bytes_read_callback(s, key, NULL, NULL, data, len); ++ fw_cfg_add_bytes_read_callback(s, key, NULL, NULL, data, len, true); + } + + void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value) +@@ -595,7 +617,7 @@ void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value) + + void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, + FWCfgReadCallback callback, void *callback_opaque, +- void *data, size_t len) ++ void *data, size_t len, bool read_only) + { + int i, index; + size_t dsize; +@@ -620,7 +642,8 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, + } + + fw_cfg_add_bytes_read_callback(s, FW_CFG_FILE_FIRST + index, +- callback, callback_opaque, data, len); ++ callback, callback_opaque, data, len, ++ read_only); + + s->files->f[index].size = cpu_to_be32(len); + s->files->f[index].select = cpu_to_be16(FW_CFG_FILE_FIRST + index); +@@ -632,7 +655,7 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, + void fw_cfg_add_file(FWCfgState *s, const char *filename, + void *data, size_t len) + { +- fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len); ++ fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len, true); + } + + static void fw_cfg_machine_ready(struct Notifier *n, void *data) +diff --git a/include/hw/loader.h b/include/hw/loader.h +index a5e02ce..f04a834 100644 +--- a/include/hw/loader.h ++++ b/include/hw/loader.h +@@ -31,7 +31,8 @@ int rom_add_file(const char *file, const char *fw_dir, + bool option_rom); + void *rom_add_blob(const char *name, const void *blob, size_t len, + hwaddr addr, const char *fw_file_name, +- FWCfgReadCallback fw_callback, void *callback_opaque); ++ FWCfgReadCallback fw_callback, void *callback_opaque, ++ bool read_only); + int rom_add_elf_program(const char *name, void *data, size_t datasize, + size_t romsize, hwaddr addr); + int rom_load_all(void); +@@ -44,7 +45,7 @@ void do_info_roms(Monitor *mon, const QDict *qdict); + #define rom_add_file_fixed(_f, _a, _i) \ + rom_add_file(_f, NULL, _a, _i, false) + #define rom_add_blob_fixed(_f, _b, _l, _a) \ +- (rom_add_blob(_f, _b, _l, _a, NULL, NULL, NULL) ? 0 : -1) ++ (rom_add_blob(_f, _b, _l, _a, NULL, NULL, NULL, true) ? 0 : -1) + + #define PC_ROM_MIN_VGA 0xc0000 + #define PC_ROM_MIN_OPTION 0xc8000 +diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h +index b193e38..76fc787 100644 +--- a/include/hw/nvram/fw_cfg.h ++++ b/include/hw/nvram/fw_cfg.h +@@ -83,7 +83,7 @@ void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data, + size_t len); + void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, + FWCfgReadCallback callback, void *callback_opaque, +- void *data, size_t len); ++ void *data, size_t len, bool read_only); + FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port, + hwaddr crl_addr, hwaddr data_addr); + FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-fw_cfg-add-write-callback.patch b/SOURCES/kvm-fw_cfg-add-write-callback.patch new file mode 100644 index 0000000..01f90d6 --- /dev/null +++ b/SOURCES/kvm-fw_cfg-add-write-callback.patch @@ -0,0 +1,173 @@ +From f865f4fe293db1dfdfbb2e03963d0c6a25a398cc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:42 +0100 +Subject: [PATCH 11/41] fw_cfg: add write callback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-12-marcandre.lureau@redhat.com> +Patchwork-id: 78361 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 11/41] fw_cfg: add write callback +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +Reintroduce the write callback that was removed when write support was +removed in commit 023e3148567ac898c7258138f8e86c3c2bb40d07. + +Contrary to the previous callback implementation, the write_cb +callback is called whenever a write happened, so handlers must be +ready to handle partial write as necessary. + +Signed-off-by: Marc-André Lureau +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin + +(cherry picked from commit 5f9252f7cc12c5cec1b3c6695aca02eb52ea7acc) + +RHEL: major conflict due to API changes, but minor functional changes. + +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + hw/core/loader.c | 2 +- + hw/nvram/fw_cfg.c | 32 ++++++++++++++++++++------------ + include/hw/nvram/fw_cfg.h | 8 ++++++-- + 3 files changed, 27 insertions(+), 15 deletions(-) + +diff --git a/hw/core/loader.c b/hw/core/loader.c +index c824bc2..5a15449 100644 +--- a/hw/core/loader.c ++++ b/hw/core/loader.c +@@ -700,7 +700,7 @@ void *rom_add_blob(const char *name, const void *blob, size_t len, + } + + fw_cfg_add_file_callback(fw_cfg, fw_file_name, +- fw_callback, callback_opaque, ++ fw_callback, NULL, callback_opaque, + data, rom->romsize, read_only); + } + return data; +diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c +index a7bc98e..616c782 100644 +--- a/hw/nvram/fw_cfg.c ++++ b/hw/nvram/fw_cfg.c +@@ -54,6 +54,7 @@ typedef struct FWCfgEntry { + uint8_t *data; + void *callback_opaque; + FWCfgReadCallback read_callback; ++ FWCfgWriteCallback write_cb; + } FWCfgEntry; + + struct FWCfgState { +@@ -365,6 +366,8 @@ static void fw_cfg_dma_transfer(FWCfgState *s) + dma_memory_read(s->dma, dma.address, + &e->data[s->cur_offset], len)) { + dma.control |= FW_CFG_DMA_CTL_ERROR; ++ } else if (e->write_cb) { ++ e->write_cb(e->callback_opaque, s->cur_offset, len); + } + } + +@@ -556,11 +559,12 @@ static const VMStateDescription vmstate_fw_cfg = { + } + }; + +-static void fw_cfg_add_bytes_read_callback(FWCfgState *s, uint16_t key, +- FWCfgReadCallback callback, +- void *callback_opaque, +- void *data, size_t len, +- bool read_only) ++static void fw_cfg_add_bytes_callback(FWCfgState *s, uint16_t key, ++ FWCfgReadCallback callback, ++ FWCfgWriteCallback write_cb, ++ void *callback_opaque, ++ void *data, size_t len, ++ bool read_only) + { + int arch = !!(key & FW_CFG_ARCH_LOCAL); + +@@ -572,13 +576,14 @@ static void fw_cfg_add_bytes_read_callback(FWCfgState *s, uint16_t key, + s->entries[arch][key].data = data; + s->entries[arch][key].len = (uint32_t)len; + s->entries[arch][key].read_callback = callback; ++ s->entries[arch][key].write_cb = write_cb; + s->entries[arch][key].callback_opaque = callback_opaque; + s->entries[arch][key].allow_write = !read_only; + } + + void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len) + { +- fw_cfg_add_bytes_read_callback(s, key, NULL, NULL, data, len, true); ++ fw_cfg_add_bytes_callback(s, key, NULL, NULL, NULL, data, len, true); + } + + void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value) +@@ -616,8 +621,11 @@ void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value) + } + + void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, +- FWCfgReadCallback callback, void *callback_opaque, +- void *data, size_t len, bool read_only) ++ FWCfgReadCallback callback, ++ FWCfgWriteCallback write_cb, ++ void *callback_opaque, ++ void *data, size_t len, ++ bool read_only) + { + int i, index; + size_t dsize; +@@ -641,9 +649,9 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, + } + } + +- fw_cfg_add_bytes_read_callback(s, FW_CFG_FILE_FIRST + index, +- callback, callback_opaque, data, len, +- read_only); ++ fw_cfg_add_bytes_callback(s, FW_CFG_FILE_FIRST + index, ++ callback, write_cb, callback_opaque, data, len, ++ read_only); + + s->files->f[index].size = cpu_to_be32(len); + s->files->f[index].select = cpu_to_be16(FW_CFG_FILE_FIRST + index); +@@ -655,7 +663,7 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, + void fw_cfg_add_file(FWCfgState *s, const char *filename, + void *data, size_t len) + { +- fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len, true); ++ fw_cfg_add_file_callback(s, filename, NULL, NULL, NULL, data, len, true); + } + + static void fw_cfg_machine_ready(struct Notifier *n, void *data) +diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h +index 76fc787..a77ab84 100644 +--- a/include/hw/nvram/fw_cfg.h ++++ b/include/hw/nvram/fw_cfg.h +@@ -73,6 +73,7 @@ typedef struct FWCfgDmaAccess { + + typedef void (*FWCfgCallback)(void *opaque, uint8_t *data); + typedef void (*FWCfgReadCallback)(void *opaque, uint32_t offset); ++typedef void (*FWCfgWriteCallback)(void *opaque, off_t start, size_t len); + + void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len); + void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value); +@@ -82,8 +83,11 @@ void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value); + void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data, + size_t len); + void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, +- FWCfgReadCallback callback, void *callback_opaque, +- void *data, size_t len, bool read_only); ++ FWCfgReadCallback callback, ++ FWCfgWriteCallback write_cb, ++ void *callback_opaque, ++ void *data, size_t len, ++ bool read_only); + FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port, + hwaddr crl_addr, hwaddr data_addr); + FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-fw_cfg-avoid-calculating-invalid-current-entry-point.patch b/SOURCES/kvm-fw_cfg-avoid-calculating-invalid-current-entry-point.patch new file mode 100644 index 0000000..5ab5257 --- /dev/null +++ b/SOURCES/kvm-fw_cfg-avoid-calculating-invalid-current-entry-point.patch @@ -0,0 +1,67 @@ +From 8fb3ac70845fbe261407e7782d3e6233e368da8f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:37 +0100 +Subject: [PATCH 06/41] fw_cfg: avoid calculating invalid current entry pointer +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-7-marcandre.lureau@redhat.com> +Patchwork-id: 78355 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 06/41] fw_cfg: avoid calculating invalid current entry pointer +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: "Gabriel L. Somlo" + +When calculating a pointer to the currently selected fw_cfg item, the +following is used: + + FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK]; + +When s->cur_entry is FW_CFG_INVALID, we are calculating the address of +a non-existent element in s->entries[arch][...], which is undefined. + +This patch ensures the resulting entry pointer is set to NULL whenever +s->cur_entry is FW_CFG_INVALID. + +Reported-by: Laszlo Ersek +Reviewed-by: Laszlo Ersek +Signed-off-by: Gabriel Somlo +Message-id: 1446733972-1602-5-git-send-email-somlo@cmu.edu +Cc: Marc Marí +Signed-off-by: Gabriel Somlo +Reviewed-by: Laszlo Ersek +Signed-off-by: Gerd Hoffmann + +(cherry picked from commit 66f8fd9dda312191b78d2a2ba2848bcee76127a2) + +RHEL: fix minor conflicts due to previous partial backport in commit + ba24567fd90702ea40ff320a79bc921b38510f22. + +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + hw/nvram/fw_cfg.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c +index 85e950c..1317df7 100644 +--- a/hw/nvram/fw_cfg.c ++++ b/hw/nvram/fw_cfg.c +@@ -301,7 +301,8 @@ static void fw_cfg_dma_transfer(FWCfgState *s) + } + + arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL); +- e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK]; ++ e = (s->cur_entry == FW_CFG_INVALID) ? NULL : ++ &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK]; + + if (dma.control & FW_CFG_DMA_CTL_READ) { + read = 1; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-fw_cfg-enable-DMA-if-device-vmcoreinfo.patch b/SOURCES/kvm-fw_cfg-enable-DMA-if-device-vmcoreinfo.patch new file mode 100644 index 0000000..7553cc9 --- /dev/null +++ b/SOURCES/kvm-fw_cfg-enable-DMA-if-device-vmcoreinfo.patch @@ -0,0 +1,75 @@ +From 9d150071a8170807a0e5f638e3eddbbc29219ddc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:45 +0100 +Subject: [PATCH 14/41] fw_cfg: enable DMA if -device vmcoreinfo +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-15-marcandre.lureau@redhat.com> +Patchwork-id: 78364 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 14/41] fw_cfg: enable DMA if -device vmcoreinfo +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +Upstream status: RHEL-only + +vmcoreinfo needs fw_cfg with DMA enabled. However, for compatibility +reasons, DMA can't be enabled by default. In order to avoid having a +RHEL-specific libvirt patch to enable DMA when vmcoreinfo device is +requested, it can be done in qemu directly. + +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + hw/nvram/fw_cfg.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c +index 616c782..7caf43c 100644 +--- a/hw/nvram/fw_cfg.c ++++ b/hw/nvram/fw_cfg.c +@@ -30,6 +30,7 @@ + #include "trace.h" + #include "qemu/error-report.h" + #include "qemu/config-file.h" ++#include "qemu/option.h" + + #define FW_CFG_CTL_SIZE 2 + #define FW_CFG_DATA_SIZE 1 +@@ -675,6 +676,17 @@ static void fw_cfg_machine_ready(struct Notifier *n, void *data) + fw_cfg_add_file(s, "bootorder", (uint8_t*)bootindex, len); + } + ++static int driver_is_vmcoreinfo(QemuOpts *opts, void *opaque) ++{ ++ return g_strcmp0(qemu_opt_get(opts, "driver"), "vmcoreinfo") == 0; ++} ++ ++static bool opts_has_vmcoreinfo(void) ++{ ++ return qemu_opts_foreach(qemu_find_opts("device"), ++ driver_is_vmcoreinfo, NULL, 1) != 0; ++} ++ + static FWCfgState * + fw_cfg_init_dma(uint32_t ctl_port, uint32_t data_port, + uint32_t dma_port, +@@ -692,6 +704,11 @@ fw_cfg_init_dma(uint32_t ctl_port, uint32_t data_port, + qdev_prop_set_uint32(dev, "data_iobase", data_port); + qdev_prop_set_uint32(dev, "dma_iobase", dma_port); + ++ if (opts_has_vmcoreinfo()) { ++ /* RHEL-only: enable DMA operations for vmcoreinfo device */ ++ qdev_prop_set_bit(dev, "dma_enabled", true); ++ } ++ + if (!dma_requested) { + qdev_prop_set_bit(dev, "dma_enabled", false); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-fw_cfg-factor-out-initialization-of-FW_CFG_ID-rev.-n.patch b/SOURCES/kvm-fw_cfg-factor-out-initialization-of-FW_CFG_ID-rev.-n.patch new file mode 100644 index 0000000..9cd13ec --- /dev/null +++ b/SOURCES/kvm-fw_cfg-factor-out-initialization-of-FW_CFG_ID-rev.-n.patch @@ -0,0 +1,149 @@ +From 0dbf3617c8b4dda06460190d4017a5bc605f79d9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:35 +0100 +Subject: [PATCH 04/41] fw_cfg: factor out initialization of FW_CFG_ID (rev. + number) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-5-marcandre.lureau@redhat.com> +Patchwork-id: 78354 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 04/41] fw_cfg: factor out initialization of FW_CFG_ID (rev. number) +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: "Gabriel L. Somlo" + +The fw_cfg documentation says this of the revision key (0x0001, FW_CFG_ID): + +> A 32-bit little-endian unsigned int, this item is used as an interface +> revision number, and is currently set to 1 by all QEMU architectures +> which expose a fw_cfg device. + +arm/virt doesn't. It could be argued that that's an error in +"hw/arm/virt.c"; on the other hand, all of the other fw_cfg providing +boards set the interface version to 1 manually, despite the device +coming from the same, shared implementation. Therefore, instead of +adding + + fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); + +to arm/virt, consolidate all such existing calls in the fw_cfg +initialization code. + +Signed-off-by: Gabriel Somlo +Message-Id: <1426789244-26318-1-git-send-email-somlo@cmu.edu> +Reviewed-by: Laszlo Ersek +Signed-off-by: Paolo Bonzini + +(cherry picked from commit 3a5c76baf312d83cb77c8faa72c5f7a477effed0) + +RHEL: Remove a few extra calls that got removed in upstream + commit 6a4e17711442849bf2cc731ccddef5a2a2d92d29. + +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + hw/i386/pc.c | 1 - + hw/nvram/fw_cfg.c | 1 + + hw/ppc/mac_newworld.c | 1 - + hw/ppc/mac_oldworld.c | 1 - + hw/sparc/sun4m.c | 3 --- + hw/sparc64/sun4u.c | 1 - + 6 files changed, 1 insertion(+), 7 deletions(-) + +diff --git a/hw/i386/pc.c b/hw/i386/pc.c +index 1468d50..29d6588 100644 +--- a/hw/i386/pc.c ++++ b/hw/i386/pc.c +@@ -625,7 +625,6 @@ static FWCfgState *bochs_bios_init(void) + * the APIC ID, not the "CPU index" + */ + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)apic_id_limit); +- fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); + fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); + fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES, + acpi_tables, acpi_tables_len); +diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c +index a33e861..01d4566 100644 +--- a/hw/nvram/fw_cfg.c ++++ b/hw/nvram/fw_cfg.c +@@ -506,6 +506,7 @@ FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port, + sysbus_mmio_map(d, 1, data_addr); + } + fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4); ++ fw_cfg_add_i32(s, FW_CFG_ID, 1); + fw_cfg_add_bytes(s, FW_CFG_UUID, qemu_uuid, 16); + fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)(display_type == DT_NOGRAPHIC)); + fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus); +diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c +index ce44e95..77446d7 100644 +--- a/hw/ppc/mac_newworld.c ++++ b/hw/ppc/mac_newworld.c +@@ -416,7 +416,6 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) + + fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); +- fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); + fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); + fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, machine_arch); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base); +diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c +index 3acca94..d52a110 100644 +--- a/hw/ppc/mac_oldworld.c ++++ b/hw/ppc/mac_oldworld.c +@@ -300,7 +300,6 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) + + fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); +- fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); + fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); + fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, ARCH_HEATHROW); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base); +diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c +index 7c5b8e7..3c126e0 100644 +--- a/hw/sparc/sun4m.c ++++ b/hw/sparc/sun4m.c +@@ -1029,7 +1029,6 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size, + + fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); +- fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); + fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); + fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); + fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_DEPTH, graphic_depth); +@@ -1674,7 +1673,6 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size, + + fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); +- fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); + fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); + fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); + fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_DEPTH, graphic_depth); +@@ -1875,7 +1873,6 @@ static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size, + + fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); +- fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); + fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); + fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); + fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_DEPTH, graphic_depth); +diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c +index 5ce5ed6..63447fc 100644 +--- a/hw/sparc64/sun4u.c ++++ b/hw/sparc64/sun4u.c +@@ -885,7 +885,6 @@ static void sun4uv_init(MemoryRegion *address_space_mem, + + fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0); + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); +- fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); + fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); + fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); + fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_entry); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-fw_cfg-prevent-selector-key-conflict.patch b/SOURCES/kvm-fw_cfg-prevent-selector-key-conflict.patch new file mode 100644 index 0000000..5bc98f7 --- /dev/null +++ b/SOURCES/kvm-fw_cfg-prevent-selector-key-conflict.patch @@ -0,0 +1,47 @@ +From f893c8d5665ce4c9978eb7428b57f5e84448836c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:33 +0100 +Subject: [PATCH 02/41] fw_cfg: prevent selector key conflict +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-3-marcandre.lureau@redhat.com> +Patchwork-id: 78352 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 02/41] fw_cfg: prevent selector key conflict +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: "Gabriel L. Somlo" + +Enforce a single assignment of data for each distinct selector key. + +Signed-off-by: Gabriel Somlo +Reviewed-by: Laszlo Ersek +Signed-off-by: Gerd Hoffmann + +(cherry picked from commit 0f9b214139d11ef058fa0f1c11c89e94fa6ef95d) +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + hw/nvram/fw_cfg.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c +index 9d7b99e..149e2fb 100644 +--- a/hw/nvram/fw_cfg.c ++++ b/hw/nvram/fw_cfg.c +@@ -380,6 +380,7 @@ static void fw_cfg_add_bytes_read_callback(FWCfgState *s, uint16_t key, + key &= FW_CFG_ENTRY_MASK; + + assert(key < FW_CFG_MAX_ENTRY && len < UINT32_MAX); ++ assert(s->entries[arch][key].data == NULL); /* avoid key conflict */ + + s->entries[arch][key].data = data; + s->entries[arch][key].len = (uint32_t)len; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-fw_cfg-prohibit-insertion-of-duplicate-fw_cfg-file-n.patch b/SOURCES/kvm-fw_cfg-prohibit-insertion-of-duplicate-fw_cfg-file-n.patch new file mode 100644 index 0000000..ac5184c --- /dev/null +++ b/SOURCES/kvm-fw_cfg-prohibit-insertion-of-duplicate-fw_cfg-file-n.patch @@ -0,0 +1,80 @@ +From 08eb83666fe11d81813270541bcb76bad8bd5902 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:34 +0100 +Subject: [PATCH 03/41] fw_cfg: prohibit insertion of duplicate fw_cfg file + names +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-4-marcandre.lureau@redhat.com> +Patchwork-id: 78351 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 03/41] fw_cfg: prohibit insertion of duplicate fw_cfg file names +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: "Gabriel L. Somlo" + +Exit with an error (instead of simply logging a trace event) +whenever the same fw_cfg file name is added multiple times via +one of the fw_cfg_add_file[_callback]() host-side API calls. + +Signed-off-by: Gabriel Somlo +Reviewed-by: Laszlo Ersek +Signed-off-by: Gerd Hoffmann + +(cherry picked from commit 0eb973f91521c6bcb6399d25327711d083f6eb10) +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + hw/nvram/fw_cfg.c | 11 ++++++----- + trace-events | 1 - + 2 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c +index 149e2fb..a33e861 100644 +--- a/hw/nvram/fw_cfg.c ++++ b/hw/nvram/fw_cfg.c +@@ -443,18 +443,19 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, + index = be32_to_cpu(s->files->count); + assert(index < FW_CFG_FILE_SLOTS); + +- fw_cfg_add_bytes_read_callback(s, FW_CFG_FILE_FIRST + index, +- callback, callback_opaque, data, len); +- + pstrcpy(s->files->f[index].name, sizeof(s->files->f[index].name), + filename); + for (i = 0; i < index; i++) { + if (strcmp(s->files->f[index].name, s->files->f[i].name) == 0) { +- trace_fw_cfg_add_file_dupe(s, s->files->f[index].name); +- return; ++ error_report("duplicate fw_cfg file name: %s", ++ s->files->f[index].name); ++ exit(1); + } + } + ++ fw_cfg_add_bytes_read_callback(s, FW_CFG_FILE_FIRST + index, ++ callback, callback_opaque, data, len); ++ + s->files->f[index].size = cpu_to_be32(len); + s->files->f[index].select = cpu_to_be16(FW_CFG_FILE_FIRST + index); + trace_fw_cfg_add_file(s, index, s->files->f[index].name, len); +diff --git a/trace-events b/trace-events +index a987dfa..8c3ce0c 100644 +--- a/trace-events ++++ b/trace-events +@@ -178,7 +178,6 @@ ecc_diag_mem_readb(uint64_t addr, uint32_t ret) "Read diagnostic %"PRId64"= %02x + # hw/nvram/fw_cfg.c + fw_cfg_select(void *s, uint16_t key, int ret) "%p key %d = %d" + fw_cfg_read(void *s, uint8_t ret) "%p = %d" +-fw_cfg_add_file_dupe(void *s, char *name) "%p %s" + fw_cfg_add_file(void *s, int index, char *name, size_t len) "%p #%d: %s (%zd bytes)" + + # hw/block/hd-geometry.c +-- +1.8.3.1 + diff --git a/SOURCES/kvm-fw_cfg-remove-support-for-guest-side-data-writes.patch b/SOURCES/kvm-fw_cfg-remove-support-for-guest-side-data-writes.patch new file mode 100644 index 0000000..bf1b7c7 --- /dev/null +++ b/SOURCES/kvm-fw_cfg-remove-support-for-guest-side-data-writes.patch @@ -0,0 +1,130 @@ +From bc5ebe6df8479b32dbf46f75f32cfad7008a14f0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:32 +0100 +Subject: [PATCH 01/41] fw_cfg: remove support for guest-side data writes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-2-marcandre.lureau@redhat.com> +Patchwork-id: 78353 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 01/41] fw_cfg: remove support for guest-side data writes +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: "Gabriel L. Somlo" + +>From this point forward, any guest-side writes to the fw_cfg +data register will be treated as no-ops. This patch also removes +the unused host-side API function fw_cfg_add_callback(), which +allowed the registration of a callback to be executed each time +the guest completed a full overwrite of a given fw_cfg data item. + +Signed-off-by: Gabriel Somlo +Reviewed-by: Laszlo Ersek +Signed-off-by: Gerd Hoffmann + +(cherry picked from commit 023e3148567ac898c7258138f8e86c3c2bb40d07) + +RHEL: Fix conflicts, due to fw_cfg_modify_bytes_read() introduction in + upstream commit bdbb5b1706d165e8d4222121f1e9b59b6b4359ce. + +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + hw/nvram/fw_cfg.c | 35 +---------------------------------- + include/hw/nvram/fw_cfg.h | 2 -- + trace-events | 1 - + 3 files changed, 1 insertion(+), 37 deletions(-) + +diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c +index fcb3146..9d7b99e 100644 +--- a/hw/nvram/fw_cfg.c ++++ b/hw/nvram/fw_cfg.c +@@ -40,7 +40,6 @@ typedef struct FWCfgEntry { + uint32_t len; + uint8_t *data; + void *callback_opaque; +- FWCfgCallback callback; + FWCfgReadCallback read_callback; + } FWCfgEntry; + +@@ -206,22 +205,7 @@ static void fw_cfg_reboot(FWCfgState *s) + + static void fw_cfg_write(FWCfgState *s, uint8_t value) + { +- int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL); +- FWCfgEntry *e = (s->cur_entry == FW_CFG_INVALID) ? NULL : +- &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK]; +- +- trace_fw_cfg_write(s, value); +- +- if (s->cur_entry & FW_CFG_WRITE_CHANNEL +- && e != NULL +- && e->callback +- && s->cur_offset < e->len) { +- e->data[s->cur_offset++] = value; +- if (s->cur_offset == e->len) { +- e->callback(e->callback_opaque, e->data); +- s->cur_offset = 0; +- } +- } ++ /* nothing, write support removed in QEMU v2.4+ */ + } + + static int fw_cfg_select(FWCfgState *s, uint16_t key) +@@ -442,23 +426,6 @@ void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value) + fw_cfg_add_bytes(s, key, copy, sizeof(value)); + } + +-void fw_cfg_add_callback(FWCfgState *s, uint16_t key, FWCfgCallback callback, +- void *callback_opaque, void *data, size_t len) +-{ +- int arch = !!(key & FW_CFG_ARCH_LOCAL); +- +- assert(key & FW_CFG_WRITE_CHANNEL); +- +- key &= FW_CFG_ENTRY_MASK; +- +- assert(key < FW_CFG_MAX_ENTRY && len <= UINT32_MAX); +- +- s->entries[arch][key].data = data; +- s->entries[arch][key].len = (uint32_t)len; +- s->entries[arch][key].callback_opaque = callback_opaque; +- s->entries[arch][key].callback = callback; +-} +- + void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, + FWCfgReadCallback callback, void *callback_opaque, + void *data, size_t len) +diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h +index 72b1549..aa5f351 100644 +--- a/include/hw/nvram/fw_cfg.h ++++ b/include/hw/nvram/fw_cfg.h +@@ -69,8 +69,6 @@ void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value); + void fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value); + void fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value); + void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value); +-void fw_cfg_add_callback(FWCfgState *s, uint16_t key, FWCfgCallback callback, +- void *callback_opaque, void *data, size_t len); + void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data, + size_t len); + void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, +diff --git a/trace-events b/trace-events +index fa2618d..a987dfa 100644 +--- a/trace-events ++++ b/trace-events +@@ -176,7 +176,6 @@ ecc_diag_mem_writeb(uint64_t addr, uint32_t val) "Write diagnostic %"PRId64" = % + ecc_diag_mem_readb(uint64_t addr, uint32_t ret) "Read diagnostic %"PRId64"= %02x" + + # hw/nvram/fw_cfg.c +-fw_cfg_write(void *s, uint8_t value) "%p %d" + fw_cfg_select(void *s, uint16_t key, int ret) "%p key %d = %d" + fw_cfg_read(void *s, uint8_t ret) "%p = %d" + fw_cfg_add_file_dupe(void *s, char *name) "%p %s" +-- +1.8.3.1 + diff --git a/SOURCES/kvm-fw_cfg-unbreak-migration-compatibility.patch b/SOURCES/kvm-fw_cfg-unbreak-migration-compatibility.patch new file mode 100644 index 0000000..8c0a6f6 --- /dev/null +++ b/SOURCES/kvm-fw_cfg-unbreak-migration-compatibility.patch @@ -0,0 +1,74 @@ +From 1d05047c15ca1d8e29dcb0892e449987739682b4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:40 +0100 +Subject: [PATCH 09/41] fw_cfg: unbreak migration compatibility +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-10-marcandre.lureau@redhat.com> +Patchwork-id: 78359 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 09/41] fw_cfg: unbreak migration compatibility +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: Laszlo Ersek + +Upstream-status: RHEL only + +fw_cfg DMA shouldn't be enabled by default on x86, or it will break +migration from new (DMA) to old (non-DMA) qemu. + +Thus we must maintain DMA disabled by default. Since we don't +introduce a new machine, only if requested explicitely with -global +fw_cfg.dma_enabled=on, or -device vmcoreinfo (see upcoming RHEL-only +patch) should DMA be enabled. + +(this is somewhat similar to upstream commit +e6915b5f3a874a467a9a65f7ec1d6ef8d251a51a, except that we can't enable +DMA by default on RHEL qemu) + +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + hw/nvram/fw_cfg.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c +index 1789487..a7bc98e 100644 +--- a/hw/nvram/fw_cfg.c ++++ b/hw/nvram/fw_cfg.c +@@ -677,13 +677,16 @@ fw_cfg_init_dma(uint32_t ctl_port, uint32_t data_port, + SysBusDevice *d; + FWCfgState *s; + uint32_t version = FW_CFG_VERSION; +- bool dma_enabled = dma_port && dma_as; ++ bool dma_requested = dma_port && dma_as; + + dev = qdev_create(NULL, "fw_cfg"); + qdev_prop_set_uint32(dev, "ctl_iobase", ctl_port); + qdev_prop_set_uint32(dev, "data_iobase", data_port); + qdev_prop_set_uint32(dev, "dma_iobase", dma_port); +- qdev_prop_set_bit(dev, "dma_enabled", dma_enabled); ++ ++ if (!dma_requested) { ++ qdev_prop_set_bit(dev, "dma_enabled", false); ++ } + + d = SYS_BUS_DEVICE(dev); + +@@ -702,7 +705,7 @@ fw_cfg_init_dma(uint32_t ctl_port, uint32_t data_port, + if (data_addr) { + sysbus_mmio_map(d, 1, data_addr); + } +- if (dma_enabled) { ++ if (s->dma_enabled) { + /* 64 bits for the address field */ + s->dma = &dma_context_memory; + s->dma_addr = 0; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-hw-misc-add-vmcoreinfo-device.patch b/SOURCES/kvm-hw-misc-add-vmcoreinfo-device.patch new file mode 100644 index 0000000..4b83a2d --- /dev/null +++ b/SOURCES/kvm-hw-misc-add-vmcoreinfo-device.patch @@ -0,0 +1,262 @@ +From 8d7f958d14fa739c64436d0926bc712eaa63fe14 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:43 +0100 +Subject: [PATCH 12/41] hw/misc: add vmcoreinfo device +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-13-marcandre.lureau@redhat.com> +Patchwork-id: 78362 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 12/41] hw/misc: add vmcoreinfo device +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +See docs/specs/vmcoreinfo.txt for details. + +"etc/vmcoreinfo" fw_cfg entry is added when using "-device vmcoreinfo". + +Signed-off-by: Marc-André Lureau +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin + +(cherry picked from commit 6e43353f10c6688060af0bc26bdfdd4cf9c96ea2) + +RHEL: adapted to qemu 1.5 API. + +FWCfgState is not exposed, use object_property_get_bool() instead. + +DeviceClass.hotpluggable doesn't exist. Not important since libvirt +shouldn't allow or do 'device_add vmcoreinfo'. + +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + docs/specs/vmcoreinfo.txt | 41 +++++++++++++++++++ + hw/misc/Makefile.objs | 1 + + hw/misc/vmcoreinfo.c | 96 ++++++++++++++++++++++++++++++++++++++++++++ + include/hw/misc/vmcoreinfo.h | 46 +++++++++++++++++++++ + 4 files changed, 184 insertions(+) + create mode 100644 docs/specs/vmcoreinfo.txt + create mode 100644 hw/misc/vmcoreinfo.c + create mode 100644 include/hw/misc/vmcoreinfo.h + +diff --git a/docs/specs/vmcoreinfo.txt b/docs/specs/vmcoreinfo.txt +new file mode 100644 +index 0000000..2868a77 +--- /dev/null ++++ b/docs/specs/vmcoreinfo.txt +@@ -0,0 +1,41 @@ ++================= ++VMCoreInfo device ++================= ++ ++The `-device vmcoreinfo` will create a fw_cfg entry for a guest to ++store dump details. ++ ++etc/vmcoreinfo ++************** ++ ++A guest may use this fw_cfg entry to add information details to qemu ++dumps. ++ ++The entry of 16 bytes has the following layout, in little-endian:: ++ ++#define VMCOREINFO_FORMAT_NONE 0x0 ++#define VMCOREINFO_FORMAT_ELF 0x1 ++ ++ struct FWCfgVMCoreInfo { ++ uint16_t host_format; /* formats host supports */ ++ uint16_t guest_format; /* format guest supplies */ ++ uint32_t size; /* size of vmcoreinfo region */ ++ uint64_t paddr; /* physical address of vmcoreinfo region */ ++ }; ++ ++Only full write (of 16 bytes) are considered valid for further ++processing of entry values. ++ ++A write of 0 in guest_format will disable further processing of ++vmcoreinfo entry values & content. ++ ++Format & content ++**************** ++ ++As of qemu 2.11, only VMCOREINFO_FORMAT_ELF is supported. ++ ++The entry gives location and size of an ELF note that is appended in ++qemu dumps. ++ ++The note format/class must be of the target bitness and the size must ++be less than 1Mb. +diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs +index cd3123b..39b6593 100644 +--- a/hw/misc/Makefile.objs ++++ b/hw/misc/Makefile.objs +@@ -5,6 +5,7 @@ common-obj-$(CONFIG_ISA_DEBUG) += debugexit.o + common-obj-$(CONFIG_SGA) += sga.o + common-obj-$(CONFIG_ISA_TESTDEV) += pc-testdev.o + common-obj-$(CONFIG_PCI_TESTDEV) += pci-testdev.o ++common-obj-y += vmcoreinfo.o + + obj-$(CONFIG_VMPORT) += vmport.o + +diff --git a/hw/misc/vmcoreinfo.c b/hw/misc/vmcoreinfo.c +new file mode 100644 +index 0000000..1bf6735 +--- /dev/null ++++ b/hw/misc/vmcoreinfo.c +@@ -0,0 +1,96 @@ ++/* ++ * Virtual Machine coreinfo device ++ * ++ * Copyright (C) 2017 Red Hat, Inc. ++ * ++ * Authors: Marc-André Lureau ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ */ ++#include "qemu/osdep.h" ++#include "qapi/error.h" ++#include "hw/nvram/fw_cfg.h" ++#include "hw/misc/vmcoreinfo.h" ++ ++static void fw_cfg_vmci_write(void *dev, off_t offset, size_t len) ++{ ++ VMCoreInfoState *s = VMCOREINFO(dev); ++ ++ s->has_vmcoreinfo = offset == 0 && len == sizeof(s->vmcoreinfo) ++ && s->vmcoreinfo.guest_format != VMCOREINFO_FORMAT_NONE; ++} ++ ++static void vmcoreinfo_reset(void *dev) ++{ ++ VMCoreInfoState *s = VMCOREINFO(dev); ++ ++ s->has_vmcoreinfo = false; ++ memset(&s->vmcoreinfo, 0, sizeof(s->vmcoreinfo)); ++ s->vmcoreinfo.host_format = cpu_to_le16(VMCOREINFO_FORMAT_ELF); ++} ++ ++static void vmcoreinfo_realize(DeviceState *dev, Error **errp) ++{ ++ VMCoreInfoState *s = VMCOREINFO(dev); ++ FWCfgState *fw_cfg = fw_cfg_find(); ++ ++ /* Given that this function is executing, there is at least one VMCOREINFO ++ * device. Check if there are several. ++ */ ++ if (!vmcoreinfo_find()) { ++ error_setg(errp, "at most one %s device is permitted", ++ VMCOREINFO_DEVICE); ++ return; ++ } ++ ++ if (!fw_cfg || !object_property_get_bool(OBJECT(fw_cfg), "dma_enabled", NULL)) { ++ error_setg(errp, "%s device requires fw_cfg with DMA", ++ VMCOREINFO_DEVICE); ++ return; ++ } ++ ++ fw_cfg_add_file_callback(fw_cfg, "etc/vmcoreinfo", ++ NULL, fw_cfg_vmci_write, s, ++ &s->vmcoreinfo, sizeof(s->vmcoreinfo), ++ false); ++ ++ qemu_register_reset(vmcoreinfo_reset, dev); ++} ++ ++static const VMStateDescription vmstate_vmcoreinfo = { ++ .name = "vmcoreinfo", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField[]) { ++ VMSTATE_BOOL(has_vmcoreinfo, VMCoreInfoState), ++ VMSTATE_UINT16(vmcoreinfo.host_format, VMCoreInfoState), ++ VMSTATE_UINT16(vmcoreinfo.guest_format, VMCoreInfoState), ++ VMSTATE_UINT32(vmcoreinfo.size, VMCoreInfoState), ++ VMSTATE_UINT64(vmcoreinfo.paddr, VMCoreInfoState), ++ VMSTATE_END_OF_LIST() ++ }, ++}; ++ ++static void vmcoreinfo_device_class_init(ObjectClass *klass, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(klass); ++ ++ dc->vmsd = &vmstate_vmcoreinfo; ++ dc->realize = vmcoreinfo_realize; ++} ++ ++static const TypeInfo vmcoreinfo_device_info = { ++ .name = VMCOREINFO_DEVICE, ++ .parent = TYPE_DEVICE, ++ .instance_size = sizeof(VMCoreInfoState), ++ .class_init = vmcoreinfo_device_class_init, ++}; ++ ++static void vmcoreinfo_register_types(void) ++{ ++ type_register_static(&vmcoreinfo_device_info); ++} ++ ++type_init(vmcoreinfo_register_types) +diff --git a/include/hw/misc/vmcoreinfo.h b/include/hw/misc/vmcoreinfo.h +new file mode 100644 +index 0000000..c3aa856 +--- /dev/null ++++ b/include/hw/misc/vmcoreinfo.h +@@ -0,0 +1,46 @@ ++/* ++ * Virtual Machine coreinfo device ++ * ++ * Copyright (C) 2017 Red Hat, Inc. ++ * ++ * Authors: Marc-André Lureau ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ */ ++#ifndef VMCOREINFO_H ++#define VMCOREINFO_H ++ ++#include "hw/qdev.h" ++ ++#define VMCOREINFO_DEVICE "vmcoreinfo" ++#define VMCOREINFO(obj) OBJECT_CHECK(VMCoreInfoState, (obj), VMCOREINFO_DEVICE) ++ ++#define VMCOREINFO_FORMAT_NONE 0x0 ++#define VMCOREINFO_FORMAT_ELF 0x1 ++ ++/* all fields are little-endian */ ++typedef struct FWCfgVMCoreInfo { ++ uint16_t host_format; /* set on reset */ ++ uint16_t guest_format; ++ uint32_t size; ++ uint64_t paddr; ++} QEMU_PACKED FWCfgVMCoreInfo; ++ ++typedef struct VMCoreInfoState { ++ DeviceClass parent_obj; ++ ++ bool has_vmcoreinfo; ++ FWCfgVMCoreInfo vmcoreinfo; ++} VMCoreInfoState; ++ ++/* returns NULL unless there is exactly one device */ ++static inline VMCoreInfoState *vmcoreinfo_find(void) ++{ ++ Object *o = object_resolve_path_type("", VMCOREINFO_DEVICE, NULL); ++ ++ return o ? VMCOREINFO(o) : NULL; ++} ++ ++#endif +-- +1.8.3.1 + diff --git a/SOURCES/kvm-hw-use-ld_p-st_p-instead-of-ld_raw-st_raw.patch b/SOURCES/kvm-hw-use-ld_p-st_p-instead-of-ld_raw-st_raw.patch index 071baa0..6892a53 100644 --- a/SOURCES/kvm-hw-use-ld_p-st_p-instead-of-ld_raw-st_raw.patch +++ b/SOURCES/kvm-hw-use-ld_p-st_p-instead-of-ld_raw-st_raw.patch @@ -1,13 +1,13 @@ -From e4c72f672ead22ca78bbdef54517c120f39cf531 Mon Sep 17 00:00:00 2001 +From 7303beb9c00357762941f602807439512b2b1916 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 5 Oct 2017 14:51:14 +0200 -Subject: [PATCH 02/11] hw: use ld_p/st_p instead of ld_raw/st_raw +Subject: [PATCH 18/27] hw: use ld_p/st_p instead of ld_raw/st_raw RH-Author: Gerd Hoffmann Message-id: <20171005145119.15277-3-kraxel@redhat.com> Patchwork-id: 76827 O-Subject: [RHEL-7.5 qemu-kvm PATCH 2/7] hw: use ld_p/st_p instead of ld_raw/st_raw -Bugzilla: 1501294 +Bugzilla: 1486642 RH-Acked-by: Dr. David Alan Gilbert RH-Acked-by: Thomas Huth RH-Acked-by: Miroslav Rezanina diff --git a/SOURCES/kvm-hw-vfio-pci-Introduce-VFIORegion.patch b/SOURCES/kvm-hw-vfio-pci-Introduce-VFIORegion.patch new file mode 100644 index 0000000..b3e5d05 --- /dev/null +++ b/SOURCES/kvm-hw-vfio-pci-Introduce-VFIORegion.patch @@ -0,0 +1,517 @@ +From 725ad24f771adcc8aeacaf27b21a6d95cab41e69 Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Fri, 29 Sep 2017 21:45:02 +0200 +Subject: [PATCH 07/27] hw/vfio/pci: Introduce VFIORegion + +RH-Author: Alex Williamson +Message-id: <20170929214502.16765.46217.stgit@gimli.home> +Patchwork-id: 76765 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 07/16] hw/vfio/pci: Introduce VFIORegion +Bugzilla: 1494181 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Auger Eric +RH-Acked-by: Miroslav Rezanina + +From: Eric Auger + +Upstream: a664477db8dac84cc046e9d79701eefda1d58703 + +This structure is going to be shared by VFIOPCIDevice and +VFIOPlatformDevice. VFIOBAR includes it. + +vfio_eoi becomes an ops of VFIODevice specialized by parent device. +This makes possible to transform vfio_bar_write/read into generic +vfio_region_write/read that will be used by VFIOPlatformDevice too. + +vfio_mmap_bar becomes vfio_map_region + +Signed-off-by: Eric Auger +Signed-off-by: Alex Williamson +Signed-off-by: Miroslav Rezanina +--- + hw/misc/vfio.c | 188 +++++++++++++++++++++++++++++---------------------------- + 1 file changed, 97 insertions(+), 91 deletions(-) + +diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c +index 3e559ed..92414b9 100644 +--- a/hw/misc/vfio.c ++++ b/hw/misc/vfio.c +@@ -84,15 +84,19 @@ typedef struct VFIOQuirk { + } data; + } VFIOQuirk; + +-typedef struct VFIOBAR { +- off_t fd_offset; /* offset of BAR within device fd */ +- int fd; /* device fd, allows us to pass VFIOBAR as opaque data */ ++typedef struct VFIORegion { ++ struct VFIODevice *vbasedev; ++ off_t fd_offset; /* offset of region within device fd */ + MemoryRegion mem; /* slow, read/write access */ + MemoryRegion mmap_mem; /* direct mapped access */ + void *mmap; + size_t size; + uint32_t flags; /* VFIO region flags (rd/wr/mmap) */ +- uint8_t nr; /* cache the BAR number for debug */ ++ uint8_t nr; /* cache the region number for debug */ ++} VFIORegion; ++ ++typedef struct VFIOBAR { ++ VFIORegion region; + bool ioport; + bool mem64; + QLIST_HEAD(, VFIOQuirk) quirks; +@@ -194,6 +198,7 @@ typedef struct VFIODevice { + struct VFIODeviceOps { + void (*vfio_compute_needs_reset)(VFIODevice *vdev); + int (*vfio_hot_reset_multi)(VFIODevice *vdev); ++ void (*vfio_eoi)(VFIODevice *vdev); + }; + + typedef struct VFIOPCIDevice { +@@ -383,8 +388,10 @@ static void vfio_intx_interrupt(void *opaque) + } + } + +-static void vfio_eoi(VFIOPCIDevice *vdev) ++static void vfio_eoi(VFIODevice *vbasedev) + { ++ VFIOPCIDevice *vdev = container_of(vbasedev, VFIOPCIDevice, vbasedev); ++ + if (!vdev->intx.pending) { + return; + } +@@ -394,7 +401,7 @@ static void vfio_eoi(VFIOPCIDevice *vdev) + + vdev->intx.pending = false; + qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0); +- vfio_unmask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); ++ vfio_unmask_single_irqindex(vbasedev, VFIO_PCI_INTX_IRQ_INDEX); + } + + static void vfio_enable_intx_kvm(VFIOPCIDevice *vdev) +@@ -549,7 +556,7 @@ static void vfio_update_irq(PCIDevice *pdev) + vfio_enable_intx_kvm(vdev); + + /* Re-enable the interrupt in cased we missed an EOI */ +- vfio_eoi(vdev); ++ vfio_eoi(&vdev->vbasedev); + } + + static int vfio_enable_intx(VFIOPCIDevice *vdev) +@@ -1086,10 +1093,11 @@ static void vfio_update_msi(VFIOPCIDevice *vdev) + /* + * IO Port/MMIO - Beware of the endians, VFIO is always little endian + */ +-static void vfio_bar_write(void *opaque, hwaddr addr, +- uint64_t data, unsigned size) ++static void vfio_region_write(void *opaque, hwaddr addr, ++ uint64_t data, unsigned size) + { +- VFIOBAR *bar = opaque; ++ VFIORegion *region = opaque; ++ VFIODevice *vbasedev = region->vbasedev; + union { + uint8_t byte; + uint16_t word; +@@ -1112,21 +1120,15 @@ static void vfio_bar_write(void *opaque, hwaddr addr, + break; + } + +- if (pwrite(bar->fd, &buf, size, bar->fd_offset + addr) != size) { +- error_report("%s(,0x%"HWADDR_PRIx", 0x%"PRIx64", %d) failed: %m", +- __func__, addr, data, size); ++ if (pwrite(vbasedev->fd, &buf, size, region->fd_offset + addr) != size) { ++ error_report("%s(%s:region%d+0x%"HWADDR_PRIx", 0x%"PRIx64 ++ ",%d) failed: %m", ++ __func__, vbasedev->name, region->nr, ++ addr, data, size); + } + +-#ifdef DEBUG_VFIO +- { +- VFIOPCIDevice *vdev = container_of(bar, VFIOPCIDevice, bars[bar->nr]); +- +- DPRINTF("%s(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx", 0x%"PRIx64 +- ", %d)\n", __func__, vdev->host.domain, vdev->host.bus, +- vdev->host.slot, vdev->host.function, bar->nr, addr, +- data, size); +- } +-#endif ++ DPRINTF("%s(%s:BAR%d+0x%"HWADDR_PRIx", 0x%"PRIx64", %d)\n", __func__, ++ vbasedev->name, region->nr, addr, data, size); + + /* + * A read or write to a BAR always signals an INTx EOI. This will +@@ -1136,13 +1138,14 @@ static void vfio_bar_write(void *opaque, hwaddr addr, + * which access will service the interrupt, so we're potentially + * getting quite a few host interrupts per guest interrupt. + */ +- vfio_eoi(container_of(bar, VFIOPCIDevice, bars[bar->nr])); ++ vbasedev->ops->vfio_eoi(vbasedev); + } + +-static uint64_t vfio_bar_read(void *opaque, +- hwaddr addr, unsigned size) ++static uint64_t vfio_region_read(void *opaque, ++ hwaddr addr, unsigned size) + { +- VFIOBAR *bar = opaque; ++ VFIORegion *region = opaque; ++ VFIODevice *vbasedev = region->vbasedev; + union { + uint8_t byte; + uint16_t word; +@@ -1151,9 +1154,10 @@ static uint64_t vfio_bar_read(void *opaque, + } buf; + uint64_t data = 0; + +- if (pread(bar->fd, &buf, size, bar->fd_offset + addr) != size) { +- error_report("%s(,0x%"HWADDR_PRIx", %d) failed: %m", +- __func__, addr, size); ++ if (pread(vbasedev->fd, &buf, size, region->fd_offset + addr) != size) { ++ error_report("%s(%s:region%d+0x%"HWADDR_PRIx", %d) failed: %m", ++ __func__, vbasedev->name, region->nr, ++ addr, size); + return (uint64_t)-1; + } + +@@ -1172,26 +1176,18 @@ static uint64_t vfio_bar_read(void *opaque, + break; + } + +-#ifdef DEBUG_VFIO +- { +- VFIOPCIDevice *vdev = container_of(bar, VFIOPCIDevice, bars[bar->nr]); +- +- DPRINTF("%s(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx +- ", %d) = 0x%"PRIx64"\n", __func__, vdev->host.domain, +- vdev->host.bus, vdev->host.slot, vdev->host.function, +- bar->nr, addr, size, data); +- } +-#endif ++ DPRINTF("%s(%s:BAR%d+0x%"HWADDR_PRIx", %d) = 0x%"PRIx64"\n", __func__, ++ vbasedev->name, region->nr, addr, size, data); + + /* Same as write above */ +- vfio_eoi(container_of(bar, VFIOPCIDevice, bars[bar->nr])); ++ vbasedev->ops->vfio_eoi(vbasedev); + + return data; + } + +-static const MemoryRegionOps vfio_bar_ops = { +- .read = vfio_bar_read, +- .write = vfio_bar_write, ++static const MemoryRegionOps vfio_region_ops = { ++ .read = vfio_region_read, ++ .write = vfio_region_write, + .endianness = DEVICE_LITTLE_ENDIAN, + }; + +@@ -1505,8 +1501,8 @@ static uint64_t vfio_generic_window_quirk_read(void *opaque, + vdev->host.bus, vdev->host.slot, vdev->host.function, + quirk->data.bar, addr, size, data); + } else { +- data = vfio_bar_read(&vdev->bars[quirk->data.bar], +- addr + quirk->data.base_offset, size); ++ data = vfio_region_read(&vdev->bars[quirk->data.bar].region, ++ addr + quirk->data.base_offset, size); + } + + return data; +@@ -1556,7 +1552,7 @@ static void vfio_generic_window_quirk_write(void *opaque, hwaddr addr, + return; + } + +- vfio_bar_write(&vdev->bars[quirk->data.bar], ++ vfio_region_write(&vdev->bars[quirk->data.bar].region, + addr + quirk->data.base_offset, data, size); + } + +@@ -1590,7 +1586,8 @@ static uint64_t vfio_generic_quirk_read(void *opaque, + vdev->host.bus, vdev->host.slot, vdev->host.function, + quirk->data.bar, addr + base, size, data); + } else { +- data = vfio_bar_read(&vdev->bars[quirk->data.bar], addr + base, size); ++ data = vfio_region_read(&vdev->bars[quirk->data.bar].region, ++ addr + base, size); + } + + return data; +@@ -1619,7 +1616,8 @@ static void vfio_generic_quirk_write(void *opaque, hwaddr addr, + vdev->host.domain, vdev->host.bus, vdev->host.slot, + vdev->host.function, quirk->data.bar, addr + base, data, size); + } else { +- vfio_bar_write(&vdev->bars[quirk->data.bar], addr + base, data, size); ++ vfio_region_write(&vdev->bars[quirk->data.bar].region, ++ addr + base, data, size); + } + } + +@@ -1672,7 +1670,7 @@ static void vfio_vga_probe_ati_3c3_quirk(VFIOPCIDevice *vdev) + * As long as the BAR is >= 256 bytes it will be aligned such that the + * lower byte is always zero. Filter out anything else, if it exists. + */ +- if (!vdev->bars[4].ioport || vdev->bars[4].size < 256) { ++ if (!vdev->bars[4].ioport || vdev->bars[4].region.size < 256) { + return; + } + +@@ -1725,7 +1723,7 @@ static void vfio_probe_ati_bar4_window_quirk(VFIOPCIDevice *vdev, int nr) + memory_region_init_io(&quirk->mem, + &vfio_generic_window_quirk, quirk, + "vfio-ati-bar4-window-quirk", 8); +- memory_region_add_subregion_overlap(&vdev->bars[nr].mem, ++ memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, + quirk->data.base_offset, &quirk->mem, 1); + + QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); +@@ -1759,7 +1757,7 @@ static void vfio_probe_ati_bar2_4000_quirk(VFIOPCIDevice *vdev, int nr) + memory_region_init_io(&quirk->mem, &vfio_generic_quirk, quirk, + "vfio-ati-bar2-4000-quirk", + TARGET_PAGE_ALIGN(quirk->data.address_mask + 1)); +- memory_region_add_subregion_overlap(&vdev->bars[nr].mem, ++ memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, + quirk->data.address_match & TARGET_PAGE_MASK, + &quirk->mem, 1); + +@@ -1878,7 +1876,7 @@ static void vfio_vga_probe_nvidia_3d0_quirk(VFIOPCIDevice *vdev) + VFIOQuirk *quirk; + + if (pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA || +- !vdev->bars[1].size) { ++ !vdev->bars[1].region.size) { + return; + } + +@@ -1986,7 +1984,8 @@ static void vfio_probe_nvidia_bar5_window_quirk(VFIOPCIDevice *vdev, int nr) + memory_region_init_io(&quirk->mem, + &vfio_nvidia_bar5_window_quirk, quirk, + "vfio-nvidia-bar5-window-quirk", 16); +- memory_region_add_subregion_overlap(&vdev->bars[nr].mem, 0, &quirk->mem, 1); ++ memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, ++ 0, &quirk->mem, 1); + + QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); + +@@ -2024,7 +2023,7 @@ static void vfio_probe_nvidia_bar0_88000_quirk(VFIOPCIDevice *vdev, int nr) + memory_region_init_io(&quirk->mem, &vfio_generic_quirk, + quirk, "vfio-nvidia-bar0-88000-quirk", + TARGET_PAGE_ALIGN(quirk->data.address_mask + 1)); +- memory_region_add_subregion_overlap(&vdev->bars[nr].mem, ++ memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, + quirk->data.address_match & TARGET_PAGE_MASK, + &quirk->mem, 1); + +@@ -2050,7 +2049,8 @@ static void vfio_probe_nvidia_bar0_1800_quirk(VFIOPCIDevice *vdev, int nr) + + /* Log the chipset ID */ + DPRINTF("Nvidia NV%02x\n", +- (unsigned int)(vfio_bar_read(&vdev->bars[0], 0, 4) >> 20) & 0xff); ++ (unsigned int)(vfio_region_read(&vdev->bars[0].region, 0, 4) >> 20) ++ & 0xff); + + quirk = g_malloc0(sizeof(*quirk)); + quirk->vdev = vdev; +@@ -2062,7 +2062,7 @@ static void vfio_probe_nvidia_bar0_1800_quirk(VFIOPCIDevice *vdev, int nr) + memory_region_init_io(&quirk->mem, &vfio_generic_quirk, quirk, + "vfio-nvidia-bar0-1800-quirk", + TARGET_PAGE_ALIGN(quirk->data.address_mask + 1)); +- memory_region_add_subregion_overlap(&vdev->bars[nr].mem, ++ memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, + quirk->data.address_match & TARGET_PAGE_MASK, + &quirk->mem, 1); + +@@ -2118,7 +2118,7 @@ static void vfio_bar_quirk_teardown(VFIOPCIDevice *vdev, int nr) + + while (!QLIST_EMPTY(&bar->quirks)) { + VFIOQuirk *quirk = QLIST_FIRST(&bar->quirks); +- memory_region_del_subregion(&bar->mem, &quirk->mem); ++ memory_region_del_subregion(&bar->region.mem, &quirk->mem); + memory_region_destroy(&quirk->mem); + QLIST_REMOVE(quirk, next); + g_free(quirk); +@@ -2495,7 +2495,7 @@ static int vfio_early_setup_msix(VFIOPCIDevice *vdev) + * specific quirk if the device is known or we have a broken configuration. + */ + if (vdev->msix->pba_offset >= +- vdev->bars[vdev->msix->pba_bar].size) { ++ vdev->bars[vdev->msix->pba_bar].region.size) { + + PCIDevice *pdev = &vdev->pdev; + uint16_t vendor = pci_get_word(pdev->config + PCI_VENDOR_ID); +@@ -2524,9 +2524,9 @@ static int vfio_setup_msix(VFIOPCIDevice *vdev, int pos) + int ret; + + ret = msix_init(&vdev->pdev, vdev->msix->entries, +- &vdev->bars[vdev->msix->table_bar].mem, ++ &vdev->bars[vdev->msix->table_bar].region.mem, + vdev->msix->table_bar, vdev->msix->table_offset, +- &vdev->bars[vdev->msix->pba_bar].mem, ++ &vdev->bars[vdev->msix->pba_bar].region.mem, + vdev->msix->pba_bar, vdev->msix->pba_offset, pos); + if (ret < 0) { + if (ret == -ENOTSUP) { +@@ -2544,8 +2544,9 @@ static void vfio_teardown_msi(VFIOPCIDevice *vdev) + msi_uninit(&vdev->pdev); + + if (vdev->msix) { +- msix_uninit(&vdev->pdev, &vdev->bars[vdev->msix->table_bar].mem, +- &vdev->bars[vdev->msix->pba_bar].mem); ++ msix_uninit(&vdev->pdev, ++ &vdev->bars[vdev->msix->table_bar].region.mem, ++ &vdev->bars[vdev->msix->pba_bar].region.mem); + } + } + +@@ -2559,11 +2560,11 @@ static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled) + for (i = 0; i < PCI_ROM_SLOT; i++) { + VFIOBAR *bar = &vdev->bars[i]; + +- if (!bar->size) { ++ if (!bar->region.size) { + continue; + } + +- memory_region_set_enabled(&bar->mmap_mem, enabled); ++ memory_region_set_enabled(&bar->region.mmap_mem, enabled); + if (vdev->msix && vdev->msix->table_bar == i) { + memory_region_set_enabled(&vdev->msix->mmap_mem, enabled); + } +@@ -2574,45 +2575,47 @@ static void vfio_unmap_bar(VFIOPCIDevice *vdev, int nr) + { + VFIOBAR *bar = &vdev->bars[nr]; + +- if (!bar->size) { ++ if (!bar->region.size) { + return; + } + + vfio_bar_quirk_teardown(vdev, nr); + +- memory_region_del_subregion(&bar->mem, &bar->mmap_mem); +- munmap(bar->mmap, memory_region_size(&bar->mmap_mem)); +- memory_region_destroy(&bar->mmap_mem); ++ memory_region_del_subregion(&bar->region.mem, &bar->region.mmap_mem); ++ munmap(bar->region.mmap, memory_region_size(&bar->region.mmap_mem)); ++ memory_region_destroy(&bar->region.mmap_mem); + + if (vdev->msix && vdev->msix->table_bar == nr) { +- memory_region_del_subregion(&bar->mem, &vdev->msix->mmap_mem); ++ memory_region_del_subregion(&bar->region.mem, &vdev->msix->mmap_mem); + munmap(vdev->msix->mmap, memory_region_size(&vdev->msix->mmap_mem)); + memory_region_destroy(&vdev->msix->mmap_mem); + } + +- memory_region_destroy(&bar->mem); ++ memory_region_destroy(&bar->region.mem); + } + +-static int vfio_mmap_bar(VFIOPCIDevice *vdev, VFIOBAR *bar, +- MemoryRegion *mem, MemoryRegion *submem, +- void **map, size_t size, off_t offset, +- const char *name) ++static int vfio_mmap_region(Object *obj, VFIORegion *region, ++ MemoryRegion *mem, MemoryRegion *submem, ++ void **map, size_t size, off_t offset, ++ const char *name) + { + int ret = 0; ++ VFIODevice *vbasedev = region->vbasedev; + +- if (VFIO_ALLOW_MMAP && size && bar->flags & VFIO_REGION_INFO_FLAG_MMAP) { ++ if (VFIO_ALLOW_MMAP && size && region->flags & ++ VFIO_REGION_INFO_FLAG_MMAP) { + int prot = 0; + +- if (bar->flags & VFIO_REGION_INFO_FLAG_READ) { ++ if (region->flags & VFIO_REGION_INFO_FLAG_READ) { + prot |= PROT_READ; + } + +- if (bar->flags & VFIO_REGION_INFO_FLAG_WRITE) { ++ if (region->flags & VFIO_REGION_INFO_FLAG_WRITE) { + prot |= PROT_WRITE; + } + + *map = mmap(NULL, size, prot, MAP_SHARED, +- bar->fd, bar->fd_offset + offset); ++ vbasedev->fd, region->fd_offset + offset); + if (*map == MAP_FAILED) { + *map = NULL; + ret = -errno; +@@ -2635,7 +2638,7 @@ empty_region: + static void vfio_map_bar(VFIOPCIDevice *vdev, int nr) + { + VFIOBAR *bar = &vdev->bars[nr]; +- uint64_t size = bar->size; ++ uint64_t size = bar->region.size; + char name[64]; + uint32_t pci_bar; + uint8_t type; +@@ -2665,9 +2668,9 @@ static void vfio_map_bar(VFIOPCIDevice *vdev, int nr) + ~PCI_BASE_ADDRESS_MEM_MASK); + + /* A "slow" read/write mapping underlies all BARs */ +- memory_region_init_io(&bar->mem, &vfio_bar_ops, ++ memory_region_init_io(&bar->region.mem, &vfio_region_ops, + bar, name, size); +- pci_register_bar(&vdev->pdev, nr, type, &bar->mem); ++ pci_register_bar(&vdev->pdev, nr, type, &bar->region.mem); + + /* + * We can't mmap areas overlapping the MSIX vector table, so we +@@ -2678,8 +2681,9 @@ static void vfio_map_bar(VFIOPCIDevice *vdev, int nr) + } + + strncat(name, " mmap", sizeof(name) - strlen(name) - 1); +- if (vfio_mmap_bar(vdev, bar, &bar->mem, +- &bar->mmap_mem, &bar->mmap, size, 0, name)) { ++ if (vfio_mmap_region(OBJECT(vdev), &bar->region, &bar->region.mem, ++ &bar->region.mmap_mem, &bar->region.mmap, ++ size, 0, name)) { + error_report("%s unsupported. Performance may be slow", name); + } + +@@ -2689,10 +2693,11 @@ static void vfio_map_bar(VFIOPCIDevice *vdev, int nr) + start = TARGET_PAGE_ALIGN((uint64_t)vdev->msix->table_offset + + (vdev->msix->entries * PCI_MSIX_ENTRY_SIZE)); + +- size = start < bar->size ? bar->size - start : 0; ++ size = start < bar->region.size ? bar->region.size - start : 0; + strncat(name, " msix-hi", sizeof(name) - strlen(name) - 1); + /* VFIOMSIXInfo contains another MemoryRegion for this mapping */ +- if (vfio_mmap_bar(vdev, bar, &bar->mem, &vdev->msix->mmap_mem, ++ if (vfio_mmap_region(OBJECT(vdev), &bar->region, &bar->region.mem, ++ &vdev->msix->mmap_mem, + &vdev->msix->mmap, size, start, name)) { + error_report("%s unsupported. Performance may be slow", name); + } +@@ -3281,6 +3286,7 @@ static void vfio_pci_compute_needs_reset(VFIODevice *vbasedev) + static VFIODeviceOps vfio_pci_ops = { + .vfio_compute_needs_reset = vfio_pci_compute_needs_reset, + .vfio_hot_reset_multi = vfio_pci_hot_reset_multi, ++ .vfio_eoi = vfio_eoi, + }; + + static void vfio_reset_handler(void *opaque) +@@ -3607,11 +3613,11 @@ static int vfio_get_device(VFIOGroup *group, const char *name, + (unsigned long)reg_info.size, (unsigned long)reg_info.offset, + (unsigned long)reg_info.flags); + +- vdev->bars[i].flags = reg_info.flags; +- vdev->bars[i].size = reg_info.size; +- vdev->bars[i].fd_offset = reg_info.offset; +- vdev->bars[i].fd = vdev->vbasedev.fd; +- vdev->bars[i].nr = i; ++ vdev->bars[i].region.vbasedev = &vdev->vbasedev; ++ vdev->bars[i].region.flags = reg_info.flags; ++ vdev->bars[i].region.size = reg_info.size; ++ vdev->bars[i].region.fd_offset = reg_info.offset; ++ vdev->bars[i].region.nr = i; + QLIST_INIT(&vdev->bars[i].quirks); + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-hw-vfio-pci-Rename-VFIODevice-into-VFIOPCIDevice.patch b/SOURCES/kvm-hw-vfio-pci-Rename-VFIODevice-into-VFIOPCIDevice.patch new file mode 100644 index 0000000..7bfc3d9 --- /dev/null +++ b/SOURCES/kvm-hw-vfio-pci-Rename-VFIODevice-into-VFIOPCIDevice.patch @@ -0,0 +1,917 @@ +From c0cad7dde740ad701c4a095c607970e1f76ad720 Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Fri, 29 Sep 2017 21:44:12 +0200 +Subject: [PATCH 02/27] hw/vfio/pci: Rename VFIODevice into VFIOPCIDevice + +RH-Author: Alex Williamson +Message-id: <20170929214412.16765.59126.stgit@gimli.home> +Patchwork-id: 76760 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 02/16] hw/vfio/pci: Rename VFIODevice into VFIOPCIDevice +Bugzilla: 1494181 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Auger Eric +RH-Acked-by: Miroslav Rezanina + +From: Eric Auger + +Upstream: 9ee27d7381c2d540ee976c7cbae941c66bb66e70 +RHEL: Request notifier didn't exist upstream yet, included in change. + +This prepares for the introduction of VFIOPlatformDevice + +Signed-off-by: Eric Auger +Signed-off-by: Alex Williamson +Signed-off-by: Miroslav Rezanina +--- + hw/misc/vfio.c | 209 +++++++++++++++++++++++++++++---------------------------- + 1 file changed, 105 insertions(+), 104 deletions(-) + +diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c +index 363c646..a1ca883 100644 +--- a/hw/misc/vfio.c ++++ b/hw/misc/vfio.c +@@ -55,11 +55,11 @@ + #define VFIO_ALLOW_KVM_MSI 1 + #define VFIO_ALLOW_KVM_MSIX 1 + +-struct VFIODevice; ++struct VFIOPCIDevice; + + typedef struct VFIOQuirk { + MemoryRegion mem; +- struct VFIODevice *vdev; ++ struct VFIOPCIDevice *vdev; + QLIST_ENTRY(VFIOQuirk) next; + struct { + uint32_t base_offset:TARGET_PAGE_BITS; +@@ -130,7 +130,7 @@ typedef struct VFIOMSIVector { + */ + EventNotifier interrupt; + EventNotifier kvm_interrupt; +- struct VFIODevice *vdev; /* back pointer to device */ ++ struct VFIOPCIDevice *vdev; /* back pointer to device */ + int virq; + bool use; + } VFIOMSIVector; +@@ -174,7 +174,7 @@ typedef struct VFIOMSIXInfo { + void *mmap; + } VFIOMSIXInfo; + +-typedef struct VFIODevice { ++typedef struct VFIOPCIDevice { + PCIDevice pdev; + int fd; + VFIOINTx intx; +@@ -192,7 +192,7 @@ typedef struct VFIODevice { + VFIOBAR bars[PCI_NUM_REGIONS - 1]; /* No ROM */ + VFIOVGA vga; /* 0xa0000, 0x3b0, 0x3c0 */ + PCIHostDeviceAddress host; +- QLIST_ENTRY(VFIODevice) next; ++ QLIST_ENTRY(VFIOPCIDevice) next; + struct VFIOGroup *group; + EventNotifier err_notifier; + EventNotifier req_notifier; +@@ -211,13 +211,13 @@ typedef struct VFIODevice { + bool has_pm_reset; + bool needs_reset; + bool rom_read_failed; +-} VFIODevice; ++} VFIOPCIDevice; + + typedef struct VFIOGroup { + int fd; + int groupid; + VFIOContainer *container; +- QLIST_HEAD(, VFIODevice) device_list; ++ QLIST_HEAD(, VFIOPCIDevice) device_list; + QLIST_ENTRY(VFIOGroup) next; + QLIST_ENTRY(VFIOGroup) container_next; + } VFIOGroup; +@@ -263,16 +263,16 @@ static QLIST_HEAD(, VFIOGroup) + */ + static int vfio_kvm_device_fd = -1; + +-static void vfio_disable_interrupts(VFIODevice *vdev); ++static void vfio_disable_interrupts(VFIOPCIDevice *vdev); + static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len); + static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr, + uint32_t val, int len); +-static void vfio_mmap_set_enabled(VFIODevice *vdev, bool enabled); ++static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled); + + /* + * Common VFIO interrupt disable + */ +-static void vfio_disable_irqindex(VFIODevice *vdev, int index) ++static void vfio_disable_irqindex(VFIOPCIDevice *vdev, int index) + { + struct vfio_irq_set irq_set = { + .argsz = sizeof(irq_set), +@@ -288,7 +288,7 @@ static void vfio_disable_irqindex(VFIODevice *vdev, int index) + /* + * INTx + */ +-static void vfio_unmask_intx(VFIODevice *vdev) ++static void vfio_unmask_intx(VFIOPCIDevice *vdev) + { + struct vfio_irq_set irq_set = { + .argsz = sizeof(irq_set), +@@ -302,7 +302,7 @@ static void vfio_unmask_intx(VFIODevice *vdev) + } + + #ifdef CONFIG_KVM /* Unused outside of CONFIG_KVM code */ +-static void vfio_mask_intx(VFIODevice *vdev) ++static void vfio_mask_intx(VFIOPCIDevice *vdev) + { + struct vfio_irq_set irq_set = { + .argsz = sizeof(irq_set), +@@ -333,7 +333,7 @@ static void vfio_mask_intx(VFIODevice *vdev) + */ + static void vfio_intx_mmap_enable(void *opaque) + { +- VFIODevice *vdev = opaque; ++ VFIOPCIDevice *vdev = opaque; + + if (vdev->intx.pending) { + qemu_mod_timer(vdev->intx.mmap_timer, +@@ -346,7 +346,7 @@ static void vfio_intx_mmap_enable(void *opaque) + + static void vfio_intx_interrupt(void *opaque) + { +- VFIODevice *vdev = opaque; ++ VFIOPCIDevice *vdev = opaque; + + if (!event_notifier_test_and_clear(&vdev->intx.interrupt)) { + return; +@@ -365,7 +365,7 @@ static void vfio_intx_interrupt(void *opaque) + } + } + +-static void vfio_eoi(VFIODevice *vdev) ++static void vfio_eoi(VFIOPCIDevice *vdev) + { + if (!vdev->intx.pending) { + return; +@@ -379,7 +379,7 @@ static void vfio_eoi(VFIODevice *vdev) + vfio_unmask_intx(vdev); + } + +-static void vfio_enable_intx_kvm(VFIODevice *vdev) ++static void vfio_enable_intx_kvm(VFIOPCIDevice *vdev) + { + #ifdef CONFIG_KVM + struct kvm_irqfd irqfd = { +@@ -458,7 +458,7 @@ fail: + #endif + } + +-static void vfio_disable_intx_kvm(VFIODevice *vdev) ++static void vfio_disable_intx_kvm(VFIOPCIDevice *vdev) + { + #ifdef CONFIG_KVM + struct kvm_irqfd irqfd = { +@@ -503,7 +503,7 @@ static void vfio_disable_intx_kvm(VFIODevice *vdev) + + static void vfio_update_irq(PCIDevice *pdev) + { +- VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev); ++ VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); + PCIINTxRoute route; + + if (vdev->interrupt != VFIO_INT_INTx) { +@@ -534,7 +534,7 @@ static void vfio_update_irq(PCIDevice *pdev) + vfio_eoi(vdev); + } + +-static int vfio_enable_intx(VFIODevice *vdev) ++static int vfio_enable_intx(VFIOPCIDevice *vdev) + { + uint8_t pin = vfio_pci_read_config(&vdev->pdev, PCI_INTERRUPT_PIN, 1); + int ret, argsz; +@@ -599,7 +599,7 @@ static int vfio_enable_intx(VFIODevice *vdev) + return 0; + } + +-static void vfio_disable_intx(VFIODevice *vdev) ++static void vfio_disable_intx(VFIOPCIDevice *vdev) + { + int fd; + +@@ -626,7 +626,7 @@ static void vfio_disable_intx(VFIODevice *vdev) + static void vfio_msi_interrupt(void *opaque) + { + VFIOMSIVector *vector = opaque; +- VFIODevice *vdev = vector->vdev; ++ VFIOPCIDevice *vdev = vector->vdev; + int nr = vector - vdev->msi_vectors; + + if (!event_notifier_test_and_clear(&vector->interrupt)) { +@@ -658,7 +658,7 @@ static void vfio_msi_interrupt(void *opaque) + } + } + +-static int vfio_enable_vectors(VFIODevice *vdev, bool msix) ++static int vfio_enable_vectors(VFIOPCIDevice *vdev, bool msix) + { + struct vfio_irq_set *irq_set; + int ret = 0, i, argsz; +@@ -749,7 +749,7 @@ static void vfio_update_kvm_msi_virq(VFIOMSIVector *vector, MSIMessage msg) + static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, + MSIMessage *msg, IOHandler *handler) + { +- VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev); ++ VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); + VFIOMSIVector *vector; + int ret; + +@@ -838,7 +838,7 @@ static int vfio_msix_vector_use(PCIDevice *pdev, + + static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr) + { +- VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev); ++ VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); + VFIOMSIVector *vector = &vdev->msi_vectors[nr]; + + DPRINTF("%s(%04x:%02x:%02x.%x) vector %d released\n", __func__, +@@ -877,7 +877,7 @@ static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr) + } + } + +-static void vfio_enable_msix(VFIODevice *vdev) ++static void vfio_enable_msix(VFIOPCIDevice *vdev) + { + vfio_disable_interrupts(vdev); + +@@ -910,7 +910,7 @@ static void vfio_enable_msix(VFIODevice *vdev) + vdev->host.bus, vdev->host.slot, vdev->host.function); + } + +-static void vfio_enable_msi(VFIODevice *vdev) ++static void vfio_enable_msi(VFIOPCIDevice *vdev) + { + int ret, i; + +@@ -988,7 +988,7 @@ retry: + vdev->host.function, vdev->nr_vectors); + } + +-static void vfio_disable_msi_common(VFIODevice *vdev) ++static void vfio_disable_msi_common(VFIOPCIDevice *vdev) + { + int i; + +@@ -1012,7 +1012,7 @@ static void vfio_disable_msi_common(VFIODevice *vdev) + vfio_enable_intx(vdev); + } + +-static void vfio_disable_msix(VFIODevice *vdev) ++static void vfio_disable_msix(VFIOPCIDevice *vdev) + { + int i; + +@@ -1039,7 +1039,7 @@ static void vfio_disable_msix(VFIODevice *vdev) + vdev->host.bus, vdev->host.slot, vdev->host.function); + } + +-static void vfio_disable_msi(VFIODevice *vdev) ++static void vfio_disable_msi(VFIOPCIDevice *vdev) + { + vfio_disable_irqindex(vdev, VFIO_PCI_MSI_IRQ_INDEX); + vfio_disable_msi_common(vdev); +@@ -1048,7 +1048,7 @@ static void vfio_disable_msi(VFIODevice *vdev) + vdev->host.bus, vdev->host.slot, vdev->host.function); + } + +-static void vfio_update_msi(VFIODevice *vdev) ++static void vfio_update_msi(VFIOPCIDevice *vdev) + { + int i; + +@@ -1101,7 +1101,7 @@ static void vfio_bar_write(void *opaque, hwaddr addr, + + #ifdef DEBUG_VFIO + { +- VFIODevice *vdev = container_of(bar, VFIODevice, bars[bar->nr]); ++ VFIOPCIDevice *vdev = container_of(bar, VFIOPCIDevice, bars[bar->nr]); + + DPRINTF("%s(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx", 0x%"PRIx64 + ", %d)\n", __func__, vdev->host.domain, vdev->host.bus, +@@ -1118,7 +1118,7 @@ static void vfio_bar_write(void *opaque, hwaddr addr, + * which access will service the interrupt, so we're potentially + * getting quite a few host interrupts per guest interrupt. + */ +- vfio_eoi(container_of(bar, VFIODevice, bars[bar->nr])); ++ vfio_eoi(container_of(bar, VFIOPCIDevice, bars[bar->nr])); + } + + static uint64_t vfio_bar_read(void *opaque, +@@ -1156,7 +1156,7 @@ static uint64_t vfio_bar_read(void *opaque, + + #ifdef DEBUG_VFIO + { +- VFIODevice *vdev = container_of(bar, VFIODevice, bars[bar->nr]); ++ VFIOPCIDevice *vdev = container_of(bar, VFIOPCIDevice, bars[bar->nr]); + + DPRINTF("%s(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx + ", %d) = 0x%"PRIx64"\n", __func__, vdev->host.domain, +@@ -1166,7 +1166,7 @@ static uint64_t vfio_bar_read(void *opaque, + #endif + + /* Same as write above */ +- vfio_eoi(container_of(bar, VFIODevice, bars[bar->nr])); ++ vfio_eoi(container_of(bar, VFIOPCIDevice, bars[bar->nr])); + + return data; + } +@@ -1177,7 +1177,7 @@ static const MemoryRegionOps vfio_bar_ops = { + .endianness = DEVICE_LITTLE_ENDIAN, + }; + +-static void vfio_pci_load_rom(VFIODevice *vdev) ++static void vfio_pci_load_rom(VFIOPCIDevice *vdev) + { + struct vfio_region_info reg_info = { + .argsz = sizeof(reg_info), +@@ -1235,7 +1235,7 @@ static void vfio_pci_load_rom(VFIODevice *vdev) + + static uint64_t vfio_rom_read(void *opaque, hwaddr addr, unsigned size) + { +- VFIODevice *vdev = opaque; ++ VFIOPCIDevice *vdev = opaque; + uint64_t val = ((uint64_t)1 << (size * 8)) - 1; + + /* Load the ROM lazily when the guest tries to read it */ +@@ -1264,7 +1264,7 @@ static const MemoryRegionOps vfio_rom_ops = { + .endianness = DEVICE_LITTLE_ENDIAN, + }; + +-static bool vfio_blacklist_opt_rom(VFIODevice *vdev) ++static bool vfio_blacklist_opt_rom(VFIOPCIDevice *vdev) + { + PCIDevice *pdev = &vdev->pdev; + uint16_t vendor_id, device_id; +@@ -1284,7 +1284,7 @@ static bool vfio_blacklist_opt_rom(VFIODevice *vdev) + return false; + } + +-static void vfio_pci_size_rom(VFIODevice *vdev) ++static void vfio_pci_size_rom(VFIOPCIDevice *vdev) + { + uint32_t orig, size = cpu_to_le32((uint32_t)PCI_ROM_ADDRESS_MASK); + off_t offset = vdev->config_offset + PCI_ROM_ADDRESS; +@@ -1463,7 +1463,7 @@ static uint64_t vfio_generic_window_quirk_read(void *opaque, + hwaddr addr, unsigned size) + { + VFIOQuirk *quirk = opaque; +- VFIODevice *vdev = quirk->vdev; ++ VFIOPCIDevice *vdev = quirk->vdev; + uint64_t data; + + if (vfio_flags_enabled(quirk->data.flags, quirk->data.read_flags) && +@@ -1496,7 +1496,7 @@ static void vfio_generic_window_quirk_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) + { + VFIOQuirk *quirk = opaque; +- VFIODevice *vdev = quirk->vdev; ++ VFIOPCIDevice *vdev = quirk->vdev; + + if (ranges_overlap(addr, size, + quirk->data.address_offset, quirk->data.address_size)) { +@@ -1550,7 +1550,7 @@ static uint64_t vfio_generic_quirk_read(void *opaque, + hwaddr addr, unsigned size) + { + VFIOQuirk *quirk = opaque; +- VFIODevice *vdev = quirk->vdev; ++ VFIOPCIDevice *vdev = quirk->vdev; + hwaddr base = quirk->data.address_match & TARGET_PAGE_MASK; + hwaddr offset = quirk->data.address_match & ~TARGET_PAGE_MASK; + uint64_t data; +@@ -1580,7 +1580,7 @@ static void vfio_generic_quirk_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) + { + VFIOQuirk *quirk = opaque; +- VFIODevice *vdev = quirk->vdev; ++ VFIOPCIDevice *vdev = quirk->vdev; + hwaddr base = quirk->data.address_match & TARGET_PAGE_MASK; + hwaddr offset = quirk->data.address_match & ~TARGET_PAGE_MASK; + +@@ -1625,7 +1625,7 @@ static uint64_t vfio_ati_3c3_quirk_read(void *opaque, + hwaddr addr, unsigned size) + { + VFIOQuirk *quirk = opaque; +- VFIODevice *vdev = quirk->vdev; ++ VFIOPCIDevice *vdev = quirk->vdev; + uint64_t data = vfio_pci_read_config(&vdev->pdev, + PCI_BASE_ADDRESS_0 + (4 * 4) + 1, + size); +@@ -1639,7 +1639,7 @@ static const MemoryRegionOps vfio_ati_3c3_quirk = { + .endianness = DEVICE_LITTLE_ENDIAN, + }; + +-static void vfio_vga_probe_ati_3c3_quirk(VFIODevice *vdev) ++static void vfio_vga_probe_ati_3c3_quirk(VFIOPCIDevice *vdev) + { + PCIDevice *pdev = &vdev->pdev; + VFIOQuirk *quirk; +@@ -1682,7 +1682,7 @@ static void vfio_vga_probe_ati_3c3_quirk(VFIODevice *vdev) + * that only read-only access is provided, but we drop writes when the window + * is enabled to config space nonetheless. + */ +-static void vfio_probe_ati_bar4_window_quirk(VFIODevice *vdev, int nr) ++static void vfio_probe_ati_bar4_window_quirk(VFIOPCIDevice *vdev, int nr) + { + PCIDevice *pdev = &vdev->pdev; + VFIOQuirk *quirk; +@@ -1718,7 +1718,7 @@ static void vfio_probe_ati_bar4_window_quirk(VFIODevice *vdev, int nr) + /* + * Trap the BAR2 MMIO window to config space as well. + */ +-static void vfio_probe_ati_bar2_4000_quirk(VFIODevice *vdev, int nr) ++static void vfio_probe_ati_bar2_4000_quirk(VFIOPCIDevice *vdev, int nr) + { + PCIDevice *pdev = &vdev->pdev; + VFIOQuirk *quirk; +@@ -1786,7 +1786,7 @@ static uint64_t vfio_nvidia_3d0_quirk_read(void *opaque, + hwaddr addr, unsigned size) + { + VFIOQuirk *quirk = opaque; +- VFIODevice *vdev = quirk->vdev; ++ VFIOPCIDevice *vdev = quirk->vdev; + PCIDevice *pdev = &vdev->pdev; + uint64_t data = vfio_vga_read(&vdev->vga.region[QEMU_PCI_VGA_IO_HI], + addr + quirk->data.base_offset, size); +@@ -1805,7 +1805,7 @@ static void vfio_nvidia_3d0_quirk_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) + { + VFIOQuirk *quirk = opaque; +- VFIODevice *vdev = quirk->vdev; ++ VFIOPCIDevice *vdev = quirk->vdev; + PCIDevice *pdev = &vdev->pdev; + + switch (quirk->data.flags) { +@@ -1852,7 +1852,7 @@ static const MemoryRegionOps vfio_nvidia_3d0_quirk = { + .endianness = DEVICE_LITTLE_ENDIAN, + }; + +-static void vfio_vga_probe_nvidia_3d0_quirk(VFIODevice *vdev) ++static void vfio_vga_probe_nvidia_3d0_quirk(VFIOPCIDevice *vdev) + { + PCIDevice *pdev = &vdev->pdev; + VFIOQuirk *quirk; +@@ -1944,7 +1944,7 @@ static const MemoryRegionOps vfio_nvidia_bar5_window_quirk = { + .endianness = DEVICE_LITTLE_ENDIAN, + }; + +-static void vfio_probe_nvidia_bar5_window_quirk(VFIODevice *vdev, int nr) ++static void vfio_probe_nvidia_bar5_window_quirk(VFIOPCIDevice *vdev, int nr) + { + PCIDevice *pdev = &vdev->pdev; + VFIOQuirk *quirk; +@@ -1984,7 +1984,7 @@ static void vfio_probe_nvidia_bar5_window_quirk(VFIODevice *vdev, int nr) + * + * Here's offset 0x88000... + */ +-static void vfio_probe_nvidia_bar0_88000_quirk(VFIODevice *vdev, int nr) ++static void vfio_probe_nvidia_bar0_88000_quirk(VFIOPCIDevice *vdev, int nr) + { + PCIDevice *pdev = &vdev->pdev; + VFIOQuirk *quirk; +@@ -2018,7 +2018,7 @@ static void vfio_probe_nvidia_bar0_88000_quirk(VFIODevice *vdev, int nr) + /* + * And here's the same for BAR0 offset 0x1800... + */ +-static void vfio_probe_nvidia_bar0_1800_quirk(VFIODevice *vdev, int nr) ++static void vfio_probe_nvidia_bar0_1800_quirk(VFIOPCIDevice *vdev, int nr) + { + PCIDevice *pdev = &vdev->pdev; + VFIOQuirk *quirk; +@@ -2062,13 +2062,13 @@ static void vfio_probe_nvidia_bar0_1800_quirk(VFIODevice *vdev, int nr) + /* + * Common quirk probe entry points. + */ +-static void vfio_vga_quirk_setup(VFIODevice *vdev) ++static void vfio_vga_quirk_setup(VFIOPCIDevice *vdev) + { + vfio_vga_probe_ati_3c3_quirk(vdev); + vfio_vga_probe_nvidia_3d0_quirk(vdev); + } + +-static void vfio_vga_quirk_teardown(VFIODevice *vdev) ++static void vfio_vga_quirk_teardown(VFIOPCIDevice *vdev) + { + int i; + +@@ -2083,7 +2083,7 @@ static void vfio_vga_quirk_teardown(VFIODevice *vdev) + } + } + +-static void vfio_bar_quirk_setup(VFIODevice *vdev, int nr) ++static void vfio_bar_quirk_setup(VFIOPCIDevice *vdev, int nr) + { + vfio_probe_ati_bar4_window_quirk(vdev, nr); + vfio_probe_ati_bar2_4000_quirk(vdev, nr); +@@ -2092,7 +2092,7 @@ static void vfio_bar_quirk_setup(VFIODevice *vdev, int nr) + vfio_probe_nvidia_bar0_1800_quirk(vdev, nr); + } + +-static void vfio_bar_quirk_teardown(VFIODevice *vdev, int nr) ++static void vfio_bar_quirk_teardown(VFIOPCIDevice *vdev, int nr) + { + VFIOBAR *bar = &vdev->bars[nr]; + +@@ -2110,7 +2110,7 @@ static void vfio_bar_quirk_teardown(VFIODevice *vdev, int nr) + */ + static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len) + { +- VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev); ++ VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); + uint32_t emu_bits = 0, emu_val = 0, phys_val = 0, val; + + memcpy(&emu_bits, vdev->emulated_config_bits + addr, len); +@@ -2145,7 +2145,7 @@ static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len) + static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr, + uint32_t val, int len) + { +- VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev); ++ VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); + uint32_t val_le = cpu_to_le32(val); + + DPRINTF("%s(%04x:%02x:%02x.%x, @0x%x, 0x%x, len=0x%x)\n", __func__, +@@ -2365,7 +2365,7 @@ static void vfio_listener_release(VFIOContainer *container) + /* + * Interrupt setup + */ +-static void vfio_disable_interrupts(VFIODevice *vdev) ++static void vfio_disable_interrupts(VFIOPCIDevice *vdev) + { + /* + * More complicated than it looks. Disabling MSI/X transitions the +@@ -2383,7 +2383,7 @@ static void vfio_disable_interrupts(VFIODevice *vdev) + } + } + +-static int vfio_setup_msi(VFIODevice *vdev, int pos) ++static int vfio_setup_msi(VFIOPCIDevice *vdev, int pos) + { + uint16_t ctrl; + bool msi_64bit, msi_maskbit; +@@ -2423,7 +2423,7 @@ static int vfio_setup_msi(VFIODevice *vdev, int pos) + * need to first look for where the MSI-X table lives. So we + * unfortunately split MSI-X setup across two functions. + */ +-static int vfio_early_setup_msix(VFIODevice *vdev) ++static int vfio_early_setup_msix(VFIOPCIDevice *vdev) + { + uint8_t pos; + uint16_t ctrl; +@@ -2496,7 +2496,7 @@ static int vfio_early_setup_msix(VFIODevice *vdev) + return 0; + } + +-static int vfio_setup_msix(VFIODevice *vdev, int pos) ++static int vfio_setup_msix(VFIOPCIDevice *vdev, int pos) + { + int ret; + +@@ -2516,7 +2516,7 @@ static int vfio_setup_msix(VFIODevice *vdev, int pos) + return 0; + } + +-static void vfio_teardown_msi(VFIODevice *vdev) ++static void vfio_teardown_msi(VFIOPCIDevice *vdev) + { + msi_uninit(&vdev->pdev); + +@@ -2529,7 +2529,7 @@ static void vfio_teardown_msi(VFIODevice *vdev) + /* + * Resource setup + */ +-static void vfio_mmap_set_enabled(VFIODevice *vdev, bool enabled) ++static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled) + { + int i; + +@@ -2547,7 +2547,7 @@ static void vfio_mmap_set_enabled(VFIODevice *vdev, bool enabled) + } + } + +-static void vfio_unmap_bar(VFIODevice *vdev, int nr) ++static void vfio_unmap_bar(VFIOPCIDevice *vdev, int nr) + { + VFIOBAR *bar = &vdev->bars[nr]; + +@@ -2570,7 +2570,7 @@ static void vfio_unmap_bar(VFIODevice *vdev, int nr) + memory_region_destroy(&bar->mem); + } + +-static int vfio_mmap_bar(VFIODevice *vdev, VFIOBAR *bar, ++static int vfio_mmap_bar(VFIOPCIDevice *vdev, VFIOBAR *bar, + MemoryRegion *mem, MemoryRegion *submem, + void **map, size_t size, off_t offset, + const char *name) +@@ -2609,7 +2609,7 @@ empty_region: + return ret; + } + +-static void vfio_map_bar(VFIODevice *vdev, int nr) ++static void vfio_map_bar(VFIOPCIDevice *vdev, int nr) + { + VFIOBAR *bar = &vdev->bars[nr]; + uint64_t size = bar->size; +@@ -2678,7 +2678,7 @@ static void vfio_map_bar(VFIODevice *vdev, int nr) + vfio_bar_quirk_setup(vdev, nr); + } + +-static void vfio_map_bars(VFIODevice *vdev) ++static void vfio_map_bars(VFIOPCIDevice *vdev) + { + int i; + +@@ -2710,7 +2710,7 @@ static void vfio_map_bars(VFIODevice *vdev) + } + } + +-static void vfio_unmap_bars(VFIODevice *vdev) ++static void vfio_unmap_bars(VFIOPCIDevice *vdev) + { + int i; + +@@ -2749,7 +2749,7 @@ static void vfio_set_word_bits(uint8_t *buf, uint16_t val, uint16_t mask) + pci_set_word(buf, (pci_get_word(buf) & ~mask) | val); + } + +-static void vfio_add_emulated_word(VFIODevice *vdev, int pos, ++static void vfio_add_emulated_word(VFIOPCIDevice *vdev, int pos, + uint16_t val, uint16_t mask) + { + vfio_set_word_bits(vdev->pdev.config + pos, val, mask); +@@ -2762,7 +2762,7 @@ static void vfio_set_long_bits(uint8_t *buf, uint32_t val, uint32_t mask) + pci_set_long(buf, (pci_get_long(buf) & ~mask) | val); + } + +-static void vfio_add_emulated_long(VFIODevice *vdev, int pos, ++static void vfio_add_emulated_long(VFIOPCIDevice *vdev, int pos, + uint32_t val, uint32_t mask) + { + vfio_set_long_bits(vdev->pdev.config + pos, val, mask); +@@ -2770,7 +2770,7 @@ static void vfio_add_emulated_long(VFIODevice *vdev, int pos, + vfio_set_long_bits(vdev->emulated_config_bits + pos, mask, mask); + } + +-static int vfio_setup_pcie_cap(VFIODevice *vdev, int pos, uint8_t size) ++static int vfio_setup_pcie_cap(VFIOPCIDevice *vdev, int pos, uint8_t size) + { + uint16_t flags; + uint8_t type; +@@ -2862,7 +2862,7 @@ static int vfio_setup_pcie_cap(VFIODevice *vdev, int pos, uint8_t size) + return pos; + } + +-static void vfio_check_pcie_flr(VFIODevice *vdev, uint8_t pos) ++static void vfio_check_pcie_flr(VFIOPCIDevice *vdev, uint8_t pos) + { + uint32_t cap = pci_get_long(vdev->pdev.config + pos + PCI_EXP_DEVCAP); + +@@ -2874,7 +2874,7 @@ static void vfio_check_pcie_flr(VFIODevice *vdev, uint8_t pos) + } + } + +-static void vfio_check_pm_reset(VFIODevice *vdev, uint8_t pos) ++static void vfio_check_pm_reset(VFIOPCIDevice *vdev, uint8_t pos) + { + uint16_t csr = pci_get_word(vdev->pdev.config + pos + PCI_PM_CTRL); + +@@ -2886,7 +2886,7 @@ static void vfio_check_pm_reset(VFIODevice *vdev, uint8_t pos) + } + } + +-static void vfio_check_af_flr(VFIODevice *vdev, uint8_t pos) ++static void vfio_check_af_flr(VFIOPCIDevice *vdev, uint8_t pos) + { + uint8_t cap = pci_get_byte(vdev->pdev.config + pos + PCI_AF_CAP); + +@@ -2898,7 +2898,7 @@ static void vfio_check_af_flr(VFIODevice *vdev, uint8_t pos) + } + } + +-static int vfio_add_std_cap(VFIODevice *vdev, uint8_t pos) ++static int vfio_add_std_cap(VFIOPCIDevice *vdev, uint8_t pos) + { + PCIDevice *pdev = &vdev->pdev; + uint8_t cap_id, next, size; +@@ -2973,7 +2973,7 @@ static int vfio_add_std_cap(VFIODevice *vdev, uint8_t pos) + return 0; + } + +-static int vfio_add_capabilities(VFIODevice *vdev) ++static int vfio_add_capabilities(VFIOPCIDevice *vdev) + { + PCIDevice *pdev = &vdev->pdev; + +@@ -2985,7 +2985,7 @@ static int vfio_add_capabilities(VFIODevice *vdev) + return vfio_add_std_cap(vdev, pdev->config[PCI_CAPABILITY_LIST]); + } + +-static void vfio_pci_pre_reset(VFIODevice *vdev) ++static void vfio_pci_pre_reset(VFIOPCIDevice *vdev) + { + PCIDevice *pdev = &vdev->pdev; + uint16_t cmd; +@@ -3022,7 +3022,7 @@ static void vfio_pci_pre_reset(VFIODevice *vdev) + vfio_pci_write_config(pdev, PCI_COMMAND, cmd, 2); + } + +-static void vfio_pci_post_reset(VFIODevice *vdev) ++static void vfio_pci_post_reset(VFIOPCIDevice *vdev) + { + vfio_enable_intx(vdev); + } +@@ -3034,7 +3034,7 @@ static bool vfio_pci_host_match(PCIHostDeviceAddress *host1, + host1->slot == host2->slot && host1->function == host2->function); + } + +-static int vfio_pci_hot_reset(VFIODevice *vdev, bool single) ++static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single) + { + VFIOGroup *group; + struct vfio_pci_hot_reset_info *info; +@@ -3084,7 +3084,7 @@ static int vfio_pci_hot_reset(VFIODevice *vdev, bool single) + /* Verify that we have all the groups required */ + for (i = 0; i < info->count; i++) { + PCIHostDeviceAddress host; +- VFIODevice *tmp; ++ VFIOPCIDevice *tmp; + + host.domain = devices[i].segment; + host.bus = devices[i].bus; +@@ -3176,7 +3176,7 @@ out: + /* Re-enable INTx on affected devices */ + for (i = 0; i < info->count; i++) { + PCIHostDeviceAddress host; +- VFIODevice *tmp; ++ VFIOPCIDevice *tmp; + + host.domain = devices[i].segment; + host.bus = devices[i].bus; +@@ -3226,12 +3226,12 @@ out_single: + * _one() will only do a hot reset for the one in-use devices case, calling + * _multi() will do nothing if a _one() would have been sufficient. + */ +-static int vfio_pci_hot_reset_one(VFIODevice *vdev) ++static int vfio_pci_hot_reset_one(VFIOPCIDevice *vdev) + { + return vfio_pci_hot_reset(vdev, true); + } + +-static int vfio_pci_hot_reset_multi(VFIODevice *vdev) ++static int vfio_pci_hot_reset_multi(VFIOPCIDevice *vdev) + { + return vfio_pci_hot_reset(vdev, false); + } +@@ -3239,7 +3239,7 @@ static int vfio_pci_hot_reset_multi(VFIODevice *vdev) + static void vfio_pci_reset_handler(void *opaque) + { + VFIOGroup *group; +- VFIODevice *vdev; ++ VFIOPCIDevice *vdev; + + QLIST_FOREACH(group, &group_list, next) { + QLIST_FOREACH(vdev, &group->device_list, next) { +@@ -3499,7 +3499,8 @@ static void vfio_put_group(VFIOGroup *group) + } + } + +-static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev) ++static int vfio_get_device(VFIOGroup *group, const char *name, ++ VFIOPCIDevice *vdev) + { + struct vfio_device_info dev_info = { .argsz = sizeof(dev_info) }; + struct vfio_region_info reg_info = { .argsz = sizeof(reg_info) }; +@@ -3654,7 +3655,7 @@ error: + return ret; + } + +-static void vfio_put_device(VFIODevice *vdev) ++static void vfio_put_device(VFIOPCIDevice *vdev) + { + QLIST_REMOVE(vdev, next); + vdev->group = NULL; +@@ -3668,7 +3669,7 @@ static void vfio_put_device(VFIODevice *vdev) + + static void vfio_err_notifier_handler(void *opaque) + { +- VFIODevice *vdev = opaque; ++ VFIOPCIDevice *vdev = opaque; + + if (!event_notifier_test_and_clear(&vdev->err_notifier)) { + return; +@@ -3697,7 +3698,7 @@ static void vfio_err_notifier_handler(void *opaque) + * and continue after disabling error recovery support for the + * device. + */ +-static void vfio_register_err_notifier(VFIODevice *vdev) ++static void vfio_register_err_notifier(VFIOPCIDevice *vdev) + { + int ret; + int argsz; +@@ -3738,7 +3739,7 @@ static void vfio_register_err_notifier(VFIODevice *vdev) + g_free(irq_set); + } + +-static void vfio_unregister_err_notifier(VFIODevice *vdev) ++static void vfio_unregister_err_notifier(VFIOPCIDevice *vdev) + { + int argsz; + struct vfio_irq_set *irq_set; +@@ -3773,7 +3774,7 @@ static void vfio_unregister_err_notifier(VFIODevice *vdev) + + static void vfio_req_notifier_handler(void *opaque) + { +- VFIODevice *vdev = opaque; ++ VFIOPCIDevice *vdev = opaque; + + if (!event_notifier_test_and_clear(&vdev->req_notifier)) { + return; +@@ -3782,7 +3783,7 @@ static void vfio_req_notifier_handler(void *opaque) + qdev_unplug(&vdev->pdev.qdev, NULL); + } + +-static void vfio_register_req_notifier(VFIODevice *vdev) ++static void vfio_register_req_notifier(VFIOPCIDevice *vdev) + { + struct vfio_irq_info irq_info = { .argsz = sizeof(irq_info), + .index = VFIO_PCI_REQ_IRQ_INDEX }; +@@ -3829,7 +3830,7 @@ static void vfio_register_req_notifier(VFIODevice *vdev) + g_free(irq_set); + } + +-static void vfio_unregister_req_notifier(VFIODevice *vdev) ++static void vfio_unregister_req_notifier(VFIOPCIDevice *vdev) + { + int argsz; + struct vfio_irq_set *irq_set; +@@ -3864,7 +3865,7 @@ static void vfio_unregister_req_notifier(VFIODevice *vdev) + + static int vfio_initfn(PCIDevice *pdev) + { +- VFIODevice *pvdev, *vdev = DO_UPCAST(VFIODevice, pdev, pdev); ++ VFIOPCIDevice *pvdev, *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); + VFIOGroup *group; + char path[PATH_MAX], iommu_group_path[PATH_MAX], *group_name; + ssize_t len; +@@ -4031,7 +4032,7 @@ out_put: + + static void vfio_exitfn(PCIDevice *pdev) + { +- VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev); ++ VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); + VFIOGroup *group = vdev->group; + + vfio_unregister_req_notifier(vdev); +@@ -4052,7 +4053,7 @@ static void vfio_exitfn(PCIDevice *pdev) + static void vfio_pci_reset(DeviceState *dev) + { + PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, dev); +- VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev); ++ VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); + + DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); +@@ -4084,18 +4085,18 @@ post_reset: + } + + static Property vfio_pci_dev_properties[] = { +- DEFINE_PROP_PCI_HOST_DEVADDR("host", VFIODevice, host), +- DEFINE_PROP_UINT32("x-intx-mmap-timeout-ms", VFIODevice, ++ DEFINE_PROP_PCI_HOST_DEVADDR("host", VFIOPCIDevice, host), ++ DEFINE_PROP_UINT32("x-intx-mmap-timeout-ms", VFIOPCIDevice, + intx.mmap_timeout, 1100), +- DEFINE_PROP_BIT("x-vga", VFIODevice, features, ++ DEFINE_PROP_BIT("x-vga", VFIOPCIDevice, features, + VFIO_FEATURE_ENABLE_VGA_BIT, false), +- DEFINE_PROP_BIT("x-req", VFIODevice, features, ++ DEFINE_PROP_BIT("x-req", VFIOPCIDevice, features, + VFIO_FEATURE_ENABLE_REQ_BIT, true), +- DEFINE_PROP_INT32("bootindex", VFIODevice, bootindex, -1), ++ DEFINE_PROP_INT32("bootindex", VFIOPCIDevice, bootindex, -1), + /* + * TODO - support passed fds... is this necessary? +- * DEFINE_PROP_STRING("vfiofd", VFIODevice, vfiofd_name), +- * DEFINE_PROP_STRING("vfiogroupfd, VFIODevice, vfiogroupfd_name), ++ * DEFINE_PROP_STRING("vfiofd", VFIOPCIDevice, vfiofd_name), ++ * DEFINE_PROP_STRING("vfiogroupfd, VFIOPCIDevice, vfiogroupfd_name), + */ + DEFINE_PROP_END_OF_LIST(), + }; +@@ -4125,7 +4126,7 @@ static void vfio_pci_dev_class_init(ObjectClass *klass, void *data) + static const TypeInfo vfio_pci_dev_info = { + .name = "vfio-pci", + .parent = TYPE_PCI_DEVICE, +- .instance_size = sizeof(VFIODevice), ++ .instance_size = sizeof(VFIOPCIDevice), + .class_init = vfio_pci_dev_class_init, + }; + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-hw-vfio-pci-add-type-name-and-group-fields-in-VFIODe.patch b/SOURCES/kvm-hw-vfio-pci-add-type-name-and-group-fields-in-VFIODe.patch new file mode 100644 index 0000000..dd17e5d --- /dev/null +++ b/SOURCES/kvm-hw-vfio-pci-add-type-name-and-group-fields-in-VFIODe.patch @@ -0,0 +1,136 @@ +From dde4b959d6722bc2ebc5cd247b4e21055d2f0abd Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Fri, 29 Sep 2017 21:44:35 +0200 +Subject: [PATCH 05/27] hw/vfio/pci: add type, name and group fields in + VFIODevice + +RH-Author: Alex Williamson +Message-id: <20170929214435.16765.27045.stgit@gimli.home> +Patchwork-id: 76763 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 05/16] hw/vfio/pci: add type, name and group fields in VFIODevice +Bugzilla: 1494181 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Auger Eric +RH-Acked-by: Miroslav Rezanina + +From: Eric Auger + +Upstream: 462037c9e85b27149e71d7f5c7f41375ca6e47d5 + +Add 3 new fields in the VFIODevice struct. Type is set to +VFIO_DEVICE_TYPE_PCI. The type enum value will later be used +to discriminate between VFIO PCI and platform devices. The name is +set to domain:bus:slot:function. Currently used to test whether +the device already is attached to the group. Later on, the name +will be used to simplify all traces. The group is simply moved +from VFIOPCIDevice to VFIODevice. + +Signed-off-by: Eric Auger +[Fix g_strdup_printf() usage] +Signed-off-by: Alex Williamson + +Signed-off-by: Miroslav Rezanina +--- + hw/misc/vfio.c | 27 ++++++++++++++++++--------- + 1 file changed, 18 insertions(+), 9 deletions(-) + +diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c +index 340d967..cc151e2 100644 +--- a/hw/misc/vfio.c ++++ b/hw/misc/vfio.c +@@ -55,6 +55,10 @@ + #define VFIO_ALLOW_KVM_MSI 1 + #define VFIO_ALLOW_KVM_MSIX 1 + ++enum { ++ VFIO_DEVICE_TYPE_PCI = 0, ++}; ++ + struct VFIOPCIDevice; + + typedef struct VFIOQuirk { +@@ -175,7 +179,10 @@ typedef struct VFIOMSIXInfo { + } VFIOMSIXInfo; + + typedef struct VFIODevice { ++ struct VFIOGroup *group; ++ char *name; + int fd; ++ int type; + } VFIODevice; + + typedef struct VFIOPCIDevice { +@@ -197,7 +204,6 @@ typedef struct VFIOPCIDevice { + VFIOVGA vga; /* 0xa0000, 0x3b0, 0x3c0 */ + PCIHostDeviceAddress host; + QLIST_ENTRY(VFIOPCIDevice) next; +- struct VFIOGroup *group; + EventNotifier err_notifier; + EventNotifier req_notifier; + uint32_t features; +@@ -3526,7 +3532,7 @@ static int vfio_get_device(VFIOGroup *group, const char *name, + } + + vdev->vbasedev.fd = ret; +- vdev->group = group; ++ vdev->vbasedev.group = group; + QLIST_INSERT_HEAD(&group->device_list, vdev, next); + + /* Sanity check device */ +@@ -3658,7 +3664,7 @@ static int vfio_get_device(VFIOGroup *group, const char *name, + error: + if (ret) { + QLIST_REMOVE(vdev, next); +- vdev->group = NULL; ++ vdev->vbasedev.group = NULL; + close(vdev->vbasedev.fd); + } + return ret; +@@ -3667,9 +3673,10 @@ error: + static void vfio_put_device(VFIOPCIDevice *vdev) + { + QLIST_REMOVE(vdev, next); +- vdev->group = NULL; ++ vdev->vbasedev.group = NULL; + DPRINTF("vfio_put_device: close vdev->vbasedev.fd\n"); + close(vdev->vbasedev.fd); ++ g_free(vdev->vbasedev.name); + if (vdev->msix) { + g_free(vdev->msix); + vdev->msix = NULL; +@@ -3904,6 +3911,11 @@ static int vfio_initfn(PCIDevice *pdev) + return -errno; + } + ++ vdev->vbasedev.type = VFIO_DEVICE_TYPE_PCI; ++ vdev->vbasedev.name = g_strdup_printf("%04x:%02x:%02x.%01x", ++ vdev->host.domain, vdev->host.bus, ++ vdev->host.slot, vdev->host.function); ++ + strncat(path, "iommu_group", sizeof(path) - strlen(path) - 1); + + len = readlink(path, iommu_group_path, sizeof(path)); +@@ -3934,10 +3946,7 @@ static int vfio_initfn(PCIDevice *pdev) + vdev->host.function); + + QLIST_FOREACH(pvdev, &group->device_list, next) { +- if (pvdev->host.domain == vdev->host.domain && +- pvdev->host.bus == vdev->host.bus && +- pvdev->host.slot == vdev->host.slot && +- pvdev->host.function == vdev->host.function) { ++ if (strcmp(pvdev->vbasedev.name, vdev->vbasedev.name) == 0) { + + error_report("vfio: error: device %s is already attached", path); + vfio_put_group(group); +@@ -4042,7 +4051,7 @@ out_put: + static void vfio_exitfn(PCIDevice *pdev) + { + VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); +- VFIOGroup *group = vdev->group; ++ VFIOGroup *group = vdev->vbasedev.group; + + vfio_unregister_req_notifier(vdev); + vfio_unregister_err_notifier(vdev); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-hw-vfio-pci-generalize-mask-unmask-to-any-IRQ-index.patch b/SOURCES/kvm-hw-vfio-pci-generalize-mask-unmask-to-any-IRQ-index.patch new file mode 100644 index 0000000..c650b7e --- /dev/null +++ b/SOURCES/kvm-hw-vfio-pci-generalize-mask-unmask-to-any-IRQ-index.patch @@ -0,0 +1,123 @@ +From c7e1a8da5c3576d962c10c7afc11b0146f6b9adc Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Fri, 29 Sep 2017 21:44:24 +0200 +Subject: [PATCH 03/27] hw/vfio/pci: generalize mask/unmask to any IRQ index + +RH-Author: Alex Williamson +Message-id: <20170929214424.16765.25345.stgit@gimli.home> +Patchwork-id: 76761 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 03/16] hw/vfio/pci: generalize mask/unmask to any IRQ index +Bugzilla: 1494181 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Auger Eric +RH-Acked-by: Miroslav Rezanina + +From: Eric Auger + +Upstream: 079eb19cbb3079536788dfd58832824804815e48 + +To prepare for platform device introduction, rename vfio_mask_intx +and vfio_unmask_intx into vfio_mask_single_irqindex and respectively +unmask_single_irqindex. Also use a nex index parameter. + +With that name and prototype the function will be usable for other +indexes than VFIO_PCI_INTX_IRQ_INDEX. + +Signed-off-by: Eric Auger +Signed-off-by: Alex Williamson +Signed-off-by: Miroslav Rezanina +--- + hw/misc/vfio.c | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c +index a1ca883..ed9b8c4 100644 +--- a/hw/misc/vfio.c ++++ b/hw/misc/vfio.c +@@ -288,12 +288,12 @@ static void vfio_disable_irqindex(VFIOPCIDevice *vdev, int index) + /* + * INTx + */ +-static void vfio_unmask_intx(VFIOPCIDevice *vdev) ++static void vfio_unmask_single_irqindex(VFIOPCIDevice *vdev, int index) + { + struct vfio_irq_set irq_set = { + .argsz = sizeof(irq_set), + .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK, +- .index = VFIO_PCI_INTX_IRQ_INDEX, ++ .index = index, + .start = 0, + .count = 1, + }; +@@ -302,12 +302,12 @@ static void vfio_unmask_intx(VFIOPCIDevice *vdev) + } + + #ifdef CONFIG_KVM /* Unused outside of CONFIG_KVM code */ +-static void vfio_mask_intx(VFIOPCIDevice *vdev) ++static void vfio_mask_single_irqindex(VFIOPCIDevice *vdev, int index) + { + struct vfio_irq_set irq_set = { + .argsz = sizeof(irq_set), + .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_MASK, +- .index = VFIO_PCI_INTX_IRQ_INDEX, ++ .index = index, + .start = 0, + .count = 1, + }; +@@ -376,7 +376,7 @@ static void vfio_eoi(VFIOPCIDevice *vdev) + + vdev->intx.pending = false; + qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0); +- vfio_unmask_intx(vdev); ++ vfio_unmask_single_irqindex(vdev, VFIO_PCI_INTX_IRQ_INDEX); + } + + static void vfio_enable_intx_kvm(VFIOPCIDevice *vdev) +@@ -399,7 +399,7 @@ static void vfio_enable_intx_kvm(VFIOPCIDevice *vdev) + + /* Get to a known interrupt state */ + qemu_set_fd_handler(irqfd.fd, NULL, NULL, vdev); +- vfio_mask_intx(vdev); ++ vfio_mask_single_irqindex(vdev, VFIO_PCI_INTX_IRQ_INDEX); + vdev->intx.pending = false; + qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0); + +@@ -437,7 +437,7 @@ static void vfio_enable_intx_kvm(VFIOPCIDevice *vdev) + } + + /* Let'em rip */ +- vfio_unmask_intx(vdev); ++ vfio_unmask_single_irqindex(vdev, VFIO_PCI_INTX_IRQ_INDEX); + + vdev->intx.kvm_accel = true; + +@@ -454,7 +454,7 @@ fail_irqfd: + event_notifier_cleanup(&vdev->intx.unmask); + fail: + qemu_set_fd_handler(irqfd.fd, vfio_intx_interrupt, NULL, vdev); +- vfio_unmask_intx(vdev); ++ vfio_unmask_single_irqindex(vdev, VFIO_PCI_INTX_IRQ_INDEX); + #endif + } + +@@ -475,7 +475,7 @@ static void vfio_disable_intx_kvm(VFIOPCIDevice *vdev) + * Get to a known state, hardware masked, QEMU ready to accept new + * interrupts, QEMU IRQ de-asserted. + */ +- vfio_mask_intx(vdev); ++ vfio_mask_single_irqindex(vdev, VFIO_PCI_INTX_IRQ_INDEX); + vdev->intx.pending = false; + qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0); + +@@ -493,7 +493,7 @@ static void vfio_disable_intx_kvm(VFIOPCIDevice *vdev) + vdev->intx.kvm_accel = false; + + /* If we've missed an event, let it re-fire through QEMU */ +- vfio_unmask_intx(vdev); ++ vfio_unmask_single_irqindex(vdev, VFIO_PCI_INTX_IRQ_INDEX); + + DPRINTF("%s(%04x:%02x:%02x.%x) KVM INTx accel disabled\n", + __func__, vdev->host.domain, vdev->host.bus, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-hw-vfio-pci-handle-reset-at-VFIODevice.patch b/SOURCES/kvm-hw-vfio-pci-handle-reset-at-VFIODevice.patch new file mode 100644 index 0000000..07a343b --- /dev/null +++ b/SOURCES/kvm-hw-vfio-pci-handle-reset-at-VFIODevice.patch @@ -0,0 +1,320 @@ +From f81cc30fefd469f19b2f4550d4453a8aaff3239a Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Fri, 29 Sep 2017 21:44:49 +0200 +Subject: [PATCH 06/27] hw/vfio/pci: handle reset at VFIODevice + +RH-Author: Alex Williamson +Message-id: <20170929214449.16765.43500.stgit@gimli.home> +Patchwork-id: 76764 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 06/16] hw/vfio/pci: handle reset at VFIODevice +Bugzilla: 1494181 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Auger Eric +RH-Acked-by: Miroslav Rezanina + +From: Eric Auger + +Upstream: b47d8efa9f430c332bf96ce6eede169eb48422ad + +Since we can potentially have both PCI and platform devices in +the same VFIO group, this latter now owns a list of VFIODevices. +A unified reset handler, vfio_reset_handler, is registered, looping +through this VFIODevice list. 2 specialized operations are introduced +(vfio_compute_needs_reset and vfio_hot_reset_multi): they allow to +implement type specific behavior. also reset_works and needs_reset +VFIOPCIDevice fields are moved into VFIODevice. + +Signed-off-by: Eric Auger +Signed-off-by: Alex Williamson +Signed-off-by: Miroslav Rezanina +--- + hw/misc/vfio.c | 95 +++++++++++++++++++++++++++++++++++++++------------------- + 1 file changed, 64 insertions(+), 31 deletions(-) + +diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c +index cc151e2..3e559ed 100644 +--- a/hw/misc/vfio.c ++++ b/hw/misc/vfio.c +@@ -178,13 +178,24 @@ typedef struct VFIOMSIXInfo { + void *mmap; + } VFIOMSIXInfo; + ++typedef struct VFIODeviceOps VFIODeviceOps; ++ + typedef struct VFIODevice { ++ QLIST_ENTRY(VFIODevice) next; + struct VFIOGroup *group; + char *name; + int fd; + int type; ++ bool reset_works; ++ bool needs_reset; ++ VFIODeviceOps *ops; + } VFIODevice; + ++struct VFIODeviceOps { ++ void (*vfio_compute_needs_reset)(VFIODevice *vdev); ++ int (*vfio_hot_reset_multi)(VFIODevice *vdev); ++}; ++ + typedef struct VFIOPCIDevice { + PCIDevice pdev; + VFIODevice vbasedev; +@@ -203,7 +214,6 @@ typedef struct VFIOPCIDevice { + VFIOBAR bars[PCI_NUM_REGIONS - 1]; /* No ROM */ + VFIOVGA vga; /* 0xa0000, 0x3b0, 0x3c0 */ + PCIHostDeviceAddress host; +- QLIST_ENTRY(VFIOPCIDevice) next; + EventNotifier err_notifier; + EventNotifier req_notifier; + uint32_t features; +@@ -213,13 +223,11 @@ typedef struct VFIOPCIDevice { + #define VFIO_FEATURE_ENABLE_REQ (1 << VFIO_FEATURE_ENABLE_REQ_BIT) + int32_t bootindex; + uint8_t pm_cap; +- bool reset_works; + bool has_vga; + bool pci_aer; + bool req_enabled; + bool has_flr; + bool has_pm_reset; +- bool needs_reset; + bool rom_read_failed; + } VFIOPCIDevice; + +@@ -227,7 +235,7 @@ typedef struct VFIOGroup { + int fd; + int groupid; + VFIOContainer *container; +- QLIST_HEAD(, VFIOPCIDevice) device_list; ++ QLIST_HEAD(, VFIODevice) device_list; + QLIST_ENTRY(VFIOGroup) next; + QLIST_ENTRY(VFIOGroup) container_next; + } VFIOGroup; +@@ -3064,7 +3072,7 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single) + single ? "one" : "multi"); + + vfio_pci_pre_reset(vdev); +- vdev->needs_reset = false; ++ vdev->vbasedev.needs_reset = false; + + info = g_malloc0(sizeof(*info)); + info->argsz = sizeof(*info); +@@ -3100,6 +3108,7 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single) + for (i = 0; i < info->count; i++) { + PCIHostDeviceAddress host; + VFIOPCIDevice *tmp; ++ VFIODevice *vbasedev_iter; + + host.domain = devices[i].segment; + host.bus = devices[i].bus; +@@ -3131,7 +3140,11 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single) + } + + /* Prep dependent devices for reset and clear our marker. */ +- QLIST_FOREACH(tmp, &group->device_list, next) { ++ QLIST_FOREACH(vbasedev_iter, &group->device_list, next) { ++ if (vbasedev_iter->type != VFIO_DEVICE_TYPE_PCI) { ++ continue; ++ } ++ tmp = container_of(vbasedev_iter, VFIOPCIDevice, vbasedev); + if (vfio_pci_host_match(&host, &tmp->host)) { + if (single) { + DPRINTF("vfio: found another in-use device " +@@ -3141,7 +3154,7 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single) + goto out_single; + } + vfio_pci_pre_reset(tmp); +- tmp->needs_reset = false; ++ tmp->vbasedev.needs_reset = false; + multi = true; + break; + } +@@ -3192,6 +3205,7 @@ out: + for (i = 0; i < info->count; i++) { + PCIHostDeviceAddress host; + VFIOPCIDevice *tmp; ++ VFIODevice *vbasedev_iter; + + host.domain = devices[i].segment; + host.bus = devices[i].bus; +@@ -3212,7 +3226,11 @@ out: + break; + } + +- QLIST_FOREACH(tmp, &group->device_list, next) { ++ QLIST_FOREACH(vbasedev_iter, &group->device_list, next) { ++ if (vbasedev_iter->type != VFIO_DEVICE_TYPE_PCI) { ++ continue; ++ } ++ tmp = container_of(vbasedev_iter, VFIOPCIDevice, vbasedev); + if (vfio_pci_host_match(&host, &tmp->host)) { + vfio_pci_post_reset(tmp); + break; +@@ -3246,28 +3264,40 @@ static int vfio_pci_hot_reset_one(VFIOPCIDevice *vdev) + return vfio_pci_hot_reset(vdev, true); + } + +-static int vfio_pci_hot_reset_multi(VFIOPCIDevice *vdev) ++static int vfio_pci_hot_reset_multi(VFIODevice *vbasedev) + { ++ VFIOPCIDevice *vdev = container_of(vbasedev, VFIOPCIDevice, vbasedev); + return vfio_pci_hot_reset(vdev, false); + } + +-static void vfio_pci_reset_handler(void *opaque) ++static void vfio_pci_compute_needs_reset(VFIODevice *vbasedev) ++{ ++ VFIOPCIDevice *vdev = container_of(vbasedev, VFIOPCIDevice, vbasedev); ++ if (!vbasedev->reset_works || (!vdev->has_flr && vdev->has_pm_reset)) { ++ vbasedev->needs_reset = true; ++ } ++} ++ ++static VFIODeviceOps vfio_pci_ops = { ++ .vfio_compute_needs_reset = vfio_pci_compute_needs_reset, ++ .vfio_hot_reset_multi = vfio_pci_hot_reset_multi, ++}; ++ ++static void vfio_reset_handler(void *opaque) + { + VFIOGroup *group; +- VFIOPCIDevice *vdev; ++ VFIODevice *vbasedev; + + QLIST_FOREACH(group, &group_list, next) { +- QLIST_FOREACH(vdev, &group->device_list, next) { +- if (!vdev->reset_works || (!vdev->has_flr && vdev->has_pm_reset)) { +- vdev->needs_reset = true; +- } ++ QLIST_FOREACH(vbasedev, &group->device_list, next) { ++ vbasedev->ops->vfio_compute_needs_reset(vbasedev); + } + } + + QLIST_FOREACH(group, &group_list, next) { +- QLIST_FOREACH(vdev, &group->device_list, next) { +- if (vdev->needs_reset) { +- vfio_pci_hot_reset_multi(vdev); ++ QLIST_FOREACH(vbasedev, &group->device_list, next) { ++ if (vbasedev->needs_reset) { ++ vbasedev->ops->vfio_hot_reset_multi(vbasedev); + } + } + } +@@ -3486,7 +3516,7 @@ static VFIOGroup *vfio_get_group(int groupid) + } + + if (QLIST_EMPTY(&group_list)) { +- qemu_register_reset(vfio_pci_reset_handler, NULL); ++ qemu_register_reset(vfio_reset_handler, NULL); + } + + QLIST_INSERT_HEAD(&group_list, group, next); +@@ -3510,7 +3540,7 @@ static void vfio_put_group(VFIOGroup *group) + g_free(group); + + if (QLIST_EMPTY(&group_list)) { +- qemu_unregister_reset(vfio_pci_reset_handler, NULL); ++ qemu_unregister_reset(vfio_reset_handler, NULL); + } + } + +@@ -3533,7 +3563,7 @@ static int vfio_get_device(VFIOGroup *group, const char *name, + + vdev->vbasedev.fd = ret; + vdev->vbasedev.group = group; +- QLIST_INSERT_HEAD(&group->device_list, vdev, next); ++ QLIST_INSERT_HEAD(&group->device_list, &vdev->vbasedev, next); + + /* Sanity check device */ + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_INFO, &dev_info); +@@ -3550,7 +3580,7 @@ static int vfio_get_device(VFIOGroup *group, const char *name, + goto error; + } + +- vdev->reset_works = !!(dev_info.flags & VFIO_DEVICE_FLAGS_RESET); ++ vdev->vbasedev.reset_works = !!(dev_info.flags & VFIO_DEVICE_FLAGS_RESET); + + if (dev_info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1) { + error_report("vfio: unexpected number of io regions %u", +@@ -3663,7 +3693,7 @@ static int vfio_get_device(VFIOGroup *group, const char *name, + + error: + if (ret) { +- QLIST_REMOVE(vdev, next); ++ QLIST_REMOVE(&vdev->vbasedev, next); + vdev->vbasedev.group = NULL; + close(vdev->vbasedev.fd); + } +@@ -3672,7 +3702,7 @@ error: + + static void vfio_put_device(VFIOPCIDevice *vdev) + { +- QLIST_REMOVE(vdev, next); ++ QLIST_REMOVE(&vdev->vbasedev, next); + vdev->vbasedev.group = NULL; + DPRINTF("vfio_put_device: close vdev->vbasedev.fd\n"); + close(vdev->vbasedev.fd); +@@ -3881,7 +3911,8 @@ static void vfio_unregister_req_notifier(VFIOPCIDevice *vdev) + + static int vfio_initfn(PCIDevice *pdev) + { +- VFIOPCIDevice *pvdev, *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); ++ VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); ++ VFIODevice *vbasedev_iter; + VFIOGroup *group; + char path[PATH_MAX], iommu_group_path[PATH_MAX], *group_name; + ssize_t len; +@@ -3890,7 +3921,7 @@ static int vfio_initfn(PCIDevice *pdev) + int ret, i = 0; + + QLIST_FOREACH(group, &group_list, next) { +- QLIST_FOREACH(pvdev, &group->device_list, next) { ++ QLIST_FOREACH(vbasedev_iter, &group->device_list, next) { + i++; + } + } +@@ -3911,6 +3942,8 @@ static int vfio_initfn(PCIDevice *pdev) + return -errno; + } + ++ vdev->vbasedev.ops = &vfio_pci_ops; ++ + vdev->vbasedev.type = VFIO_DEVICE_TYPE_PCI; + vdev->vbasedev.name = g_strdup_printf("%04x:%02x:%02x.%01x", + vdev->host.domain, vdev->host.bus, +@@ -3945,9 +3978,8 @@ static int vfio_initfn(PCIDevice *pdev) + vdev->host.domain, vdev->host.bus, vdev->host.slot, + vdev->host.function); + +- QLIST_FOREACH(pvdev, &group->device_list, next) { +- if (strcmp(pvdev->vbasedev.name, vdev->vbasedev.name) == 0) { +- ++ QLIST_FOREACH(vbasedev_iter, &group->device_list, next) { ++ if (strcmp(vbasedev_iter->name, vdev->vbasedev.name) == 0) { + error_report("vfio: error: device %s is already attached", path); + vfio_put_group(group); + return -EBUSY; +@@ -4078,7 +4110,8 @@ static void vfio_pci_reset(DeviceState *dev) + + vfio_pci_pre_reset(vdev); + +- if (vdev->reset_works && (vdev->has_flr || !vdev->has_pm_reset) && ++ if (vdev->vbasedev.reset_works && ++ (vdev->has_flr || !vdev->has_pm_reset) && + !ioctl(vdev->vbasedev.fd, VFIO_DEVICE_RESET)) { + DPRINTF("%04x:%02x:%02x.%x FLR/VFIO_DEVICE_RESET\n", vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); +@@ -4091,7 +4124,7 @@ static void vfio_pci_reset(DeviceState *dev) + } + + /* If nothing else works and the device supports PM reset, use it */ +- if (vdev->reset_works && vdev->has_pm_reset && ++ if (vdev->vbasedev.reset_works && vdev->has_pm_reset && + !ioctl(vdev->vbasedev.fd, VFIO_DEVICE_RESET)) { + DPRINTF("%04x:%02x:%02x.%x PCI PM Reset\n", vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-hw-vfio-pci-introduce-minimalist-VFIODevice-with-fd.patch b/SOURCES/kvm-hw-vfio-pci-introduce-minimalist-VFIODevice-with-fd.patch new file mode 100644 index 0000000..3a89f16 --- /dev/null +++ b/SOURCES/kvm-hw-vfio-pci-introduce-minimalist-VFIODevice-with-fd.patch @@ -0,0 +1,534 @@ +From ec24bb3a66429e7b1d086ab6f3597c550099831d Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Fri, 29 Sep 2017 21:44:30 +0200 +Subject: [PATCH 04/27] hw/vfio/pci: introduce minimalist VFIODevice with fd + +RH-Author: Alex Williamson +Message-id: <20170929214430.16765.39580.stgit@gimli.home> +Patchwork-id: 76762 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 04/16] hw/vfio/pci: introduce minimalist VFIODevice with fd +Bugzilla: 1494181 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Auger Eric +RH-Acked-by: Miroslav Rezanina + +From: Eric Auger + +Upstream: 5546a621a8801351601537b311539486b9b3ee79 +RHEL: Include request notifier + +Introduce a new base VFIODevice strcut that will be used by both PCI +and Platform VFIO device. Move VFIOPCIDevice fd field there. Obviously +other fields from VFIOPCIDevice will be moved there but this patch +file is introduced to ease the review. + +Also vfio_mask_single_irqindex, vfio_unmask_single_irqindex, +vfio_disable_irqindex now take a VFIODevice handle as argument. + +Signed-off-by: Eric Auger +Signed-off-by: Alex Williamson +Signed-off-by: Miroslav Rezanina +--- + hw/misc/vfio.c | 123 +++++++++++++++++++++++++++++++-------------------------- + 1 file changed, 66 insertions(+), 57 deletions(-) + +diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c +index ed9b8c4..340d967 100644 +--- a/hw/misc/vfio.c ++++ b/hw/misc/vfio.c +@@ -174,9 +174,13 @@ typedef struct VFIOMSIXInfo { + void *mmap; + } VFIOMSIXInfo; + ++typedef struct VFIODevice { ++ int fd; ++} VFIODevice; ++ + typedef struct VFIOPCIDevice { + PCIDevice pdev; +- int fd; ++ VFIODevice vbasedev; + VFIOINTx intx; + unsigned int config_size; + uint8_t *emulated_config_bits; /* QEMU emulated bits, little-endian */ +@@ -272,7 +276,7 @@ static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled); + /* + * Common VFIO interrupt disable + */ +-static void vfio_disable_irqindex(VFIOPCIDevice *vdev, int index) ++static void vfio_disable_irqindex(VFIODevice *vbasedev, int index) + { + struct vfio_irq_set irq_set = { + .argsz = sizeof(irq_set), +@@ -282,13 +286,13 @@ static void vfio_disable_irqindex(VFIOPCIDevice *vdev, int index) + .count = 0, + }; + +- ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); ++ ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); + } + + /* + * INTx + */ +-static void vfio_unmask_single_irqindex(VFIOPCIDevice *vdev, int index) ++static void vfio_unmask_single_irqindex(VFIODevice *vbasedev, int index) + { + struct vfio_irq_set irq_set = { + .argsz = sizeof(irq_set), +@@ -298,11 +302,11 @@ static void vfio_unmask_single_irqindex(VFIOPCIDevice *vdev, int index) + .count = 1, + }; + +- ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); ++ ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); + } + + #ifdef CONFIG_KVM /* Unused outside of CONFIG_KVM code */ +-static void vfio_mask_single_irqindex(VFIOPCIDevice *vdev, int index) ++static void vfio_mask_single_irqindex(VFIODevice *vbasedev, int index) + { + struct vfio_irq_set irq_set = { + .argsz = sizeof(irq_set), +@@ -312,7 +316,7 @@ static void vfio_mask_single_irqindex(VFIOPCIDevice *vdev, int index) + .count = 1, + }; + +- ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); ++ ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); + } + #endif + +@@ -376,7 +380,7 @@ static void vfio_eoi(VFIOPCIDevice *vdev) + + vdev->intx.pending = false; + qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0); +- vfio_unmask_single_irqindex(vdev, VFIO_PCI_INTX_IRQ_INDEX); ++ vfio_unmask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); + } + + static void vfio_enable_intx_kvm(VFIOPCIDevice *vdev) +@@ -399,7 +403,7 @@ static void vfio_enable_intx_kvm(VFIOPCIDevice *vdev) + + /* Get to a known interrupt state */ + qemu_set_fd_handler(irqfd.fd, NULL, NULL, vdev); +- vfio_mask_single_irqindex(vdev, VFIO_PCI_INTX_IRQ_INDEX); ++ vfio_mask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); + vdev->intx.pending = false; + qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0); + +@@ -429,7 +433,7 @@ static void vfio_enable_intx_kvm(VFIOPCIDevice *vdev) + + *pfd = irqfd.resamplefd; + +- ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); ++ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set); + g_free(irq_set); + if (ret) { + error_report("vfio: Error: Failed to setup INTx unmask fd: %m"); +@@ -437,7 +441,7 @@ static void vfio_enable_intx_kvm(VFIOPCIDevice *vdev) + } + + /* Let'em rip */ +- vfio_unmask_single_irqindex(vdev, VFIO_PCI_INTX_IRQ_INDEX); ++ vfio_unmask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); + + vdev->intx.kvm_accel = true; + +@@ -454,7 +458,7 @@ fail_irqfd: + event_notifier_cleanup(&vdev->intx.unmask); + fail: + qemu_set_fd_handler(irqfd.fd, vfio_intx_interrupt, NULL, vdev); +- vfio_unmask_single_irqindex(vdev, VFIO_PCI_INTX_IRQ_INDEX); ++ vfio_unmask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); + #endif + } + +@@ -475,7 +479,7 @@ static void vfio_disable_intx_kvm(VFIOPCIDevice *vdev) + * Get to a known state, hardware masked, QEMU ready to accept new + * interrupts, QEMU IRQ de-asserted. + */ +- vfio_mask_single_irqindex(vdev, VFIO_PCI_INTX_IRQ_INDEX); ++ vfio_mask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); + vdev->intx.pending = false; + qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0); + +@@ -493,7 +497,7 @@ static void vfio_disable_intx_kvm(VFIOPCIDevice *vdev) + vdev->intx.kvm_accel = false; + + /* If we've missed an event, let it re-fire through QEMU */ +- vfio_unmask_single_irqindex(vdev, VFIO_PCI_INTX_IRQ_INDEX); ++ vfio_unmask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); + + DPRINTF("%s(%04x:%02x:%02x.%x) KVM INTx accel disabled\n", + __func__, vdev->host.domain, vdev->host.bus, +@@ -580,7 +584,7 @@ static int vfio_enable_intx(VFIOPCIDevice *vdev) + *pfd = event_notifier_get_fd(&vdev->intx.interrupt); + qemu_set_fd_handler(*pfd, vfio_intx_interrupt, NULL, vdev); + +- ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); ++ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set); + g_free(irq_set); + if (ret) { + error_report("vfio: Error: Failed to setup INTx fd: %m"); +@@ -605,7 +609,7 @@ static void vfio_disable_intx(VFIOPCIDevice *vdev) + + qemu_del_timer(vdev->intx.mmap_timer); + vfio_disable_intx_kvm(vdev); +- vfio_disable_irqindex(vdev, VFIO_PCI_INTX_IRQ_INDEX); ++ vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); + vdev->intx.pending = false; + qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0); + vfio_mmap_set_enabled(vdev, true); +@@ -695,7 +699,7 @@ static int vfio_enable_vectors(VFIOPCIDevice *vdev, bool msix) + fds[i] = fd; + } + +- ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); ++ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set); + + g_free(irq_set); + +@@ -792,7 +796,7 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, + * increase them as needed. + */ + if (vdev->nr_vectors < nr + 1) { +- vfio_disable_irqindex(vdev, VFIO_PCI_MSIX_IRQ_INDEX); ++ vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX); + vdev->nr_vectors = nr + 1; + ret = vfio_enable_vectors(vdev, true); + if (ret) { +@@ -820,7 +824,7 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, + *pfd = event_notifier_get_fd(&vector->interrupt); + } + +- ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); ++ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set); + g_free(irq_set); + if (ret) { + error_report("vfio: failed to modify vector, %d", ret); +@@ -871,7 +875,7 @@ static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr) + + *pfd = event_notifier_get_fd(&vector->interrupt); + +- ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); ++ ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set); + + g_free(irq_set); + } +@@ -1030,7 +1034,7 @@ static void vfio_disable_msix(VFIOPCIDevice *vdev) + } + + if (vdev->nr_vectors) { +- vfio_disable_irqindex(vdev, VFIO_PCI_MSIX_IRQ_INDEX); ++ vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX); + } + + vfio_disable_msi_common(vdev); +@@ -1041,7 +1045,7 @@ static void vfio_disable_msix(VFIOPCIDevice *vdev) + + static void vfio_disable_msi(VFIOPCIDevice *vdev) + { +- vfio_disable_irqindex(vdev, VFIO_PCI_MSI_IRQ_INDEX); ++ vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSI_IRQ_INDEX); + vfio_disable_msi_common(vdev); + + DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain, +@@ -1187,7 +1191,7 @@ static void vfio_pci_load_rom(VFIOPCIDevice *vdev) + off_t off = 0; + size_t bytes; + +- if (ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, ®_info)) { ++ if (ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_REGION_INFO, ®_info)) { + error_report("vfio: Error getting ROM info: %m"); + return; + } +@@ -1217,7 +1221,8 @@ static void vfio_pci_load_rom(VFIOPCIDevice *vdev) + memset(vdev->rom, 0xff, size); + + while (size) { +- bytes = pread(vdev->fd, vdev->rom + off, size, vdev->rom_offset + off); ++ bytes = pread(vdev->vbasedev.fd, vdev->rom + off, ++ size, vdev->rom_offset + off); + if (bytes == 0) { + break; + } else if (bytes > 0) { +@@ -1290,6 +1295,7 @@ static void vfio_pci_size_rom(VFIOPCIDevice *vdev) + off_t offset = vdev->config_offset + PCI_ROM_ADDRESS; + DeviceState *dev = DEVICE(vdev); + char name[32]; ++ int fd = vdev->vbasedev.fd; + + if (vdev->pdev.romfile || !vdev->pdev.rom_bar) { + /* Since pci handles romfile, just print a message and return */ +@@ -1308,10 +1314,10 @@ static void vfio_pci_size_rom(VFIOPCIDevice *vdev) + * Use the same size ROM BAR as the physical device. The contents + * will get filled in later when the guest tries to read it. + */ +- if (pread(vdev->fd, &orig, 4, offset) != 4 || +- pwrite(vdev->fd, &size, 4, offset) != 4 || +- pread(vdev->fd, &size, 4, offset) != 4 || +- pwrite(vdev->fd, &orig, 4, offset) != 4) { ++ if (pread(fd, &orig, 4, offset) != 4 || ++ pwrite(fd, &size, 4, offset) != 4 || ++ pread(fd, &size, 4, offset) != 4 || ++ pwrite(fd, &orig, 4, offset) != 4) { + error_report("%s(%04x:%02x:%02x.%x) failed: %m", + __func__, vdev->host.domain, vdev->host.bus, + vdev->host.slot, vdev->host.function); +@@ -2123,7 +2129,8 @@ static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len) + if (~emu_bits & (0xffffffffU >> (32 - len * 8))) { + ssize_t ret; + +- ret = pread(vdev->fd, &phys_val, len, vdev->config_offset + addr); ++ ret = pread(vdev->vbasedev.fd, &phys_val, len, ++ vdev->config_offset + addr); + if (ret != len) { + error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x) failed: %m", + __func__, vdev->host.domain, vdev->host.bus, +@@ -2153,7 +2160,8 @@ static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr, + vdev->host.function, addr, val, len); + + /* Write everything to VFIO, let it filter out what we can't write */ +- if (pwrite(vdev->fd, &val_le, len, vdev->config_offset + addr) != len) { ++ if (pwrite(vdev->vbasedev.fd, &val_le, len, vdev->config_offset + addr) ++ != len) { + error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x, 0x%x) failed: %m", + __func__, vdev->host.domain, vdev->host.bus, + vdev->host.slot, vdev->host.function, addr, val, len); +@@ -2389,7 +2397,7 @@ static int vfio_setup_msi(VFIOPCIDevice *vdev, int pos) + bool msi_64bit, msi_maskbit; + int ret, entries; + +- if (pread(vdev->fd, &ctrl, sizeof(ctrl), ++ if (pread(vdev->vbasedev.fd, &ctrl, sizeof(ctrl), + vdev->config_offset + pos + PCI_CAP_FLAGS) != sizeof(ctrl)) { + return -errno; + } +@@ -2428,23 +2436,24 @@ static int vfio_early_setup_msix(VFIOPCIDevice *vdev) + uint8_t pos; + uint16_t ctrl; + uint32_t table, pba; ++ int fd = vdev->vbasedev.fd; + + pos = pci_find_capability(&vdev->pdev, PCI_CAP_ID_MSIX); + if (!pos) { + return 0; + } + +- if (pread(vdev->fd, &ctrl, sizeof(ctrl), ++ if (pread(fd, &ctrl, sizeof(ctrl), + vdev->config_offset + pos + PCI_CAP_FLAGS) != sizeof(ctrl)) { + return -errno; + } + +- if (pread(vdev->fd, &table, sizeof(table), ++ if (pread(fd, &table, sizeof(table), + vdev->config_offset + pos + PCI_MSIX_TABLE) != sizeof(table)) { + return -errno; + } + +- if (pread(vdev->fd, &pba, sizeof(pba), ++ if (pread(fd, &pba, sizeof(pba), + vdev->config_offset + pos + PCI_MSIX_PBA) != sizeof(pba)) { + return -errno; + } +@@ -2628,7 +2637,7 @@ static void vfio_map_bar(VFIOPCIDevice *vdev, int nr) + vdev->host.function, nr); + + /* Determine what type of BAR this is for registration */ +- ret = pread(vdev->fd, &pci_bar, sizeof(pci_bar), ++ ret = pread(vdev->vbasedev.fd, &pci_bar, sizeof(pci_bar), + vdev->config_offset + PCI_BASE_ADDRESS_0 + (4 * nr)); + if (ret != sizeof(pci_bar)) { + error_report("vfio: Failed to read BAR %d (%m)", nr); +@@ -3054,7 +3063,7 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single) + info = g_malloc0(sizeof(*info)); + info->argsz = sizeof(*info); + +- ret = ioctl(vdev->fd, VFIO_DEVICE_GET_PCI_HOT_RESET_INFO, info); ++ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_PCI_HOT_RESET_INFO, info); + if (ret && errno != ENOSPC) { + ret = -errno; + if (!vdev->has_pm_reset) { +@@ -3070,7 +3079,7 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single) + info->argsz = sizeof(*info) + (count * sizeof(*devices)); + devices = &info->devices[0]; + +- ret = ioctl(vdev->fd, VFIO_DEVICE_GET_PCI_HOT_RESET_INFO, info); ++ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_PCI_HOT_RESET_INFO, info); + if (ret) { + ret = -errno; + error_report("vfio: hot reset info failed: %m"); +@@ -3165,7 +3174,7 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single) + } + + /* Bus reset! */ +- ret = ioctl(vdev->fd, VFIO_DEVICE_PCI_HOT_RESET, reset); ++ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_PCI_HOT_RESET, reset); + g_free(reset); + + DPRINTF("%04x:%02x:%02x.%x hot reset: %s\n", vdev->host.domain, +@@ -3516,12 +3525,12 @@ static int vfio_get_device(VFIOGroup *group, const char *name, + return ret; + } + +- vdev->fd = ret; ++ vdev->vbasedev.fd = ret; + vdev->group = group; + QLIST_INSERT_HEAD(&group->device_list, vdev, next); + + /* Sanity check device */ +- ret = ioctl(vdev->fd, VFIO_DEVICE_GET_INFO, &dev_info); ++ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_INFO, &dev_info); + if (ret) { + error_report("vfio: error getting device info: %m"); + goto error; +@@ -3551,7 +3560,7 @@ static int vfio_get_device(VFIOGroup *group, const char *name, + for (i = VFIO_PCI_BAR0_REGION_INDEX; i < VFIO_PCI_ROM_REGION_INDEX; i++) { + reg_info.index = i; + +- ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, ®_info); ++ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_REGION_INFO, ®_info); + if (ret) { + error_report("vfio: Error getting region %d info: %m", i); + goto error; +@@ -3565,14 +3574,14 @@ static int vfio_get_device(VFIOGroup *group, const char *name, + vdev->bars[i].flags = reg_info.flags; + vdev->bars[i].size = reg_info.size; + vdev->bars[i].fd_offset = reg_info.offset; +- vdev->bars[i].fd = vdev->fd; ++ vdev->bars[i].fd = vdev->vbasedev.fd; + vdev->bars[i].nr = i; + QLIST_INIT(&vdev->bars[i].quirks); + } + + reg_info.index = VFIO_PCI_CONFIG_REGION_INDEX; + +- ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, ®_info); ++ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_REGION_INFO, ®_info); + if (ret) { + error_report("vfio: Error getting config info: %m"); + goto error; +@@ -3596,7 +3605,7 @@ static int vfio_get_device(VFIOGroup *group, const char *name, + .index = VFIO_PCI_VGA_REGION_INDEX, + }; + +- ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, &vga_info); ++ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_REGION_INFO, &vga_info); + if (ret) { + error_report( + "vfio: Device does not support requested feature x-vga"); +@@ -3613,7 +3622,7 @@ static int vfio_get_device(VFIOGroup *group, const char *name, + } + + vdev->vga.fd_offset = vga_info.offset; +- vdev->vga.fd = vdev->fd; ++ vdev->vga.fd = vdev->vbasedev.fd; + + vdev->vga.region[QEMU_PCI_VGA_MEM].offset = QEMU_PCI_VGA_MEM_BASE; + vdev->vga.region[QEMU_PCI_VGA_MEM].nr = QEMU_PCI_VGA_MEM; +@@ -3632,7 +3641,7 @@ static int vfio_get_device(VFIOGroup *group, const char *name, + + irq_info.index = VFIO_PCI_ERR_IRQ_INDEX; + +- ret = ioctl(vdev->fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info); ++ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info); + if (ret) { + /* This can fail for an old kernel or legacy PCI dev */ + DPRINTF("VFIO_DEVICE_GET_IRQ_INFO failure: %m\n"); +@@ -3650,7 +3659,7 @@ error: + if (ret) { + QLIST_REMOVE(vdev, next); + vdev->group = NULL; +- close(vdev->fd); ++ close(vdev->vbasedev.fd); + } + return ret; + } +@@ -3659,8 +3668,8 @@ static void vfio_put_device(VFIOPCIDevice *vdev) + { + QLIST_REMOVE(vdev, next); + vdev->group = NULL; +- DPRINTF("vfio_put_device: close vdev->fd\n"); +- close(vdev->fd); ++ DPRINTF("vfio_put_device: close vdev->vbasedev.fd\n"); ++ close(vdev->vbasedev.fd); + if (vdev->msix) { + g_free(vdev->msix); + vdev->msix = NULL; +@@ -3729,7 +3738,7 @@ static void vfio_register_err_notifier(VFIOPCIDevice *vdev) + *pfd = event_notifier_get_fd(&vdev->err_notifier); + qemu_set_fd_handler(*pfd, vfio_err_notifier_handler, NULL, vdev); + +- ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); ++ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set); + if (ret) { + error_report("vfio: Failed to set up error notification"); + qemu_set_fd_handler(*pfd, NULL, NULL, vdev); +@@ -3762,7 +3771,7 @@ static void vfio_unregister_err_notifier(VFIOPCIDevice *vdev) + pfd = (int32_t *)&irq_set->data; + *pfd = -1; + +- ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); ++ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set); + if (ret) { + error_report("vfio: Failed to de-assign error fd: %m"); + } +@@ -3795,7 +3804,7 @@ static void vfio_register_req_notifier(VFIOPCIDevice *vdev) + return; + } + +- if (ioctl(vdev->fd, ++ if (ioctl(vdev->vbasedev.fd, + VFIO_DEVICE_GET_IRQ_INFO, &irq_info) < 0 || irq_info.count < 1) { + return; + } +@@ -3819,7 +3828,7 @@ static void vfio_register_req_notifier(VFIOPCIDevice *vdev) + *pfd = event_notifier_get_fd(&vdev->req_notifier); + qemu_set_fd_handler(*pfd, vfio_req_notifier_handler, NULL, vdev); + +- if (ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set)) { ++ if (ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set)) { + error_report("vfio: Failed to set up device request notification"); + qemu_set_fd_handler(*pfd, NULL, NULL, vdev); + event_notifier_cleanup(&vdev->req_notifier); +@@ -3852,7 +3861,7 @@ static void vfio_unregister_req_notifier(VFIOPCIDevice *vdev) + pfd = (int32_t *)&irq_set->data; + *pfd = -1; + +- if (ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set)) { ++ if (ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set)) { + error_report("vfio: Failed to de-assign device request fd: %m"); + } + g_free(irq_set); +@@ -3944,7 +3953,7 @@ static int vfio_initfn(PCIDevice *pdev) + } + + /* Get a copy of config space */ +- ret = pread(vdev->fd, vdev->pdev.config, ++ ret = pread(vdev->vbasedev.fd, vdev->pdev.config, + MIN(pci_config_size(&vdev->pdev), vdev->config_size), + vdev->config_offset); + if (ret < (int)MIN(pci_config_size(&vdev->pdev), vdev->config_size)) { +@@ -4061,7 +4070,7 @@ static void vfio_pci_reset(DeviceState *dev) + vfio_pci_pre_reset(vdev); + + if (vdev->reset_works && (vdev->has_flr || !vdev->has_pm_reset) && +- !ioctl(vdev->fd, VFIO_DEVICE_RESET)) { ++ !ioctl(vdev->vbasedev.fd, VFIO_DEVICE_RESET)) { + DPRINTF("%04x:%02x:%02x.%x FLR/VFIO_DEVICE_RESET\n", vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); + goto post_reset; +@@ -4074,7 +4083,7 @@ static void vfio_pci_reset(DeviceState *dev) + + /* If nothing else works and the device supports PM reset, use it */ + if (vdev->reset_works && vdev->has_pm_reset && +- !ioctl(vdev->fd, VFIO_DEVICE_RESET)) { ++ !ioctl(vdev->vbasedev.fd, VFIO_DEVICE_RESET)) { + DPRINTF("%04x:%02x:%02x.%x PCI PM Reset\n", vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); + goto post_reset; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-hw-vfio-pci-use-name-field-in-format-strings.patch b/SOURCES/kvm-hw-vfio-pci-use-name-field-in-format-strings.patch new file mode 100644 index 0000000..958cbb7 --- /dev/null +++ b/SOURCES/kvm-hw-vfio-pci-use-name-field-in-format-strings.patch @@ -0,0 +1,550 @@ +From 38023d511ff6770e4ff1d2a4e3fdcc3820a45b3f Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Fri, 29 Sep 2017 21:45:08 +0200 +Subject: [PATCH 08/27] hw/vfio/pci: use name field in format strings + +RH-Author: Alex Williamson +Message-id: <20170929214508.16765.18033.stgit@gimli.home> +Patchwork-id: 76766 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 08/16] hw/vfio/pci: use name field in format strings +Bugzilla: 1494181 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Auger Eric +RH-Acked-by: Miroslav Rezanina + +From: Eric Auger + +Upstream: df92ee444884ba66b5cc95e3ff3d5579f89ed4aa + +Signed-off-by: Eric Auger +Signed-off-by: Alex Williamson +Signed-off-by: Miroslav Rezanina +--- + hw/misc/vfio.c | 193 ++++++++++++++++++++------------------------------------- + 1 file changed, 68 insertions(+), 125 deletions(-) + +diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c +index 92414b9..0d88313 100644 +--- a/hw/misc/vfio.c ++++ b/hw/misc/vfio.c +@@ -375,8 +375,7 @@ static void vfio_intx_interrupt(void *opaque) + return; + } + +- DPRINTF("%s(%04x:%02x:%02x.%x) Pin %c\n", __func__, vdev->host.domain, +- vdev->host.bus, vdev->host.slot, vdev->host.function, ++ DPRINTF("%s(%s) Pin %c\n", __func__, vdev->vbasedev.name, + 'A' + vdev->intx.pin); + + vdev->intx.pending = true; +@@ -396,8 +395,7 @@ static void vfio_eoi(VFIODevice *vbasedev) + return; + } + +- DPRINTF("%s(%04x:%02x:%02x.%x) EOI\n", __func__, vdev->host.domain, +- vdev->host.bus, vdev->host.slot, vdev->host.function); ++ DPRINTF("%s(%s) EOI\n", __func__, vbasedev->name); + + vdev->intx.pending = false; + qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0); +@@ -466,9 +464,7 @@ static void vfio_enable_intx_kvm(VFIOPCIDevice *vdev) + + vdev->intx.kvm_accel = true; + +- DPRINTF("%s(%04x:%02x:%02x.%x) KVM INTx accel enabled\n", +- __func__, vdev->host.domain, vdev->host.bus, +- vdev->host.slot, vdev->host.function); ++ DPRINTF("%s(%s) KVM INTx accel enabled\n", __func__, vdev->vbasedev.name); + + return; + +@@ -520,9 +516,7 @@ static void vfio_disable_intx_kvm(VFIOPCIDevice *vdev) + /* If we've missed an event, let it re-fire through QEMU */ + vfio_unmask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); + +- DPRINTF("%s(%04x:%02x:%02x.%x) KVM INTx accel disabled\n", +- __func__, vdev->host.domain, vdev->host.bus, +- vdev->host.slot, vdev->host.function); ++ DPRINTF("%s(%s) KVM INTx accel disabled\n", __func__, vdev->vbasedev.name); + #endif + } + +@@ -541,9 +535,8 @@ static void vfio_update_irq(PCIDevice *pdev) + return; /* Nothing changed */ + } + +- DPRINTF("%s(%04x:%02x:%02x.%x) IRQ moved %d -> %d\n", __func__, +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function, vdev->intx.route.irq, route.irq); ++ DPRINTF("%s(%s) IRQ moved %d -> %d\n", __func__, ++ vdev->vbasedev.name, vdev->intx.route.irq, route.irq); + + vfio_disable_intx_kvm(vdev); + +@@ -618,8 +611,7 @@ static int vfio_enable_intx(VFIOPCIDevice *vdev) + + vdev->interrupt = VFIO_INT_INTx; + +- DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain, +- vdev->host.bus, vdev->host.slot, vdev->host.function); ++ DPRINTF("%s(%s)\n", __func__, vdev->vbasedev.name); + + return 0; + } +@@ -641,8 +633,7 @@ static void vfio_disable_intx(VFIOPCIDevice *vdev) + + vdev->interrupt = VFIO_INT_NONE; + +- DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain, +- vdev->host.bus, vdev->host.slot, vdev->host.function); ++ DPRINTF("%s(%s)\n", __func__, vdev->vbasedev.name); + } + + /* +@@ -669,9 +660,8 @@ static void vfio_msi_interrupt(void *opaque) + abort(); + } + +- DPRINTF("%s(%04x:%02x:%02x.%x) vector %d 0x%"PRIx64"/0x%x\n", __func__, +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function, nr, msg.address, msg.data); ++ DPRINTF("%s(%s) vector %d 0x%"PRIx64"/0x%x\n", __func__, ++ vdev->vbasedev.name, nr, msg.address, msg.data); + #endif + + if (vdev->interrupt == VFIO_INT_MSIX) { +@@ -778,9 +768,7 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, + VFIOMSIVector *vector; + int ret; + +- DPRINTF("%s(%04x:%02x:%02x.%x) vector %d used\n", __func__, +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function, nr); ++ DPRINTF("%s(%s) vector %d used\n", __func__, vdev->vbasedev.name, nr); + + vector = &vdev->msi_vectors[nr]; + +@@ -866,9 +854,7 @@ static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr) + VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); + VFIOMSIVector *vector = &vdev->msi_vectors[nr]; + +- DPRINTF("%s(%04x:%02x:%02x.%x) vector %d released\n", __func__, +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function, nr); ++ DPRINTF("%s(%s) vector %d released\n", __func__, vdev->vbasedev.name, nr); + + /* + * There are still old guests that mask and unmask vectors on every +@@ -931,8 +917,7 @@ static void vfio_enable_msix(VFIOPCIDevice *vdev) + error_report("vfio: msix_set_vector_notifiers failed"); + } + +- DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain, +- vdev->host.bus, vdev->host.slot, vdev->host.function); ++ DPRINTF("%s(%s)\n", __func__, vdev->vbasedev.name); + } + + static void vfio_enable_msi(VFIOPCIDevice *vdev) +@@ -1008,9 +993,8 @@ retry: + return; + } + +- DPRINTF("%s(%04x:%02x:%02x.%x) Enabled %d MSI vectors\n", __func__, +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function, vdev->nr_vectors); ++ DPRINTF("%s(%s) Enabled %d MSI vectors\n", __func__, ++ vdev->vbasedev.name, vdev->nr_vectors); + } + + static void vfio_disable_msi_common(VFIOPCIDevice *vdev) +@@ -1060,8 +1044,7 @@ static void vfio_disable_msix(VFIOPCIDevice *vdev) + + vfio_disable_msi_common(vdev); + +- DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain, +- vdev->host.bus, vdev->host.slot, vdev->host.function); ++ DPRINTF("%s(%s)\n", __func__, vdev->vbasedev.name); + } + + static void vfio_disable_msi(VFIOPCIDevice *vdev) +@@ -1069,8 +1052,7 @@ static void vfio_disable_msi(VFIOPCIDevice *vdev) + vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSI_IRQ_INDEX); + vfio_disable_msi_common(vdev); + +- DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain, +- vdev->host.bus, vdev->host.slot, vdev->host.function); ++ DPRINTF("%s(%s)\n", __func__, vdev->vbasedev.name); + } + + static void vfio_update_msi(VFIOPCIDevice *vdev) +@@ -1206,8 +1188,7 @@ static void vfio_pci_load_rom(VFIOPCIDevice *vdev) + return; + } + +- DPRINTF("Device %04x:%02x:%02x.%x ROM:\n", vdev->host.domain, +- vdev->host.bus, vdev->host.slot, vdev->host.function); ++ DPRINTF("Device %s ROM:\n", vdev->vbasedev.name); + DPRINTF(" size: 0x%lx, offset: 0x%lx, flags: 0x%lx\n", + (unsigned long)reg_info.size, (unsigned long)reg_info.offset, + (unsigned long)reg_info.flags); +@@ -1218,9 +1199,7 @@ static void vfio_pci_load_rom(VFIOPCIDevice *vdev) + if (!vdev->rom_size) { + vdev->rom_read_failed = true; + error_report("vfio-pci: Cannot read device rom at " +- "%04x:%02x:%02x.%x\n", +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function); ++ "%s\n", vdev->vbasedev.name); + error_printf("Device option ROM contents are probably invalid " + "(check dmesg).\nSkip option ROM probe with rombar=0, " + "or load from file with romfile=\n"); +@@ -1261,9 +1240,8 @@ static uint64_t vfio_rom_read(void *opaque, hwaddr addr, unsigned size) + memcpy(&val, vdev->rom + addr, + (addr < vdev->rom_size) ? MIN(size, vdev->rom_size - addr) : 0); + +- DPRINTF("%s(%04x:%02x:%02x.%x, 0x%"HWADDR_PRIx", 0x%x) = 0x%"PRIx64"\n", +- __func__, vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function, addr, size, val); ++ DPRINTF("%s(%s, 0x%"HWADDR_PRIx", 0x%x) = 0x%"PRIx64"\n", ++ __func__, vdev->vbasedev.name, addr, size, val); + + return val; + } +@@ -1360,8 +1338,7 @@ static void vfio_pci_size_rom(VFIOPCIDevice *vdev) + } + } + +- DPRINTF("%04x:%02x:%02x.%x ROM size 0x%x\n", vdev->host.domain, +- vdev->host.bus, vdev->host.slot, vdev->host.function, size); ++ DPRINTF("%s ROM size 0x%x\n", vdev->vbasedev.name, size); + + snprintf(name, sizeof(name), "vfio[%04x:%02x:%02x.%x].rom", + vdev->host.domain, vdev->host.bus, vdev->host.slot, +@@ -1496,10 +1473,9 @@ static uint64_t vfio_generic_window_quirk_read(void *opaque, + data = vfio_pci_read_config(&vdev->pdev, + quirk->data.address_val + offset, size); + +- DPRINTF("%s read(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx", %d) = 0x%" +- PRIx64"\n", memory_region_name(&quirk->mem), vdev->host.domain, +- vdev->host.bus, vdev->host.slot, vdev->host.function, +- quirk->data.bar, addr, size, data); ++ DPRINTF("%s read(%s:BAR%d+0x%"HWADDR_PRIx", %d) = 0x%" ++ PRIx64"\n", memory_region_name(&quirk->mem), ++ vdev->vbasedev.name, quirk->data.bar, addr, size, data); + } else { + data = vfio_region_read(&vdev->bars[quirk->data.bar].region, + addr + quirk->data.base_offset, size); +@@ -1545,10 +1521,9 @@ static void vfio_generic_window_quirk_write(void *opaque, hwaddr addr, + + vfio_pci_write_config(&vdev->pdev, + quirk->data.address_val + offset, data, size); +- DPRINTF("%s write(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx", 0x%" ++ DPRINTF("%s write(%s:BAR%d+0x%"HWADDR_PRIx", 0x%" + PRIx64", %d)\n", memory_region_name(&quirk->mem), +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function, quirk->data.bar, addr, data, size); ++ vdev->vbasedev.name, quirk->data.bar, addr, data, size); + return; + } + +@@ -1581,10 +1556,9 @@ static uint64_t vfio_generic_quirk_read(void *opaque, + + data = vfio_pci_read_config(&vdev->pdev, addr - offset, size); + +- DPRINTF("%s read(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx", %d) = 0x%" +- PRIx64"\n", memory_region_name(&quirk->mem), vdev->host.domain, +- vdev->host.bus, vdev->host.slot, vdev->host.function, +- quirk->data.bar, addr + base, size, data); ++ DPRINTF("%s read(%s:BAR%d+0x%"HWADDR_PRIx", %d) = 0x%" ++ PRIx64"\n", memory_region_name(&quirk->mem), ++ vdev->vbasedev.name, quirk->data.bar, addr + base, size, data); + } else { + data = vfio_region_read(&vdev->bars[quirk->data.bar].region, + addr + base, size); +@@ -1611,10 +1585,9 @@ static void vfio_generic_quirk_write(void *opaque, hwaddr addr, + + vfio_pci_write_config(&vdev->pdev, addr - offset, data, size); + +- DPRINTF("%s write(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx", 0x%" ++ DPRINTF("%s write(%s:BAR%d+0x%"HWADDR_PRIx", 0x%" + PRIx64", %d)\n", memory_region_name(&quirk->mem), +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function, quirk->data.bar, addr + base, data, size); ++ vdev->vbasedev.name, quirk->data.bar, addr + base, data, size); + } else { + vfio_region_write(&vdev->bars[quirk->data.bar].region, + addr + base, data, size); +@@ -1685,9 +1658,8 @@ static void vfio_vga_probe_ati_3c3_quirk(VFIOPCIDevice *vdev) + QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks, + quirk, next); + +- DPRINTF("Enabled ATI/AMD quirk 0x3c3 BAR4for device %04x:%02x:%02x.%x\n", +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function); ++ DPRINTF("Enabled ATI/AMD quirk 0x3c3 BAR4for device %s\n", ++ vdev->vbasedev.name); + } + + /* +@@ -1728,9 +1700,8 @@ static void vfio_probe_ati_bar4_window_quirk(VFIOPCIDevice *vdev, int nr) + + QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); + +- DPRINTF("Enabled ATI/AMD BAR4 window quirk for device %04x:%02x:%02x.%x\n", +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function); ++ DPRINTF("Enabled ATI/AMD BAR4 window quirk for device %s\n", ++ vdev->vbasedev.name); + } + + /* +@@ -1763,9 +1734,8 @@ static void vfio_probe_ati_bar2_4000_quirk(VFIOPCIDevice *vdev, int nr) + + QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); + +- DPRINTF("Enabled ATI/AMD BAR2 0x4000 quirk for device %04x:%02x:%02x.%x\n", +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function); ++ DPRINTF("Enabled ATI/AMD BAR2 0x4000 quirk for device %s\n", ++ vdev->vbasedev.name); + } + + /* +@@ -1898,9 +1868,8 @@ static void vfio_vga_probe_nvidia_3d0_quirk(VFIOPCIDevice *vdev) + QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks, + quirk, next); + +- DPRINTF("Enabled NVIDIA VGA 0x3d0 quirk for device %04x:%02x:%02x.%x\n", +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function); ++ DPRINTF("Enabled NVIDIA VGA 0x3d0 quirk for device %s\n", ++ vdev->vbasedev.name); + } + + /* +@@ -1989,9 +1958,8 @@ static void vfio_probe_nvidia_bar5_window_quirk(VFIOPCIDevice *vdev, int nr) + + QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); + +- DPRINTF("Enabled NVIDIA BAR5 window quirk for device %04x:%02x:%02x.%x\n", +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function); ++ DPRINTF("Enabled NVIDIA BAR5 window quirk for device %s\n", ++ vdev->vbasedev.name); + } + + /* +@@ -2029,9 +1997,8 @@ static void vfio_probe_nvidia_bar0_88000_quirk(VFIOPCIDevice *vdev, int nr) + + QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); + +- DPRINTF("Enabled NVIDIA BAR0 0x88000 quirk for device %04x:%02x:%02x.%x\n", +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function); ++ DPRINTF("Enabled NVIDIA BAR0 0x88000 quirk for device %s\n", ++ vdev->vbasedev.name); + } + + /* +@@ -2068,9 +2035,8 @@ static void vfio_probe_nvidia_bar0_1800_quirk(VFIOPCIDevice *vdev, int nr) + + QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); + +- DPRINTF("Enabled NVIDIA BAR0 0x1800 quirk for device %04x:%02x:%02x.%x\n", +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function); ++ DPRINTF("Enabled NVIDIA BAR0 0x1800 quirk for device %s\n", ++ vdev->vbasedev.name); + } + + /* +@@ -2156,9 +2122,8 @@ static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len) + + val = (emu_val & emu_bits) | (phys_val & ~emu_bits); + +- DPRINTF("%s(%04x:%02x:%02x.%x, @0x%x, len=0x%x) %x\n", __func__, +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function, addr, len, val); ++ DPRINTF("%s(%s, @0x%x, len=0x%x) %x\n", __func__, ++ vdev->vbasedev.name, addr, len, val); + + return val; + } +@@ -2169,9 +2134,8 @@ static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr, + VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); + uint32_t val_le = cpu_to_le32(val); + +- DPRINTF("%s(%04x:%02x:%02x.%x, @0x%x, 0x%x, len=0x%x)\n", __func__, +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function, addr, val, len); ++ DPRINTF("%s(%s, @0x%x, 0x%x, len=0x%x)\n", __func__, ++ vdev->vbasedev.name, addr, val, len); + + /* Write everything to VFIO, let it filter out what we can't write */ + if (pwrite(vdev->vbasedev.fd, &val_le, len, vdev->config_offset + addr) +@@ -2421,8 +2385,7 @@ static int vfio_setup_msi(VFIOPCIDevice *vdev, int pos) + msi_maskbit = !!(ctrl & PCI_MSI_FLAGS_MASKBIT); + entries = 1 << ((ctrl & PCI_MSI_FLAGS_QMASK) >> 1); + +- DPRINTF("%04x:%02x:%02x.%x PCI MSI CAP @0x%x\n", vdev->host.domain, +- vdev->host.bus, vdev->host.slot, vdev->host.function, pos); ++ DPRINTF("%s PCI MSI CAP @0x%x\n", vdev->vbasedev.name, pos); + + ret = msi_init(&vdev->pdev, pos, entries, msi_64bit, msi_maskbit); + if (ret < 0) { +@@ -2483,10 +2446,8 @@ static int vfio_early_setup_msix(VFIOPCIDevice *vdev) + vdev->msix->pba_offset = pba & ~PCI_MSIX_FLAGS_BIRMASK; + vdev->msix->entries = (ctrl & PCI_MSIX_FLAGS_QSIZE) + 1; + +- DPRINTF("%04x:%02x:%02x.%x " +- "PCI MSI-X CAP @0x%x, BAR %d, offset 0x%x, entries %d\n", +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function, pos, vdev->msix->table_bar, ++ DPRINTF("%s PCI MSI-X CAP @0x%x, BAR %d, offset 0x%x, entries %d\n", ++ vdev->vbasedev.name, pos, vdev->msix->table_bar, + vdev->msix->table_offset, vdev->msix->entries); + + /* +@@ -2895,9 +2856,7 @@ static void vfio_check_pcie_flr(VFIOPCIDevice *vdev, uint8_t pos) + uint32_t cap = pci_get_long(vdev->pdev.config + pos + PCI_EXP_DEVCAP); + + if (cap & PCI_EXP_DEVCAP_FLR) { +- DPRINTF("%04x:%02x:%02x.%x Supports FLR via PCIe cap\n", +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function); ++ DPRINTF("%s Supports FLR via PCIe cap\n", vdev->vbasedev.name); + vdev->has_flr = true; + } + } +@@ -2907,9 +2866,7 @@ static void vfio_check_pm_reset(VFIOPCIDevice *vdev, uint8_t pos) + uint16_t csr = pci_get_word(vdev->pdev.config + pos + PCI_PM_CTRL); + + if (!(csr & PCI_PM_CTRL_NO_SOFT_RESET)) { +- DPRINTF("%04x:%02x:%02x.%x Supports PM reset\n", +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function); ++ DPRINTF("%s Supports PM reset\n", vdev->vbasedev.name); + vdev->has_pm_reset = true; + } + } +@@ -2919,9 +2876,7 @@ static void vfio_check_af_flr(VFIOPCIDevice *vdev, uint8_t pos) + uint8_t cap = pci_get_byte(vdev->pdev.config + pos + PCI_AF_CAP); + + if ((cap & PCI_AF_CAP_TP) && (cap & PCI_AF_CAP_FLR)) { +- DPRINTF("%04x:%02x:%02x.%x Supports FLR via AF cap\n", +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function); ++ DPRINTF("%s Supports FLR via AF cap\n", vdev->vbasedev.name); + vdev->has_flr = true; + } + } +@@ -3072,8 +3027,7 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single) + int ret, i, count; + bool multi = false; + +- DPRINTF("%s(%04x:%02x:%02x.%x) %s\n", __func__, vdev->host.domain, +- vdev->host.bus, vdev->host.slot, vdev->host.function, ++ DPRINTF("%s(%s) %s\n", __func__, vdev->vbasedev.name, + single ? "one" : "multi"); + + vfio_pci_pre_reset(vdev); +@@ -3105,9 +3059,7 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single) + goto out_single; + } + +- DPRINTF("%04x:%02x:%02x.%x: hot reset dependent devices:\n", +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function); ++ DPRINTF("%s: hot reset dependent devices:\n", vdev->vbasedev.name); + + /* Verify that we have all the groups required */ + for (i = 0; i < info->count; i++) { +@@ -3135,10 +3087,9 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single) + + if (!group) { + if (!vdev->has_pm_reset) { +- error_report("vfio: Cannot reset device %04x:%02x:%02x.%x, " ++ error_report("vfio: Cannot reset device %s, " + "depends on group %d which is not owned.", +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function, devices[i].group_id); ++ vdev->vbasedev.name, devices[i].group_id); + } + ret = -EPERM; + goto out; +@@ -3153,8 +3104,7 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single) + if (vfio_pci_host_match(&host, &tmp->host)) { + if (single) { + DPRINTF("vfio: found another in-use device " +- "%04x:%02x:%02x.%x\n", host.domain, host.bus, +- host.slot, host.function); ++ "%s\n", tmp->vbasedev.name); + ret = -EINVAL; + goto out_single; + } +@@ -3201,9 +3151,7 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single) + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_PCI_HOT_RESET, reset); + g_free(reset); + +- DPRINTF("%04x:%02x:%02x.%x hot reset: %s\n", vdev->host.domain, +- vdev->host.bus, vdev->host.slot, vdev->host.function, +- ret ? "%m" : "Success"); ++ DPRINTF("%s hot reset: %s\n", vdev->vbasedev.name, ret ? "%m" : "Success"); + + out: + /* Re-enable INTx on affected devices */ +@@ -3691,10 +3639,9 @@ static int vfio_get_device(VFIOGroup *group, const char *name, + } else if (irq_info.count == 1) { + vdev->pci_aer = true; + } else { +- error_report("vfio: %04x:%02x:%02x.%x " ++ error_report("vfio: %s " + "Could not enable error recovery for the device", +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function); ++ vdev->vbasedev.name); + } + + error: +@@ -3971,8 +3918,7 @@ static int vfio_initfn(PCIDevice *pdev) + return -errno; + } + +- DPRINTF("%s(%04x:%02x:%02x.%x) group %d\n", __func__, vdev->host.domain, +- vdev->host.bus, vdev->host.slot, vdev->host.function, groupid); ++ DPRINTF("%s(%s) group %d\n", __func__, vdev->vbasedev.name, groupid); + + group = vfio_get_group(groupid); + if (!group) { +@@ -4111,16 +4057,14 @@ static void vfio_pci_reset(DeviceState *dev) + PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, dev); + VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); + +- DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain, +- vdev->host.bus, vdev->host.slot, vdev->host.function); ++ DPRINTF("%s(%s)\n", __func__, vdev->vbasedev.name); + + vfio_pci_pre_reset(vdev); + + if (vdev->vbasedev.reset_works && + (vdev->has_flr || !vdev->has_pm_reset) && + !ioctl(vdev->vbasedev.fd, VFIO_DEVICE_RESET)) { +- DPRINTF("%04x:%02x:%02x.%x FLR/VFIO_DEVICE_RESET\n", vdev->host.domain, +- vdev->host.bus, vdev->host.slot, vdev->host.function); ++ DPRINTF("%s FLR/VFIO_DEVICE_RESET\n", vdev->vbasedev.name); + goto post_reset; + } + +@@ -4132,8 +4076,7 @@ static void vfio_pci_reset(DeviceState *dev) + /* If nothing else works and the device supports PM reset, use it */ + if (vdev->vbasedev.reset_works && vdev->has_pm_reset && + !ioctl(vdev->vbasedev.fd, VFIO_DEVICE_RESET)) { +- DPRINTF("%04x:%02x:%02x.%x PCI PM Reset\n", vdev->host.domain, +- vdev->host.bus, vdev->host.slot, vdev->host.function); ++ DPRINTF("%s PCI PM Reset\n", vdev->vbasedev.name); + goto post_reset; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-i386-add-Skylake-Server-cpu-model.patch b/SOURCES/kvm-i386-add-Skylake-Server-cpu-model.patch new file mode 100644 index 0000000..d615304 --- /dev/null +++ b/SOURCES/kvm-i386-add-Skylake-Server-cpu-model.patch @@ -0,0 +1,103 @@ +From 839a96660680e11ad494a02e5b14f64ebd9c8552 Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Tue, 17 Oct 2017 20:36:53 +0200 +Subject: [PATCH 27/27] i386: add Skylake-Server cpu model + +RH-Author: Eduardo Habkost +Message-id: <20171017203653.28578-3-ehabkost@redhat.com> +Patchwork-id: 77351 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 2/2] i386: add Skylake-Server cpu model +Bugzilla: 1501510 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Igor Mammedov +RH-Acked-by: Bandan Das + +From: "Boqun Feng (Intel)" + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1501510 + +Introduce Skylake-Server cpu mode which inherits the features from +Skylake-Client and supports some additional features that are: AVX512, +CLWB and PGPE1GB. + +Backport notes: +* ARAT feature not included, as it is not available in the + qemu-kvm-1.5.3 tree (and disabled by compat code in + pc-i440fx-rhel7.2.0 and older on qemu-kvm-rhev) + +Signed-off-by: Boqun Feng (Intel) +Message-Id: <20170621052935.20715-1-boqun.feng@gmail.com> +[ehabkost: copied comment about XSAVES from Skylake-Client] +Signed-off-by: Eduardo Habkost +(cherry picked from commit 53f9a6f45fb214540cb40af45efc11ac40ac454c) +Signed-off-by: Eduardo Habkost + +Signed-off-by: Miroslav Rezanina +--- + target-i386/cpu.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 50 insertions(+) + +diff --git a/target-i386/cpu.c b/target-i386/cpu.c +index e739647..539d659 100644 +--- a/target-i386/cpu.c ++++ b/target-i386/cpu.c +@@ -1066,6 +1066,56 @@ static x86_def_t builtin_x86_defs[] = { + .model_id = "Intel Core Processor (Skylake)", + }, + { ++ .name = "Skylake-Server", ++ .level = 0xd, ++ .vendor = CPUID_VENDOR_INTEL, ++ .family = 6, ++ .model = 85, ++ .stepping = 4, ++ .features[FEAT_1_EDX] = ++ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | ++ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | ++ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | ++ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | ++ CPUID_DE | CPUID_FP87, ++ .features[FEAT_1_ECX] = ++ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES | ++ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | ++ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | ++ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 | ++ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE | ++ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND, ++ .features[FEAT_8000_0001_EDX] = ++ CPUID_EXT2_LM | CPUID_EXT2_PDPE1GB | CPUID_EXT2_RDTSCP | ++ CPUID_EXT2_NX | CPUID_EXT2_SYSCALL, ++ .features[FEAT_8000_0001_ECX] = ++ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH, ++ .features[FEAT_7_0_EBX] = ++ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | ++ CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | ++ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | ++ CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | ++ CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_CLWB | ++ CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512DQ | ++ CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512CD | ++ CPUID_7_0_EBX_AVX512VL, ++ /* Missing: XSAVES (not supported by some Linux versions, ++ * including v4.1 to v4.12). ++ * KVM doesn't yet expose any XSAVES state save component, ++ * and the only one defined in Skylake (processor tracing) ++ * probably will block migration anyway. ++ */ ++ .features[FEAT_XSAVE] = ++ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | ++ CPUID_XSAVE_XGETBV1, ++ /* Missing: ARAT. not available in the qemu-kvm-1.5.3 tree (and ++ * disabled by compat code in pc-i440fx-rhel7.2.0 and older on ++ * qemu-kvm-rhev) ++ */ ++ .xlevel = 0x80000008, ++ .model_id = "Intel Xeon Processor (Skylake)", ++ }, ++ { + .name = "Opteron_G1", + .level = 5, + .vendor = CPUID_VENDOR_AMD, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-i386-expose-fw_cfg-QEMU0002-in-SSDT.patch b/SOURCES/kvm-i386-expose-fw_cfg-QEMU0002-in-SSDT.patch new file mode 100644 index 0000000..e4d9c73 --- /dev/null +++ b/SOURCES/kvm-i386-expose-fw_cfg-QEMU0002-in-SSDT.patch @@ -0,0 +1,51 @@ +From d7b246e19d4e81f231b3aff6c3885c325be9a9d2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:41 +0100 +Subject: [PATCH 10/41] i386: expose fw_cfg QEMU0002 in SSDT +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-11-marcandre.lureau@redhat.com> +Patchwork-id: 78360 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 10/41] i386: expose fw_cfg QEMU0002 in SSDT +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +RHEL only: This is needed so kernel module can find the device and +load the driver. Upstream qemu uses different API to build ACPI +tables. + +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + hw/i386/ssdt-misc.dsl | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/hw/i386/ssdt-misc.dsl b/hw/i386/ssdt-misc.dsl +index a4484b8..d124c74 100644 +--- a/hw/i386/ssdt-misc.dsl ++++ b/hw/i386/ssdt-misc.dsl +@@ -74,6 +74,16 @@ DefinitionBlock ("ssdt-misc.aml", "SSDT", 0x01, "BXPC", "BXSSDTSUSP", 0x1) + External(\_SB.PCI0, DeviceObj) + External(\_SB.PCI0.ISA, DeviceObj) + ++ Scope(\_SB.PCI0) { ++ Device(FWCF) { ++ Name(_HID, "QEMU0002") ++ Name(_STA, 0x0B) ++ Name(_CRS, ResourceTemplate () { ++ IO(Decode16, 0x0510, 0x0510, 0x01, 0x0C, IO) ++ }) ++ } ++ } ++ + Scope(\_SB.PCI0.ISA) { + Device(PEVT) { + Name(_HID, "QEMU0001") +-- +1.8.3.1 + diff --git a/SOURCES/kvm-i386-update-ssdt-misc.hex.generated.patch b/SOURCES/kvm-i386-update-ssdt-misc.hex.generated.patch new file mode 100644 index 0000000..4d76492 --- /dev/null +++ b/SOURCES/kvm-i386-update-ssdt-misc.hex.generated.patch @@ -0,0 +1,135 @@ +From 7062c4cd0e110af1bbf165db42c11ca2cbb50fc1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Thu, 4 Jan 2018 20:19:02 +0100 +Subject: [PATCH 1/2] i386: update ssdt-misc.hex.generated +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20180104201902.4364-1-marcandre.lureau@redhat.com> +Patchwork-id: 78516 +O-Subject: [RHEL-7.5 qemu-kvm PATCH] i386: update ssdt-misc.hex.generated +Bugzilla: 1411490 +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Igor Mammedov + +RHEL commit d7b246e19d4e81f231b3aff6c3885c325be9a9d2 "i386: expose +fw_cfg QEMU0002 in SSDT" modified ssdt-misc.dsl to export fw_cfg in +ACPI tables. However, the file isn't compiled in RHEL. + +Use known good version acpica-tools-20150619-3.el7.x86_64 to build the +new compiled version. I verified with a RHEL5 guest that #1377087 +isn't happening again after this update. + +RHEL only: This is needed so kernel module can find the device and +load the driver. Upstream qemu uses different API to build ACPI +tables. + +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + hw/i386/ssdt-misc.hex.generated | 68 ++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 64 insertions(+), 4 deletions(-) + +diff --git a/hw/i386/ssdt-misc.hex.generated b/hw/i386/ssdt-misc.hex.generated +index 86c5725..52ad0b7 100644 +--- a/hw/i386/ssdt-misc.hex.generated ++++ b/hw/i386/ssdt-misc.hex.generated +@@ -18,12 +18,12 @@ static unsigned char ssdp_misc_aml[] = { + 0x53, + 0x44, + 0x54, +-0x62, ++0x9e, + 0x1, + 0x0, + 0x0, + 0x1, +-0x80, ++0xbf, + 0x42, + 0x58, + 0x50, +@@ -176,6 +176,66 @@ static unsigned char ssdp_misc_aml[] = { + 0x0, + 0x0, + 0x10, ++0x3b, ++0x5c, ++0x2e, ++0x5f, ++0x53, ++0x42, ++0x5f, ++0x50, ++0x43, ++0x49, ++0x30, ++0x5b, ++0x82, ++0x2e, ++0x46, ++0x57, ++0x43, ++0x46, ++0x8, ++0x5f, ++0x48, ++0x49, ++0x44, ++0xd, ++0x51, ++0x45, ++0x4d, ++0x55, ++0x30, ++0x30, ++0x30, ++0x32, ++0x0, ++0x8, ++0x5f, ++0x53, ++0x54, ++0x41, ++0xa, ++0xb, ++0x8, ++0x5f, ++0x43, ++0x52, ++0x53, ++0x11, ++0xd, ++0xa, ++0xa, ++0x47, ++0x1, ++0x10, ++0x5, ++0x10, ++0x5, ++0x1, ++0xc, ++0x79, ++0x0, ++0x10, + 0x40, + 0xc, + 0x5c, +@@ -369,8 +429,8 @@ static unsigned char ssdp_misc_aml[] = { + 0x4d, + 0x58 + }; +-static unsigned char ssdt_isa_pest[] = { +-0xd0 ++static unsigned short ssdt_isa_pest[] = { ++0x10c + }; + static unsigned char acpi_s4_name[] = { + 0x88 +-- +1.8.3.1 + diff --git a/SOURCES/kvm-i6300esb-Fix-signed-integer-overflow.patch b/SOURCES/kvm-i6300esb-Fix-signed-integer-overflow.patch new file mode 100644 index 0000000..2e048e9 --- /dev/null +++ b/SOURCES/kvm-i6300esb-Fix-signed-integer-overflow.patch @@ -0,0 +1,79 @@ +From 7f476950b0f5780d1112f8e9d0d92ece55ae6912 Mon Sep 17 00:00:00 2001 +From: Richard Jones +Date: Wed, 1 Nov 2017 11:33:00 +0100 +Subject: [PATCH 5/7] i6300esb: Fix signed integer overflow + +RH-Author: Richard Jones +Message-id: <1509535982-27927-2-git-send-email-rjones@redhat.com> +Patchwork-id: 77461 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 1/3] i6300esb: Fix signed integer overflow +Bugzilla: 1470244 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +From: David Gibson + +If the guest programs a sufficiently large timeout value an integer +overflow can occur in i6300esb_restart_timer(). e.g. if the maximum +possible timer preload value of 0xfffff is programmed then we end up with +the calculation: + +timeout = get_ticks_per_sec() * (0xfffff << 15) / 33000000; + +get_ticks_per_sec() returns 1000000000 (10^9) giving: + + 10^9 * (0xfffff * 2^15) == 0x1dcd632329b000000 (65 bits) + +Obviously the division by 33MHz brings it back under 64-bits, but the +overflow has already occurred. + +Since signed integer overflow has undefined behaviour in C, in theory this +could be arbitrarily bad. In practice, the overflowed value wraps around +to something negative, causing the watchdog to immediately expire, killing +the guest, which is still fairly bad. + +The bug can be triggered by running a Linux guest, loading the i6300esb +driver with parameter "heartbeat=2046" and opening /dev/watchdog. The +watchdog will trigger as soon as the device is opened. + +This patch corrects the problem by using muldiv64(), which effectively +allows a 128-bit intermediate value between the multiplication and +division. + +Signed-off-by: David Gibson +Message-Id: <1427075508-12099-3-git-send-email-david@gibson.dropbear.id.au> +Signed-off-by: Paolo Bonzini +(cherry picked from commit 4bc7b4d56657ebf75b986ad46e959cf7232ff26a) + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1470244 +Upstream-status: 4bc7b4d56657ebf75b986ad46e959cf7232ff26a +Signed-off-by: Miroslav Rezanina +--- + hw/watchdog/wdt_i6300esb.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/hw/watchdog/wdt_i6300esb.c b/hw/watchdog/wdt_i6300esb.c +index a2ace52..be35034 100644 +--- a/hw/watchdog/wdt_i6300esb.c ++++ b/hw/watchdog/wdt_i6300esb.c +@@ -125,8 +125,14 @@ static void i6300esb_restart_timer(I6300State *d, int stage) + else + timeout <<= 5; + +- /* Get the timeout in units of ticks_per_sec. */ +- timeout = get_ticks_per_sec() * timeout / 33000000; ++ /* Get the timeout in units of ticks_per_sec. ++ * ++ * ticks_per_sec is typically 10^9 == 0x3B9ACA00 (30 bits), with ++ * 20 bits of user supplied preload, and 15 bits of scale, the ++ * multiply here can exceed 64-bits, before we divide by 33MHz, so ++ * we use a higher-precision intermediate result. ++ */ ++ timeout = muldiv64(get_ticks_per_sec(), timeout, 33000000); + + i6300esb_debug("stage %d, timeout %" PRIi64 "\n", d->stage, timeout); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-i6300esb-fix-timer-overflow.patch b/SOURCES/kvm-i6300esb-fix-timer-overflow.patch new file mode 100644 index 0000000..9503902 --- /dev/null +++ b/SOURCES/kvm-i6300esb-fix-timer-overflow.patch @@ -0,0 +1,63 @@ +From 5918245d224a7a527052ed30af2627187777a282 Mon Sep 17 00:00:00 2001 +From: Richard Jones +Date: Wed, 1 Nov 2017 11:33:01 +0100 +Subject: [PATCH 6/7] i6300esb: fix timer overflow + +RH-Author: Richard Jones +Message-id: <1509535982-27927-3-git-send-email-rjones@redhat.com> +Patchwork-id: 77460 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 2/3] i6300esb: fix timer overflow +Bugzilla: 1470244 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +From: Laurent Vivier + +We use muldiv64() to compute the time to wait: + + timeout = muldiv64(get_ticks_per_sec(), timeout, 33000000); + +but get_ticks_per_sec() is 10^9 (30 bit value) and timeout +is a 35 bit value. + +Whereas muldiv64 is: + + uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) + +So we loose 3 bits of timeout. + +Swapping get_ticks_per_sec() and timeout fixes it. + +We can also replace it by a multiplication by 30 ns, +but this changes PCI clock frequency from 33MHz to 33.333333MHz +and we need to do this on all the QEMU PCI devices (later...) + +Signed-off-by: Laurent Vivier +Reviewed-by: David Gibson +Signed-off-by: Michael Tokarev +(cherry picked from commit fee562e9e41290a22623de83b673a8929ec5280d) + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1470244 +Upstream-status: fee562e9e41290a22623de83b673a8929ec5280d +Signed-off-by: Miroslav Rezanina +--- + hw/watchdog/wdt_i6300esb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/watchdog/wdt_i6300esb.c b/hw/watchdog/wdt_i6300esb.c +index be35034..fa8e3b9 100644 +--- a/hw/watchdog/wdt_i6300esb.c ++++ b/hw/watchdog/wdt_i6300esb.c +@@ -132,7 +132,7 @@ static void i6300esb_restart_timer(I6300State *d, int stage) + * multiply here can exceed 64-bits, before we divide by 33MHz, so + * we use a higher-precision intermediate result. + */ +- timeout = muldiv64(get_ticks_per_sec(), timeout, 33000000); ++ timeout = muldiv64(timeout, get_ticks_per_sec(), 33000000); + + i6300esb_debug("stage %d, timeout %" PRIi64 "\n", d->stage, timeout); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-i6300esb-remove-muldiv64.patch b/SOURCES/kvm-i6300esb-remove-muldiv64.patch new file mode 100644 index 0000000..a512b24 --- /dev/null +++ b/SOURCES/kvm-i6300esb-remove-muldiv64.patch @@ -0,0 +1,78 @@ +From a548a4b5d3a130ada6498669b4bf01bf47fe4560 Mon Sep 17 00:00:00 2001 +From: Richard Jones +Date: Wed, 1 Nov 2017 11:33:02 +0100 +Subject: [PATCH 7/7] i6300esb: remove muldiv64() + +RH-Author: Richard Jones +Message-id: <1509535982-27927-4-git-send-email-rjones@redhat.com> +Patchwork-id: 77463 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 3/3] i6300esb: remove muldiv64() +Bugzilla: 1470244 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +From: Laurent Vivier + +Originally, timers were ticks based, and it made sense to +add ticks to current time to know when to trigger an alarm. + +But since commit: + +7447545 change all other clock references to use nanosecond resolution accessors + +All timers use nanoseconds and we need to convert ticks to nanoseconds, by +doing something like: + + y = muldiv64(x, get_ticks_per_sec(), PCI_FREQUENCY) + +where x is the number of device ticks and y the number of system ticks. + +y is used as nanoseconds in timer functions, +it works because 1 tick is 1 nanosecond. +(get_ticks_per_sec() is 10^9) + +But as PCI frequency is 33 MHz, we can also do: + + y = x * 30; /* 33 MHz PCI period is 30 ns */ + +Which is much more simple. + +This implies a 33.333333 MHz PCI frequency, +but this is correct. + +Signed-off-by: Laurent Vivier +(cherry picked from commit 9491e9bc019a365dfa9780f462984a0d052f4c0d) + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1470244 +Upstream-status: 9491e9bc019a365dfa9780f462984a0d052f4c0d +Signed-off-by: Miroslav Rezanina +--- + hw/watchdog/wdt_i6300esb.c | 11 +++-------- + 1 file changed, 3 insertions(+), 8 deletions(-) + +diff --git a/hw/watchdog/wdt_i6300esb.c b/hw/watchdog/wdt_i6300esb.c +index fa8e3b9..6dede4e 100644 +--- a/hw/watchdog/wdt_i6300esb.c ++++ b/hw/watchdog/wdt_i6300esb.c +@@ -125,14 +125,9 @@ static void i6300esb_restart_timer(I6300State *d, int stage) + else + timeout <<= 5; + +- /* Get the timeout in units of ticks_per_sec. +- * +- * ticks_per_sec is typically 10^9 == 0x3B9ACA00 (30 bits), with +- * 20 bits of user supplied preload, and 15 bits of scale, the +- * multiply here can exceed 64-bits, before we divide by 33MHz, so +- * we use a higher-precision intermediate result. +- */ +- timeout = muldiv64(timeout, get_ticks_per_sec(), 33000000); ++ /* Get the timeout in nanoseconds. */ ++ ++ timeout = timeout * 30; /* on a PCI bus, 1 tick is 30 ns*/ + + i6300esb_debug("stage %d, timeout %" PRIi64 "\n", d->stage, timeout); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-io-skip-updates-to-client-if-websocket-output-buffer.patch b/SOURCES/kvm-io-skip-updates-to-client-if-websocket-output-buffer.patch new file mode 100644 index 0000000..70d4360 --- /dev/null +++ b/SOURCES/kvm-io-skip-updates-to-client-if-websocket-output-buffer.patch @@ -0,0 +1,96 @@ +From 0ee28ebbde0313e54b0c8e0f316aa75f97c87169 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:41 +0100 +Subject: [PATCH 27/27] io: skip updates to client if websocket output buffer + is non-zero + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-28-berrange@redhat.com> +Patchwork-id: 78959 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 27/27] io: skip updates to client if websocket output buffer is non-zero +Bugzilla: 1518711 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +From: "Daniel P. Berrange" + +When getting a framebuffer update from the guest, we first check +to see if there's still any queued data in the VNC send buffer. +If there is, we skip the update so that we avoid having the send +buffer grow without bound. Unfortunately, the code is only +monitoring the normal send buffer, and not the websockets send +buffer which is separate. + +This flaw causes the websockets send buffer to grow without bound +if the other end of the underlying data channel doesn't +read data being sent. This can be seen with VNC if a client +is on a slow WAN link and the guest OS is sending many screen +updates. A malicious VNC client can act like it is on a slow +link by playing a video in the guest and then reading data +very slowly, causing QEMU host memory to expand arbitrarily. + +This issue is assigned CVE-2017-15268, publically reported in + + https://bugs.launchpad.net/qemu/+bug/1718964 + +Reviewed-by: Eric Blake +Signed-off-by: Daniel P. Berrange + +The corresponding upstream fix is present in commit +a7b20a8efa28e5f22c26c06cd06c2f12bc863493, however, this +patch is a complete re-implementation since the upstream +code for websockets is completely different to that in +QEMU 1.5.3. As such ignore the Reviewed-by tag above. + +Signed-off-by: Miroslav Rezanina +--- + ui/vnc-ws.c | 10 ++++++++-- + ui/vnc.c | 3 +++ + 2 files changed, 11 insertions(+), 2 deletions(-) + +diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c +index 7133be9..fbfadde 100644 +--- a/ui/vnc-ws.c ++++ b/ui/vnc-ws.c +@@ -173,8 +173,13 @@ long vnc_client_write_ws(VncState *vs) + long ret; + VNC_DEBUG("Write WS: Pending output %p size %zd offset %zd\n", + vs->output.buffer, vs->output.capacity, vs->output.offset); +- vncws_encode_frame(&vs->ws_output, vs->output.buffer, vs->output.offset); +- buffer_reset(&vs->output); ++ /* We don't consume more from 'output' unless we've finished ++ * sending the previous websockets frame. This ensures that ++ * we still correctly throttle forced framebuffer updates */ ++ if (vs->ws_output.offset == 0) { ++ vncws_encode_frame(&vs->ws_output, vs->output.buffer, vs->output.offset); ++ buffer_reset(&vs->output); ++ } + ret = vnc_client_write_buf(vs, vs->ws_output.buffer, vs->ws_output.offset); + if (!ret) { + return 0; +@@ -183,6 +188,7 @@ long vnc_client_write_ws(VncState *vs) + buffer_advance(&vs->ws_output, ret); + + if (vs->ws_output.offset == 0) { ++ vs->force_update_offset = 0; + qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); + } + +diff --git a/ui/vnc.c b/ui/vnc.c +index 2be87b8..99b1ab1 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -915,6 +915,9 @@ static bool vnc_should_update(VncState *vs) + * is completely idle. + */ + if (vs->output.offset < vs->throttle_output_offset && ++#ifdef CONFIG_VNC_WS ++ vs->ws_output.offset < vs->throttle_output_offset && ++#endif + vs->job_update == VNC_STATE_UPDATE_NONE) { + return true; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-kdump-set-vmcoreinfo-location.patch b/SOURCES/kvm-kdump-set-vmcoreinfo-location.patch new file mode 100644 index 0000000..bb79320 --- /dev/null +++ b/SOURCES/kvm-kdump-set-vmcoreinfo-location.patch @@ -0,0 +1,79 @@ +From 266135a48594041655e0e2e4b647251bc812670c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:39:03 +0100 +Subject: [PATCH 32/41] kdump: set vmcoreinfo location +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-33-marcandre.lureau@redhat.com> +Patchwork-id: 78383 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 32/41] kdump: set vmcoreinfo location +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +kdump header provides offset and size of the vmcoreinfo content, +append it if available (skip the ELF note header). + +crash-7.1.9 was the first version that started looking in the +vmcoreinfo data for phys_base instead of in the kdump_sub_header. + +Signed-off-by: Marc-André Lureau +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin + +(cherry picked from commit 9ada575bbafaf6d3724a7f59df9da89776817cac) +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + dump.c | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +diff --git a/dump.c b/dump.c +index 3bce730..5aeff02 100644 +--- a/dump.c ++++ b/dump.c +@@ -855,6 +855,18 @@ static void create_header32(DumpState *s, Error **errp) + kh->dump_level = cpu_to_dump32(s, DUMP_LEVEL); + + offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size; ++ if (s->guest_note && ++ note_name_equal(s, s->guest_note, "VMCOREINFO")) { ++ uint64_t hsize, name_size, size_vmcoreinfo_desc, offset_vmcoreinfo; ++ ++ get_note_sizes(s, s->guest_note, ++ &hsize, &name_size, &size_vmcoreinfo_desc); ++ offset_vmcoreinfo = offset_note + s->note_size - s->guest_note_size + ++ (DIV_ROUND_UP(hsize, 4) + DIV_ROUND_UP(name_size, 4)) * 4; ++ kh->offset_vmcoreinfo = cpu_to_dump64(s, offset_vmcoreinfo); ++ kh->size_vmcoreinfo = cpu_to_dump32(s, size_vmcoreinfo_desc); ++ } ++ + kh->offset_note = cpu_to_dump64(s, offset_note); + kh->note_size = cpu_to_dump32(s, s->note_size); + +@@ -955,6 +967,18 @@ static void create_header64(DumpState *s, Error **errp) + kh->dump_level = cpu_to_dump32(s, DUMP_LEVEL); + + offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size; ++ if (s->guest_note && ++ note_name_equal(s, s->guest_note, "VMCOREINFO")) { ++ uint64_t hsize, name_size, size_vmcoreinfo_desc, offset_vmcoreinfo; ++ ++ get_note_sizes(s, s->guest_note, ++ &hsize, &name_size, &size_vmcoreinfo_desc); ++ offset_vmcoreinfo = offset_note + s->note_size - s->guest_note_size + ++ (DIV_ROUND_UP(hsize, 4) + DIV_ROUND_UP(name_size, 4)) * 4; ++ kh->offset_vmcoreinfo = cpu_to_dump64(s, offset_vmcoreinfo); ++ kh->size_vmcoreinfo = cpu_to_dump64(s, size_vmcoreinfo_desc); ++ } ++ + kh->offset_note = cpu_to_dump64(s, offset_note); + kh->note_size = cpu_to_dump64(s, s->note_size); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-linux-aio-Fix-laio-resource-leak.patch b/SOURCES/kvm-linux-aio-Fix-laio-resource-leak.patch new file mode 100644 index 0000000..811019c --- /dev/null +++ b/SOURCES/kvm-linux-aio-Fix-laio-resource-leak.patch @@ -0,0 +1,61 @@ +From e5f537a8b3821b68040eada7a964b2dd1b17d3d3 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Tue, 21 Nov 2017 03:21:45 +0100 +Subject: [PATCH 2/9] linux-aio: Fix laio resource leak + +RH-Author: Fam Zheng +Message-id: <20171121032145.5681-3-famz@redhat.com> +Patchwork-id: 77767 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v2 2/2] linux-aio: Fix laio resource leak +Bugzilla: 1491434 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: John Snow +RH-Acked-by: Laurent Vivier + +From: Gonglei + +when hotplug virtio-scsi disks using laio, the aio_nr will +increase in laio_init() by io_setup(), we can see the number by + # cat /proc/sys/fs/aio-nr + 128 +if the aio_nr attach the maxnum, which found from + # cat /proc/sys/fs/aio-max-nr + 65536 +the hotplug process will fail because of aio context leak. + +Fix it by io_destroy in laio_cleanup(). + +Reported-by: daifulai +Signed-off-by: Gonglei +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit a1abf40d6be2fc4b40d90ae3b46442f4a671776b) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina + +Conflicts: + block/linux-aio.c + +Contextual conflict because of the previous patch's necessary deviation +from upstream. +--- + block/linux-aio.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/block/linux-aio.c b/block/linux-aio.c +index 43f14f3..e1d2593 100644 +--- a/block/linux-aio.c ++++ b/block/linux-aio.c +@@ -232,5 +232,10 @@ void laio_cleanup(void *s_) + + qemu_aio_set_fd_handler(s->efd, NULL, NULL, NULL, NULL); + close(s->efd); ++ ++ if (io_destroy(s->ctx) != 0) { ++ fprintf(stderr, "%s: destroy AIO context %p failed\n", ++ __func__, &s->ctx); ++ } + g_free(s); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-main-loop-Acquire-main_context-lock-around-os_host_m.patch b/SOURCES/kvm-main-loop-Acquire-main_context-lock-around-os_host_m.patch new file mode 100644 index 0000000..abfab1c --- /dev/null +++ b/SOURCES/kvm-main-loop-Acquire-main_context-lock-around-os_host_m.patch @@ -0,0 +1,128 @@ +From 6baaf82a7742a1de9160146b08ba0cc86b3d4e79 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Wed, 10 Jan 2018 17:02:21 +0100 +Subject: [PATCH 2/2] main-loop: Acquire main_context lock around + os_host_main_loop_wait. + +RH-Author: Paolo Bonzini +Message-id: <20180110170221.28975-1-pbonzini@redhat.com> +Patchwork-id: 78541 +O-Subject: [RHEL7.5 qemu-kvm PATCH] main-loop: Acquire main_context lock around os_host_main_loop_wait. +Bugzilla: 1473536 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: John Snow +RH-Acked-by: Miroslav Rezanina + +Bugzilla: 1473536 + +Brew build: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=14912977 + +When running virt-rescue the serial console hangs from time to time. +Virt-rescue runs an ordinary Linux kernel "appliance", but there is +only a single idle process running inside, so the qemu main loop is +largely idle. With virt-rescue >= 1.37 you may be able to observe the +hang by doing: + + $ virt-rescue -e ^] --scratch + > while true; do ls -l /usr/bin; done + +The hang in virt-rescue can be resolved by pressing a key on the +serial console. + +Possibly with the same root cause, we also observed hangs during very +early boot of regular Linux VMs with a serial console. Those hangs +are extremely rare, but you may be able to observe them by running +this command on baremetal for a sufficiently long time: + + $ while libguestfs-test-tool -t 60 >& /tmp/log ; do echo -n . ; done + +(Check in /tmp/log that the failure was caused by a hang during early +boot, and not some other reason) + +During investigation of this bug, Paolo Bonzini wrote: + +> glib is expecting QEMU to use g_main_context_acquire around accesses to +> GMainContext. However QEMU is not doing that, instead it is taking its +> own mutex. So we should add g_main_context_acquire and +> g_main_context_release in the two implementations of +> os_host_main_loop_wait; these should undo the effect of Frediano's +> glib patch. + +This patch exactly implements Paolo's suggestion in that paragraph. + +This fixes the serial console hang in my testing, across 3 different +physical machines (AMD, Intel Core i7 and Intel Xeon), over many hours +of automated testing. I wasn't able to reproduce the early boot hangs +(but as noted above, these are extremely rare in any case). + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1435432 +Reported-by: Richard W.M. Jones +Tested-by: Richard W.M. Jones +Signed-off-by: Richard W.M. Jones +Message-Id: <20170331205133.23906-1-rjones@redhat.com> +[Paolo: this is actually a glib bug: recent glib versions are also +expecting g_main_context_acquire around g_poll---but that is not +documented and probably not even intended]. +Signed-off-by: Paolo Bonzini +(cherry picked from commit ecbddbb106114f90008024b4e6c3ba1c38d7ca0e) + +Signed-off-by: Miroslav Rezanina +--- + main-loop.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/main-loop.c b/main-loop.c +index cf36645..a93d37b 100644 +--- a/main-loop.c ++++ b/main-loop.c +@@ -192,9 +192,12 @@ static void glib_pollfds_poll(void) + + static int os_host_main_loop_wait(uint32_t timeout) + { ++ GMainContext *context = g_main_context_default(); + int ret; + static int spin_counter; + ++ g_main_context_acquire(context); ++ + glib_pollfds_fill(&timeout); + + /* If the I/O thread is very busy or we are incorrectly busy waiting in +@@ -230,6 +233,9 @@ static int os_host_main_loop_wait(uint32_t timeout) + } + + glib_pollfds_poll(); ++ ++ g_main_context_release(context); ++ + return ret; + } + #else +@@ -385,12 +391,15 @@ static int os_host_main_loop_wait(uint32_t timeout) + fd_set rfds, wfds, xfds; + int nfds; + ++ g_main_context_acquire(context); ++ + /* XXX: need to suppress polling by better using win32 events */ + ret = 0; + for (pe = first_polling_entry; pe != NULL; pe = pe->next) { + ret |= pe->func(pe->opaque); + } + if (ret != 0) { ++ g_main_context_release(context); + return ret; + } + +@@ -440,6 +449,8 @@ static int os_host_main_loop_wait(uint32_t timeout) + g_main_context_dispatch(context); + } + ++ g_main_context_release(context); ++ + return select_ret || g_poll_ret; + } + #endif +-- +1.8.3.1 + diff --git a/SOURCES/kvm-multiboot-validate-multiboot-header-address-values.patch b/SOURCES/kvm-multiboot-validate-multiboot-header-address-values.patch index 33f5c9b..bfb93f2 100644 --- a/SOURCES/kvm-multiboot-validate-multiboot-header-address-values.patch +++ b/SOURCES/kvm-multiboot-validate-multiboot-header-address-values.patch @@ -1,13 +1,13 @@ -From 65550e3682fd27304c905e4627c3cd9f5840c260 Mon Sep 17 00:00:00 2001 +From abead8461f6c8c50cdc8dedc43e4821a7e1d5e33 Mon Sep 17 00:00:00 2001 From: Bandan Das Date: Thu, 26 Oct 2017 10:03:48 +0200 -Subject: [PATCH] multiboot: validate multiboot header address values +Subject: [PATCH 1/2] multiboot: validate multiboot header address values RH-Author: Bandan Das Message-id: Patchwork-id: 77443 O-Subject: [RHEL-7.5 qemu-kvm PATCH] multiboot: validate multiboot header address values -Bugzilla: 1501120 +Bugzilla: 1501121 RH-Acked-by: Thomas Huth RH-Acked-by: Laurent Vivier RH-Acked-by: Peter Xu diff --git a/SOURCES/kvm-qcow2-Avoid-making-the-L1-table-too-big.patch b/SOURCES/kvm-qcow2-Avoid-making-the-L1-table-too-big.patch new file mode 100644 index 0000000..4f41ea9 --- /dev/null +++ b/SOURCES/kvm-qcow2-Avoid-making-the-L1-table-too-big.patch @@ -0,0 +1,48 @@ +From 0dcf104966d3fc385510a6a2d8b8dd81d731da61 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 27 Nov 2017 18:09:28 +0100 +Subject: [PATCH 9/9] qcow2: Avoid making the L1 table too big + +RH-Author: Max Reitz +Message-id: <20171127180928.10364-3-mreitz@redhat.com> +Patchwork-id: 77918 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 2/2] qcow2: Avoid making the L1 table too big +Bugzilla: 1459725 +RH-Acked-by: John Snow +RH-Acked-by: Fam Zheng +RH-Acked-by: Stefan Hajnoczi + +We refuse to open images whose L1 table we deem "too big". Consequently, +we should not produce such images ourselves. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Max Reitz +Message-id: 20160615153630.2116-3-mreitz@redhat.com +Reviewed-by: Eric Blake +[mreitz: Added QEMU_BUILD_BUG_ON()] +Signed-off-by: Max Reitz +(cherry picked from commit 84c26520d3c1c9ff4a10455748139463278816d5) +Signed-off-by: Max Reitz + +Signed-off-by: Miroslav Rezanina +--- + block/qcow2-cluster.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c +index f7938f6..589b040 100644 +--- a/block/qcow2-cluster.c ++++ b/block/qcow2-cluster.c +@@ -55,7 +55,8 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, + } + } + +- if (new_l1_size > INT_MAX / sizeof(uint64_t)) { ++ QEMU_BUILD_BUG_ON(QCOW_MAX_L1_SIZE > INT_MAX); ++ if (new_l1_size > QCOW_MAX_L1_SIZE / sizeof(uint64_t)) { + return -EFBIG; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qcow2-Prevent-backing-file-names-longer-than-1023.patch b/SOURCES/kvm-qcow2-Prevent-backing-file-names-longer-than-1023.patch new file mode 100644 index 0000000..b9c6e0d --- /dev/null +++ b/SOURCES/kvm-qcow2-Prevent-backing-file-names-longer-than-1023.patch @@ -0,0 +1,46 @@ +From 0a5d705e471c975ca6ca4547cd3a0eb5fa5d3291 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 27 Nov 2017 17:28:39 +0100 +Subject: [PATCH 7/9] qcow2: Prevent backing file names longer than 1023 + +RH-Author: Max Reitz +Message-id: <20171127172839.22264-2-mreitz@redhat.com> +Patchwork-id: 77916 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 1/1] qcow2: Prevent backing file names longer than 1023 +Bugzilla: 1459714 +RH-Acked-by: John Snow +RH-Acked-by: Fam Zheng +RH-Acked-by: Stefan Hajnoczi + +We reject backing file names with a length of more than 1023 characters +when opening a qcow2 file, so we should not produce such files +ourselves. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Max Reitz +Signed-off-by: Kevin Wolf +(cherry picked from commit 4e876bcf2bdb3a7353df92d19bfec0afd1650bc4) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/qcow2.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/block/qcow2.c b/block/qcow2.c +index 61f7e57..dc831ba 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -1497,6 +1497,10 @@ static int qcow2_change_backing_file(BlockDriverState *bs, + { + BDRVQcowState *s = bs->opaque; + ++ if (backing_file && strlen(backing_file) > 1023) { ++ return -EINVAL; ++ } ++ + pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_file ?: ""); + pstrcpy(bs->backing_format, sizeof(bs->backing_format), backing_fmt ?: ""); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qdev-Fix-assert-in-PCI-address-property-when-used-by.patch b/SOURCES/kvm-qdev-Fix-assert-in-PCI-address-property-when-used-by.patch new file mode 100644 index 0000000..b4e426e --- /dev/null +++ b/SOURCES/kvm-qdev-Fix-assert-in-PCI-address-property-when-used-by.patch @@ -0,0 +1,65 @@ +From f8553be3140a1f77ab3c4e218ecc79437534d1ea Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Fri, 26 Jan 2018 02:21:25 +0100 +Subject: [PATCH 1/4] qdev: Fix assert in PCI address property when used by + vfio-pci + +RH-Author: Alex Williamson +Message-id: <20180126021938.25889.98354.stgit@gimli.home> +Patchwork-id: 78707 +O-Subject: [RHEL-7.5 qemu-kvm PATCH] qdev: Fix assert in PCI address property when used by vfio-pci +Bugzilla: 1538866 +RH-Acked-by: Auger Eric +RH-Acked-by: Eduardo Habkost +RH-Acked-by: Laszlo Ersek + +From: Daniel Oram + +Allow the PCIHostDeviceAddress structure to work as the host property +in vfio-pci when it has it's default value of all fields set to ~0. In +this form the property indicates a non-existant device but given the +field bit sizes gets asserted as excess (and invalid) precision +overflows the string buffer. The BDF of an invalid device +"FFFF:FF:FF.F" is returned instead. + +Signed-off-by: Daniel Oram +Reviewed-by: Alex Williamson +Message-Id: <71f06765c4ba16dcd71cbf78e877619948f04ed9.1478777270.git.daniel.oram@gmail.com> +Signed-off-by: Eduardo Habkost +(cherry picked from commit 00b8702581f312aa46f797a8b3153d9b2892d967) +Signed-off-by: Miroslav Rezanina +--- + hw/core/qdev-properties.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c +index dc8ae69..a61250e 100644 +--- a/hw/core/qdev-properties.c ++++ b/hw/core/qdev-properties.c +@@ -728,13 +728,19 @@ static void get_pci_host_devaddr(Object *obj, Visitor *v, void *opaque, + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop); +- char buffer[] = "xxxx:xx:xx.x"; ++ char buffer[] = "ffff:ff:ff.f"; + char *p = buffer; + int rc = 0; + +- rc = snprintf(buffer, sizeof(buffer), "%04x:%02x:%02x.%d", +- addr->domain, addr->bus, addr->slot, addr->function); +- assert(rc == sizeof(buffer) - 1); ++ /* ++ * Catch "invalid" device reference from vfio-pci and allow the ++ * default buffer representing the non-existant device to be used. ++ */ ++ if (~addr->domain || ~addr->bus || ~addr->slot || ~addr->function) { ++ rc = snprintf(buffer, sizeof(buffer), "%04x:%02x:%02x.%0d", ++ addr->domain, addr->bus, addr->slot, addr->function); ++ assert(rc == sizeof(buffer) - 1); ++ } + + visit_type_str(v, &p, name, errp); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-char-add-Czech-characters-to-VNC-keysyms.patch b/SOURCES/kvm-qemu-char-add-Czech-characters-to-VNC-keysyms.patch new file mode 100644 index 0000000..f98fe96 --- /dev/null +++ b/SOURCES/kvm-qemu-char-add-Czech-characters-to-VNC-keysyms.patch @@ -0,0 +1,48 @@ +From 985c196ddbb4c0182df81a5f989c197544f9ff9e Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Tue, 26 Sep 2017 10:57:32 +0200 +Subject: [PATCH 1/4] qemu-char: add Czech characters to VNC keysyms + +RH-Author: Gerd Hoffmann +Message-id: <20170926105734.746-2-kraxel@redhat.com> +Patchwork-id: 76566 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 1/3] qemu-char: add Czech characters to VNC keysyms +Bugzilla: 1476641 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Markus Armbruster +RH-Acked-by: John Snow + +From: Jan Krupa + +This patch adds missing Czech characters to the VNC keysym table. + +Signed-off-by: Jan Krupa +Signed-off-by: Michael Tokarev +(cherry picked from commit 018715f96cc1315df355743a1f807e1b95d2a10f) +Signed-off-by: Miroslav Rezanina +--- + ui/vnc_keysym.h | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/ui/vnc_keysym.h b/ui/vnc_keysym.h +index 6250bec..72c01d1 100644 +--- a/ui/vnc_keysym.h ++++ b/ui/vnc_keysym.h +@@ -224,6 +224,14 @@ static const name2keysym_t name2keysym[]={ + { "odoubleacute", 0x1f5}, + { "udoubleacute", 0x1fb}, + ++/* Czech national characters */ ++{ "ecaron", 0x1ec}, ++{ "scaron", 0x1b9}, ++{ "ccaron", 0x1e8}, ++{ "rcaron", 0x1f8}, ++{ "zcaron", 0x1be}, ++{ "uring", 0x1f9}, ++ + /* modifiers */ + {"ISO_Level3_Shift", 0xfe03}, /* XK_ISO_Level3_Shift */ + {"Control_L", 0xffe3}, /* XK_Control_L */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-char-add-cyrillic-characters-numerosign-to-VNC-.patch b/SOURCES/kvm-qemu-char-add-cyrillic-characters-numerosign-to-VNC-.patch new file mode 100644 index 0000000..2ce3ee2 --- /dev/null +++ b/SOURCES/kvm-qemu-char-add-cyrillic-characters-numerosign-to-VNC-.patch @@ -0,0 +1,46 @@ +From b9b3ebeba33cd6ba59145368550cf6ff771ac6d4 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Tue, 26 Sep 2017 10:57:34 +0200 +Subject: [PATCH 3/4] qemu-char: add cyrillic characters 'numerosign' to VNC + keysyms + +RH-Author: Gerd Hoffmann +Message-id: <20170926105734.746-4-kraxel@redhat.com> +Patchwork-id: 76564 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 3/3] qemu-char: add cyrillic characters 'numerosign' to VNC keysyms +Bugzilla: 1476641 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Markus Armbruster +RH-Acked-by: John Snow + +From: Wang Xin + +This patch adds missing cyrillic character 'numerosign' to the VNC +keysym table, it's needed by Russian keyboard. And I get the keysym from +'', the current keysym table in Qemu was generated from +it. + +Signed-off-by: Wang xin +Signed-off-by: Gonglei +Signed-off-by: Michael Tokarev +(cherry picked from commit 09f4fbe47314c2f13f16bf081997611f7f4251ea) +Signed-off-by: Miroslav Rezanina +--- + ui/vnc_keysym.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/ui/vnc_keysym.h b/ui/vnc_keysym.h +index 1dc039f..7fa2bc1 100644 +--- a/ui/vnc_keysym.h ++++ b/ui/vnc_keysym.h +@@ -404,6 +404,7 @@ static const name2keysym_t name2keysym[]={ + {"breve", 0x01a2}, /* U+02D8 BREVE */ + {"caron", 0x01b7}, /* U+02C7 CARON */ + {"Ccaron", 0x01c8}, /* U+010C LATIN CAPITAL LETTER C WITH CARON */ ++{"numerosign", 0x06b0}, /* U+2116 NUMERO SIGN */ + {"Cyrillic_a", 0x06c1}, /* U+0430 CYRILLIC SMALL LETTER A */ + {"Cyrillic_A", 0x06e1}, /* U+0410 CYRILLIC CAPITAL LETTER A */ + {"Cyrillic_be", 0x06c2}, /* U+0431 CYRILLIC SMALL LETTER BE */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-char-add-missing-characters-used-in-keymaps.patch b/SOURCES/kvm-qemu-char-add-missing-characters-used-in-keymaps.patch new file mode 100644 index 0000000..076404b --- /dev/null +++ b/SOURCES/kvm-qemu-char-add-missing-characters-used-in-keymaps.patch @@ -0,0 +1,421 @@ +From a3ef9d3065990a2d485787367d79c656f21a9649 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Tue, 26 Sep 2017 10:57:33 +0200 +Subject: [PATCH 2/4] qemu-char: add missing characters used in keymaps + +RH-Author: Gerd Hoffmann +Message-id: <20170926105734.746-3-kraxel@redhat.com> +Patchwork-id: 76565 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 2/3] qemu-char: add missing characters used in keymaps +Bugzilla: 1476641 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Markus Armbruster +RH-Acked-by: John Snow + +From: Jan Krupa + +This patch adds all missing characters used in regional keymap +files which already exist in QEMU. I checked for the missing +characters by going through all of the keymaps and matching that +with records in vnc_keysym.h. If the key wasn't found I looked +it up in libxkbcommon library [1]. If I understood it correctly +this is also the same place where most of the keymaps were +exported from according to the comment on the first line in those +files. I was able to find all symbols except "quotebl" used +in Netherland keymap. + +I tested this update with Czech keyboard by myself. I also asked +Matej Serc to test Slovenian keyboard layout - he reported problems +with it few days ago on this mailing list. Both layouts seems +to work fine. I wasn't able to test the remaining layouts but +since this change doesn't modify any existing symbols, just adds +new ones, I don't expect any sideeffects. + +[1] http://cgit.freedesktop.org/xorg/lib/libxkbcommon + +Signed-off-by: Jan Krupa +Signed-off-by: Michael Tokarev +(cherry picked from commit 4c6968c7a03d5e4805dad09aba0491e12b16a596) +Signed-off-by: Miroslav Rezanina +--- + ui/vnc_keysym.h | 365 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 365 insertions(+) + +diff --git a/ui/vnc_keysym.h b/ui/vnc_keysym.h +index 72c01d1..1dc039f 100644 +--- a/ui/vnc_keysym.h ++++ b/ui/vnc_keysym.h +@@ -350,5 +350,370 @@ static const name2keysym_t name2keysym[]={ + {"Katakana_Real", 0xff25}, + {"Eisu_toggle", 0xff30}, + ++{"abovedot", 0x01ff}, /* U+02D9 DOT ABOVE */ ++{"amacron", 0x03e0}, /* U+0101 LATIN SMALL LETTER A WITH MACRON */ ++{"Amacron", 0x03c0}, /* U+0100 LATIN CAPITAL LETTER A WITH MACRON */ ++{"Arabic_ain", 0x05d9}, /* U+0639 ARABIC LETTER AIN */ ++{"Arabic_alef", 0x05c7}, /* U+0627 ARABIC LETTER ALEF */ ++{"Arabic_alefmaksura", 0x05e9}, /* U+0649 ARABIC LETTER ALEF MAKSURA */ ++{"Arabic_beh", 0x05c8}, /* U+0628 ARABIC LETTER BEH */ ++{"Arabic_comma", 0x05ac}, /* U+060C ARABIC COMMA */ ++{"Arabic_dad", 0x05d6}, /* U+0636 ARABIC LETTER DAD */ ++{"Arabic_dal", 0x05cf}, /* U+062F ARABIC LETTER DAL */ ++{"Arabic_damma", 0x05ef}, /* U+064F ARABIC DAMMA */ ++{"Arabic_dammatan", 0x05ec}, /* U+064C ARABIC DAMMATAN */ ++{"Arabic_fatha", 0x05ee}, /* U+064E ARABIC FATHA */ ++{"Arabic_fathatan", 0x05eb}, /* U+064B ARABIC FATHATAN */ ++{"Arabic_feh", 0x05e1}, /* U+0641 ARABIC LETTER FEH */ ++{"Arabic_ghain", 0x05da}, /* U+063A ARABIC LETTER GHAIN */ ++{"Arabic_ha", 0x05e7}, /* U+0647 ARABIC LETTER HEH */ ++{"Arabic_hah", 0x05cd}, /* U+062D ARABIC LETTER HAH */ ++{"Arabic_hamza", 0x05c1}, /* U+0621 ARABIC LETTER HAMZA */ ++{"Arabic_hamzaonalef", 0x05c3}, /* U+0623 ARABIC LETTER ALEF WITH HAMZA ABOVE */ ++{"Arabic_hamzaonwaw", 0x05c4}, /* U+0624 ARABIC LETTER WAW WITH HAMZA ABOVE */ ++{"Arabic_hamzaonyeh", 0x05c6}, /* U+0626 ARABIC LETTER YEH WITH HAMZA ABOVE */ ++{"Arabic_hamzaunderalef", 0x05c5}, /* U+0625 ARABIC LETTER ALEF WITH HAMZA BELOW */ ++{"Arabic_jeem", 0x05cc}, /* U+062C ARABIC LETTER JEEM */ ++{"Arabic_kaf", 0x05e3}, /* U+0643 ARABIC LETTER KAF */ ++{"Arabic_kasra", 0x05f0}, /* U+0650 ARABIC KASRA */ ++{"Arabic_kasratan", 0x05ed}, /* U+064D ARABIC KASRATAN */ ++{"Arabic_khah", 0x05ce}, /* U+062E ARABIC LETTER KHAH */ ++{"Arabic_lam", 0x05e4}, /* U+0644 ARABIC LETTER LAM */ ++{"Arabic_maddaonalef", 0x05c2}, /* U+0622 ARABIC LETTER ALEF WITH MADDA ABOVE */ ++{"Arabic_meem", 0x05e5}, /* U+0645 ARABIC LETTER MEEM */ ++{"Arabic_noon", 0x05e6}, /* U+0646 ARABIC LETTER NOON */ ++{"Arabic_qaf", 0x05e2}, /* U+0642 ARABIC LETTER QAF */ ++{"Arabic_question_mark", 0x05bf}, /* U+061F ARABIC QUESTION MARK */ ++{"Arabic_ra", 0x05d1}, /* U+0631 ARABIC LETTER REH */ ++{"Arabic_sad", 0x05d5}, /* U+0635 ARABIC LETTER SAD */ ++{"Arabic_seen", 0x05d3}, /* U+0633 ARABIC LETTER SEEN */ ++{"Arabic_semicolon", 0x05bb}, /* U+061B ARABIC SEMICOLON */ ++{"Arabic_shadda", 0x05f1}, /* U+0651 ARABIC SHADDA */ ++{"Arabic_sheen", 0x05d4}, /* U+0634 ARABIC LETTER SHEEN */ ++{"Arabic_sukun", 0x05f2}, /* U+0652 ARABIC SUKUN */ ++{"Arabic_tah", 0x05d7}, /* U+0637 ARABIC LETTER TAH */ ++{"Arabic_tatweel", 0x05e0}, /* U+0640 ARABIC TATWEEL */ ++{"Arabic_teh", 0x05ca}, /* U+062A ARABIC LETTER TEH */ ++{"Arabic_tehmarbuta", 0x05c9}, /* U+0629 ARABIC LETTER TEH MARBUTA */ ++{"Arabic_thal", 0x05d0}, /* U+0630 ARABIC LETTER THAL */ ++{"Arabic_theh", 0x05cb}, /* U+062B ARABIC LETTER THEH */ ++{"Arabic_waw", 0x05e8}, /* U+0648 ARABIC LETTER WAW */ ++{"Arabic_yeh", 0x05ea}, /* U+064A ARABIC LETTER YEH */ ++{"Arabic_zah", 0x05d8}, /* U+0638 ARABIC LETTER ZAH */ ++{"Arabic_zain", 0x05d2}, /* U+0632 ARABIC LETTER ZAIN */ ++{"breve", 0x01a2}, /* U+02D8 BREVE */ ++{"caron", 0x01b7}, /* U+02C7 CARON */ ++{"Ccaron", 0x01c8}, /* U+010C LATIN CAPITAL LETTER C WITH CARON */ ++{"Cyrillic_a", 0x06c1}, /* U+0430 CYRILLIC SMALL LETTER A */ ++{"Cyrillic_A", 0x06e1}, /* U+0410 CYRILLIC CAPITAL LETTER A */ ++{"Cyrillic_be", 0x06c2}, /* U+0431 CYRILLIC SMALL LETTER BE */ ++{"Cyrillic_BE", 0x06e2}, /* U+0411 CYRILLIC CAPITAL LETTER BE */ ++{"Cyrillic_che", 0x06de}, /* U+0447 CYRILLIC SMALL LETTER CHE */ ++{"Cyrillic_CHE", 0x06fe}, /* U+0427 CYRILLIC CAPITAL LETTER CHE */ ++{"Cyrillic_de", 0x06c4}, /* U+0434 CYRILLIC SMALL LETTER DE */ ++{"Cyrillic_DE", 0x06e4}, /* U+0414 CYRILLIC CAPITAL LETTER DE */ ++{"Cyrillic_dzhe", 0x06af}, /* U+045F CYRILLIC SMALL LETTER DZHE */ ++{"Cyrillic_DZHE", 0x06bf}, /* U+040F CYRILLIC CAPITAL LETTER DZHE */ ++{"Cyrillic_e", 0x06dc}, /* U+044D CYRILLIC SMALL LETTER E */ ++{"Cyrillic_E", 0x06fc}, /* U+042D CYRILLIC CAPITAL LETTER E */ ++{"Cyrillic_ef", 0x06c6}, /* U+0444 CYRILLIC SMALL LETTER EF */ ++{"Cyrillic_EF", 0x06e6}, /* U+0424 CYRILLIC CAPITAL LETTER EF */ ++{"Cyrillic_el", 0x06cc}, /* U+043B CYRILLIC SMALL LETTER EL */ ++{"Cyrillic_EL", 0x06ec}, /* U+041B CYRILLIC CAPITAL LETTER EL */ ++{"Cyrillic_em", 0x06cd}, /* U+043C CYRILLIC SMALL LETTER EM */ ++{"Cyrillic_EM", 0x06ed}, /* U+041C CYRILLIC CAPITAL LETTER EM */ ++{"Cyrillic_en", 0x06ce}, /* U+043D CYRILLIC SMALL LETTER EN */ ++{"Cyrillic_EN", 0x06ee}, /* U+041D CYRILLIC CAPITAL LETTER EN */ ++{"Cyrillic_er", 0x06d2}, /* U+0440 CYRILLIC SMALL LETTER ER */ ++{"Cyrillic_ER", 0x06f2}, /* U+0420 CYRILLIC CAPITAL LETTER ER */ ++{"Cyrillic_es", 0x06d3}, /* U+0441 CYRILLIC SMALL LETTER ES */ ++{"Cyrillic_ES", 0x06f3}, /* U+0421 CYRILLIC CAPITAL LETTER ES */ ++{"Cyrillic_ghe", 0x06c7}, /* U+0433 CYRILLIC SMALL LETTER GHE */ ++{"Cyrillic_GHE", 0x06e7}, /* U+0413 CYRILLIC CAPITAL LETTER GHE */ ++{"Cyrillic_ha", 0x06c8}, /* U+0445 CYRILLIC SMALL LETTER HA */ ++{"Cyrillic_HA", 0x06e8}, /* U+0425 CYRILLIC CAPITAL LETTER HA */ ++{"Cyrillic_hardsign", 0x06df}, /* U+044A CYRILLIC SMALL LETTER HARD SIGN */ ++{"Cyrillic_HARDSIGN", 0x06ff}, /* U+042A CYRILLIC CAPITAL LETTER HARD SIGN */ ++{"Cyrillic_i", 0x06c9}, /* U+0438 CYRILLIC SMALL LETTER I */ ++{"Cyrillic_I", 0x06e9}, /* U+0418 CYRILLIC CAPITAL LETTER I */ ++{"Cyrillic_ie", 0x06c5}, /* U+0435 CYRILLIC SMALL LETTER IE */ ++{"Cyrillic_IE", 0x06e5}, /* U+0415 CYRILLIC CAPITAL LETTER IE */ ++{"Cyrillic_io", 0x06a3}, /* U+0451 CYRILLIC SMALL LETTER IO */ ++{"Cyrillic_IO", 0x06b3}, /* U+0401 CYRILLIC CAPITAL LETTER IO */ ++{"Cyrillic_je", 0x06a8}, /* U+0458 CYRILLIC SMALL LETTER JE */ ++{"Cyrillic_JE", 0x06b8}, /* U+0408 CYRILLIC CAPITAL LETTER JE */ ++{"Cyrillic_ka", 0x06cb}, /* U+043A CYRILLIC SMALL LETTER KA */ ++{"Cyrillic_KA", 0x06eb}, /* U+041A CYRILLIC CAPITAL LETTER KA */ ++{"Cyrillic_lje", 0x06a9}, /* U+0459 CYRILLIC SMALL LETTER LJE */ ++{"Cyrillic_LJE", 0x06b9}, /* U+0409 CYRILLIC CAPITAL LETTER LJE */ ++{"Cyrillic_nje", 0x06aa}, /* U+045A CYRILLIC SMALL LETTER NJE */ ++{"Cyrillic_NJE", 0x06ba}, /* U+040A CYRILLIC CAPITAL LETTER NJE */ ++{"Cyrillic_o", 0x06cf}, /* U+043E CYRILLIC SMALL LETTER O */ ++{"Cyrillic_O", 0x06ef}, /* U+041E CYRILLIC CAPITAL LETTER O */ ++{"Cyrillic_pe", 0x06d0}, /* U+043F CYRILLIC SMALL LETTER PE */ ++{"Cyrillic_PE", 0x06f0}, /* U+041F CYRILLIC CAPITAL LETTER PE */ ++{"Cyrillic_sha", 0x06db}, /* U+0448 CYRILLIC SMALL LETTER SHA */ ++{"Cyrillic_SHA", 0x06fb}, /* U+0428 CYRILLIC CAPITAL LETTER SHA */ ++{"Cyrillic_shcha", 0x06dd}, /* U+0449 CYRILLIC SMALL LETTER SHCHA */ ++{"Cyrillic_SHCHA", 0x06fd}, /* U+0429 CYRILLIC CAPITAL LETTER SHCHA */ ++{"Cyrillic_shorti", 0x06ca}, /* U+0439 CYRILLIC SMALL LETTER SHORT I */ ++{"Cyrillic_SHORTI", 0x06ea}, /* U+0419 CYRILLIC CAPITAL LETTER SHORT I */ ++{"Cyrillic_softsign", 0x06d8}, /* U+044C CYRILLIC SMALL LETTER SOFT SIGN */ ++{"Cyrillic_SOFTSIGN", 0x06f8}, /* U+042C CYRILLIC CAPITAL LETTER SOFT SIGN */ ++{"Cyrillic_te", 0x06d4}, /* U+0442 CYRILLIC SMALL LETTER TE */ ++{"Cyrillic_TE", 0x06f4}, /* U+0422 CYRILLIC CAPITAL LETTER TE */ ++{"Cyrillic_tse", 0x06c3}, /* U+0446 CYRILLIC SMALL LETTER TSE */ ++{"Cyrillic_TSE", 0x06e3}, /* U+0426 CYRILLIC CAPITAL LETTER TSE */ ++{"Cyrillic_u", 0x06d5}, /* U+0443 CYRILLIC SMALL LETTER U */ ++{"Cyrillic_U", 0x06f5}, /* U+0423 CYRILLIC CAPITAL LETTER U */ ++{"Cyrillic_ve", 0x06d7}, /* U+0432 CYRILLIC SMALL LETTER VE */ ++{"Cyrillic_VE", 0x06f7}, /* U+0412 CYRILLIC CAPITAL LETTER VE */ ++{"Cyrillic_ya", 0x06d1}, /* U+044F CYRILLIC SMALL LETTER YA */ ++{"Cyrillic_YA", 0x06f1}, /* U+042F CYRILLIC CAPITAL LETTER YA */ ++{"Cyrillic_yeru", 0x06d9}, /* U+044B CYRILLIC SMALL LETTER YERU */ ++{"Cyrillic_YERU", 0x06f9}, /* U+042B CYRILLIC CAPITAL LETTER YERU */ ++{"Cyrillic_yu", 0x06c0}, /* U+044E CYRILLIC SMALL LETTER YU */ ++{"Cyrillic_YU", 0x06e0}, /* U+042E CYRILLIC CAPITAL LETTER YU */ ++{"Cyrillic_ze", 0x06da}, /* U+0437 CYRILLIC SMALL LETTER ZE */ ++{"Cyrillic_ZE", 0x06fa}, /* U+0417 CYRILLIC CAPITAL LETTER ZE */ ++{"Cyrillic_zhe", 0x06d6}, /* U+0436 CYRILLIC SMALL LETTER ZHE */ ++{"Cyrillic_ZHE", 0x06f6}, /* U+0416 CYRILLIC CAPITAL LETTER ZHE */ ++{"doubleacute", 0x01bd}, /* U+02DD DOUBLE ACUTE ACCENT */ ++{"doublelowquotemark", 0x0afe}, /* U+201E DOUBLE LOW-9 QUOTATION MARK */ ++{"downarrow", 0x08fe}, /* U+2193 DOWNWARDS ARROW */ ++{"dstroke", 0x01f0}, /* U+0111 LATIN SMALL LETTER D WITH STROKE */ ++{"Dstroke", 0x01d0}, /* U+0110 LATIN CAPITAL LETTER D WITH STROKE */ ++{"eabovedot", 0x03ec}, /* U+0117 LATIN SMALL LETTER E WITH DOT ABOVE */ ++{"Eabovedot", 0x03cc}, /* U+0116 LATIN CAPITAL LETTER E WITH DOT ABOVE */ ++{"emacron", 0x03ba}, /* U+0113 LATIN SMALL LETTER E WITH MACRON */ ++{"Emacron", 0x03aa}, /* U+0112 LATIN CAPITAL LETTER E WITH MACRON */ ++{"endash", 0x0aaa}, /* U+2013 EN DASH */ ++{"eng", 0x03bf}, /* U+014B LATIN SMALL LETTER ENG */ ++{"ENG", 0x03bd}, /* U+014A LATIN CAPITAL LETTER ENG */ ++{"Execute", 0xff62}, /* Execute, run, do */ ++{"F16", 0xffcd}, ++{"F17", 0xffce}, ++{"F18", 0xffcf}, ++{"F19", 0xffd0}, ++{"F20", 0xffd1}, ++{"F21", 0xffd2}, ++{"F22", 0xffd3}, ++{"F23", 0xffd4}, ++{"F24", 0xffd5}, ++{"F25", 0xffd6}, ++{"F26", 0xffd7}, ++{"F27", 0xffd8}, ++{"F28", 0xffd9}, ++{"F29", 0xffda}, ++{"F30", 0xffdb}, ++{"F31", 0xffdc}, ++{"F32", 0xffdd}, ++{"F33", 0xffde}, ++{"F34", 0xffdf}, ++{"F35", 0xffe0}, ++{"fiveeighths", 0x0ac5}, /* U+215D VULGAR FRACTION FIVE EIGHTHS */ ++{"gbreve", 0x02bb}, /* U+011F LATIN SMALL LETTER G WITH BREVE */ ++{"Gbreve", 0x02ab}, /* U+011E LATIN CAPITAL LETTER G WITH BREVE */ ++{"gcedilla", 0x03bb}, /* U+0123 LATIN SMALL LETTER G WITH CEDILLA */ ++{"Gcedilla", 0x03ab}, /* U+0122 LATIN CAPITAL LETTER G WITH CEDILLA */ ++{"Greek_OMEGA", 0x07d9}, /* U+03A9 GREEK CAPITAL LETTER OMEGA */ ++{"Henkan_Mode", 0xff23}, /* Start/Stop Conversion */ ++{"horizconnector", 0x08a3}, /*(U+2500 BOX DRAWINGS LIGHT HORIZONTAL)*/ ++{"hstroke", 0x02b1}, /* U+0127 LATIN SMALL LETTER H WITH STROKE */ ++{"Hstroke", 0x02a1}, /* U+0126 LATIN CAPITAL LETTER H WITH STROKE */ ++{"Iabovedot", 0x02a9}, /* U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE */ ++{"idotless", 0x02b9}, /* U+0131 LATIN SMALL LETTER DOTLESS I */ ++{"imacron", 0x03ef}, /* U+012B LATIN SMALL LETTER I WITH MACRON */ ++{"Imacron", 0x03cf}, /* U+012A LATIN CAPITAL LETTER I WITH MACRON */ ++{"iogonek", 0x03e7}, /* U+012F LATIN SMALL LETTER I WITH OGONEK */ ++{"Iogonek", 0x03c7}, /* U+012E LATIN CAPITAL LETTER I WITH OGONEK */ ++{"ISO_First_Group", 0xfe0c}, ++{"ISO_Last_Group", 0xfe0e}, ++{"ISO_Next_Group", 0xfe08}, ++{"kana_a", 0x04a7}, /* U+30A1 KATAKANA LETTER SMALL A */ ++{"kana_A", 0x04b1}, /* U+30A2 KATAKANA LETTER A */ ++{"kana_CHI", 0x04c1}, /* U+30C1 KATAKANA LETTER TI */ ++{"kana_closingbracket", 0x04a3}, /* U+300D RIGHT CORNER BRACKET */ ++{"kana_comma", 0x04a4}, /* U+3001 IDEOGRAPHIC COMMA */ ++{"kana_conjunctive", 0x04a5}, /* U+30FB KATAKANA MIDDLE DOT */ ++{"kana_e", 0x04aa}, /* U+30A7 KATAKANA LETTER SMALL E */ ++{"kana_E", 0x04b4}, /* U+30A8 KATAKANA LETTER E */ ++{"kana_FU", 0x04cc}, /* U+30D5 KATAKANA LETTER HU */ ++{"kana_fullstop", 0x04a1}, /* U+3002 IDEOGRAPHIC FULL STOP */ ++{"kana_HA", 0x04ca}, /* U+30CF KATAKANA LETTER HA */ ++{"kana_HE", 0x04cd}, /* U+30D8 KATAKANA LETTER HE */ ++{"kana_HI", 0x04cb}, /* U+30D2 KATAKANA LETTER HI */ ++{"kana_HO", 0x04ce}, /* U+30DB KATAKANA LETTER HO */ ++{"kana_i", 0x04a8}, /* U+30A3 KATAKANA LETTER SMALL I */ ++{"kana_I", 0x04b2}, /* U+30A4 KATAKANA LETTER I */ ++{"kana_KA", 0x04b6}, /* U+30AB KATAKANA LETTER KA */ ++{"kana_KE", 0x04b9}, /* U+30B1 KATAKANA LETTER KE */ ++{"kana_KI", 0x04b7}, /* U+30AD KATAKANA LETTER KI */ ++{"kana_KO", 0x04ba}, /* U+30B3 KATAKANA LETTER KO */ ++{"kana_KU", 0x04b8}, /* U+30AF KATAKANA LETTER KU */ ++{"kana_MA", 0x04cf}, /* U+30DE KATAKANA LETTER MA */ ++{"kana_ME", 0x04d2}, /* U+30E1 KATAKANA LETTER ME */ ++{"kana_MI", 0x04d0}, /* U+30DF KATAKANA LETTER MI */ ++{"kana_MO", 0x04d3}, /* U+30E2 KATAKANA LETTER MO */ ++{"kana_MU", 0x04d1}, /* U+30E0 KATAKANA LETTER MU */ ++{"kana_N", 0x04dd}, /* U+30F3 KATAKANA LETTER N */ ++{"kana_NA", 0x04c5}, /* U+30CA KATAKANA LETTER NA */ ++{"kana_NE", 0x04c8}, /* U+30CD KATAKANA LETTER NE */ ++{"kana_NI", 0x04c6}, /* U+30CB KATAKANA LETTER NI */ ++{"kana_NO", 0x04c9}, /* U+30CE KATAKANA LETTER NO */ ++{"kana_NU", 0x04c7}, /* U+30CC KATAKANA LETTER NU */ ++{"kana_o", 0x04ab}, /* U+30A9 KATAKANA LETTER SMALL O */ ++{"kana_O", 0x04b5}, /* U+30AA KATAKANA LETTER O */ ++{"kana_openingbracket", 0x04a2}, /* U+300C LEFT CORNER BRACKET */ ++{"kana_RA", 0x04d7}, /* U+30E9 KATAKANA LETTER RA */ ++{"kana_RE", 0x04da}, /* U+30EC KATAKANA LETTER RE */ ++{"kana_RI", 0x04d8}, /* U+30EA KATAKANA LETTER RI */ ++{"kana_RU", 0x04d9}, /* U+30EB KATAKANA LETTER RU */ ++{"kana_SA", 0x04bb}, /* U+30B5 KATAKANA LETTER SA */ ++{"kana_SE", 0x04be}, /* U+30BB KATAKANA LETTER SE */ ++{"kana_SHI", 0x04bc}, /* U+30B7 KATAKANA LETTER SI */ ++{"kana_SO", 0x04bf}, /* U+30BD KATAKANA LETTER SO */ ++{"kana_SU", 0x04bd}, /* U+30B9 KATAKANA LETTER SU */ ++{"kana_TA", 0x04c0}, /* U+30BF KATAKANA LETTER TA */ ++{"kana_TE", 0x04c3}, /* U+30C6 KATAKANA LETTER TE */ ++{"kana_TO", 0x04c4}, /* U+30C8 KATAKANA LETTER TO */ ++{"kana_tsu", 0x04af}, /* U+30C3 KATAKANA LETTER SMALL TU */ ++{"kana_TSU", 0x04c2}, /* U+30C4 KATAKANA LETTER TU */ ++{"kana_u", 0x04a9}, /* U+30A5 KATAKANA LETTER SMALL U */ ++{"kana_U", 0x04b3}, /* U+30A6 KATAKANA LETTER U */ ++{"kana_WA", 0x04dc}, /* U+30EF KATAKANA LETTER WA */ ++{"kana_WO", 0x04a6}, /* U+30F2 KATAKANA LETTER WO */ ++{"kana_ya", 0x04ac}, /* U+30E3 KATAKANA LETTER SMALL YA */ ++{"kana_YA", 0x04d4}, /* U+30E4 KATAKANA LETTER YA */ ++{"kana_yo", 0x04ae}, /* U+30E7 KATAKANA LETTER SMALL YO */ ++{"kana_YO", 0x04d6}, /* U+30E8 KATAKANA LETTER YO */ ++{"kana_yu", 0x04ad}, /* U+30E5 KATAKANA LETTER SMALL YU */ ++{"kana_YU", 0x04d5}, /* U+30E6 KATAKANA LETTER YU */ ++{"Kanji", 0xff21}, /* Kanji, Kanji convert */ ++{"kcedilla", 0x03f3}, /* U+0137 LATIN SMALL LETTER K WITH CEDILLA */ ++{"Kcedilla", 0x03d3}, /* U+0136 LATIN CAPITAL LETTER K WITH CEDILLA */ ++{"kra", 0x03a2}, /* U+0138 LATIN SMALL LETTER KRA */ ++{"lcedilla", 0x03b6}, /* U+013C LATIN SMALL LETTER L WITH CEDILLA */ ++{"Lcedilla", 0x03a6}, /* U+013B LATIN CAPITAL LETTER L WITH CEDILLA */ ++{"leftarrow", 0x08fb}, /* U+2190 LEFTWARDS ARROW */ ++{"leftdoublequotemark", 0x0ad2}, /* U+201C LEFT DOUBLE QUOTATION MARK */ ++{"Macedonia_dse", 0x06a5}, /* U+0455 CYRILLIC SMALL LETTER DZE */ ++{"Macedonia_DSE", 0x06b5}, /* U+0405 CYRILLIC CAPITAL LETTER DZE */ ++{"Macedonia_gje", 0x06a2}, /* U+0453 CYRILLIC SMALL LETTER GJE */ ++{"Macedonia_GJE", 0x06b2}, /* U+0403 CYRILLIC CAPITAL LETTER GJE */ ++{"Macedonia_kje", 0x06ac}, /* U+045C CYRILLIC SMALL LETTER KJE */ ++{"Macedonia_KJE", 0x06bc}, /* U+040C CYRILLIC CAPITAL LETTER KJE */ ++{"ncedilla", 0x03f1}, /* U+0146 LATIN SMALL LETTER N WITH CEDILLA */ ++{"Ncedilla", 0x03d1}, /* U+0145 LATIN CAPITAL LETTER N WITH CEDILLA */ ++{"oe", 0x13bd}, /* U+0153 LATIN SMALL LIGATURE OE */ ++{"OE", 0x13bc}, /* U+0152 LATIN CAPITAL LIGATURE OE */ ++{"ogonek", 0x01b2}, /* U+02DB OGONEK */ ++{"omacron", 0x03f2}, /* U+014D LATIN SMALL LETTER O WITH MACRON */ ++{"Omacron", 0x03d2}, /* U+014C LATIN CAPITAL LETTER O WITH MACRON */ ++{"oneeighth", 0x0ac3}, /* U+215B VULGAR FRACTION ONE EIGHTH */ ++{"rcedilla", 0x03b3}, /* U+0157 LATIN SMALL LETTER R WITH CEDILLA */ ++{"Rcedilla", 0x03a3}, /* U+0156 LATIN CAPITAL LETTER R WITH CEDILLA */ ++{"rightarrow", 0x08fd}, /* U+2192 RIGHTWARDS ARROW */ ++{"rightdoublequotemark", 0x0ad3}, /* U+201D RIGHT DOUBLE QUOTATION MARK */ ++{"Scaron", 0x01a9}, /* U+0160 LATIN CAPITAL LETTER S WITH CARON */ ++{"scedilla", 0x01ba}, /* U+015F LATIN SMALL LETTER S WITH CEDILLA */ ++{"Scedilla", 0x01aa}, /* U+015E LATIN CAPITAL LETTER S WITH CEDILLA */ ++{"semivoicedsound", 0x04df}, /* U+309C KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ ++{"seveneighths", 0x0ac6}, /* U+215E VULGAR FRACTION SEVEN EIGHTHS */ ++{"Thai_baht", 0x0ddf}, /* U+0E3F THAI CURRENCY SYMBOL BAHT */ ++{"Thai_bobaimai", 0x0dba}, /* U+0E1A THAI CHARACTER BO BAIMAI */ ++{"Thai_chochan", 0x0da8}, /* U+0E08 THAI CHARACTER CHO CHAN */ ++{"Thai_chochang", 0x0daa}, /* U+0E0A THAI CHARACTER CHO CHANG */ ++{"Thai_choching", 0x0da9}, /* U+0E09 THAI CHARACTER CHO CHING */ ++{"Thai_chochoe", 0x0dac}, /* U+0E0C THAI CHARACTER CHO CHOE */ ++{"Thai_dochada", 0x0dae}, /* U+0E0E THAI CHARACTER DO CHADA */ ++{"Thai_dodek", 0x0db4}, /* U+0E14 THAI CHARACTER DO DEK */ ++{"Thai_fofa", 0x0dbd}, /* U+0E1D THAI CHARACTER FO FA */ ++{"Thai_fofan", 0x0dbf}, /* U+0E1F THAI CHARACTER FO FAN */ ++{"Thai_hohip", 0x0dcb}, /* U+0E2B THAI CHARACTER HO HIP */ ++{"Thai_honokhuk", 0x0dce}, /* U+0E2E THAI CHARACTER HO NOKHUK */ ++{"Thai_khokhai", 0x0da2}, /* U+0E02 THAI CHARACTER KHO KHAI */ ++{"Thai_khokhon", 0x0da5}, /* U+0E05 THAI CHARACTER KHO KHON */ ++{"Thai_khokhuat", 0x0da3}, /* U+0E03 THAI CHARACTER KHO KHUAT */ ++{"Thai_khokhwai", 0x0da4}, /* U+0E04 THAI CHARACTER KHO KHWAI */ ++{"Thai_khorakhang", 0x0da6}, /* U+0E06 THAI CHARACTER KHO RAKHANG */ ++{"Thai_kokai", 0x0da1}, /* U+0E01 THAI CHARACTER KO KAI */ ++{"Thai_lakkhangyao", 0x0de5}, /* U+0E45 THAI CHARACTER LAKKHANGYAO */ ++{"Thai_lekchet", 0x0df7}, /* U+0E57 THAI DIGIT SEVEN */ ++{"Thai_lekha", 0x0df5}, /* U+0E55 THAI DIGIT FIVE */ ++{"Thai_lekhok", 0x0df6}, /* U+0E56 THAI DIGIT SIX */ ++{"Thai_lekkao", 0x0df9}, /* U+0E59 THAI DIGIT NINE */ ++{"Thai_leknung", 0x0df1}, /* U+0E51 THAI DIGIT ONE */ ++{"Thai_lekpaet", 0x0df8}, /* U+0E58 THAI DIGIT EIGHT */ ++{"Thai_leksam", 0x0df3}, /* U+0E53 THAI DIGIT THREE */ ++{"Thai_leksi", 0x0df4}, /* U+0E54 THAI DIGIT FOUR */ ++{"Thai_leksong", 0x0df2}, /* U+0E52 THAI DIGIT TWO */ ++{"Thai_leksun", 0x0df0}, /* U+0E50 THAI DIGIT ZERO */ ++{"Thai_lochula", 0x0dcc}, /* U+0E2C THAI CHARACTER LO CHULA */ ++{"Thai_loling", 0x0dc5}, /* U+0E25 THAI CHARACTER LO LING */ ++{"Thai_lu", 0x0dc6}, /* U+0E26 THAI CHARACTER LU */ ++{"Thai_maichattawa", 0x0deb}, /* U+0E4B THAI CHARACTER MAI CHATTAWA */ ++{"Thai_maiek", 0x0de8}, /* U+0E48 THAI CHARACTER MAI EK */ ++{"Thai_maihanakat", 0x0dd1}, /* U+0E31 THAI CHARACTER MAI HAN-AKAT */ ++{"Thai_maitaikhu", 0x0de7}, /* U+0E47 THAI CHARACTER MAITAIKHU */ ++{"Thai_maitho", 0x0de9}, /* U+0E49 THAI CHARACTER MAI THO */ ++{"Thai_maitri", 0x0dea}, /* U+0E4A THAI CHARACTER MAI TRI */ ++{"Thai_maiyamok", 0x0de6}, /* U+0E46 THAI CHARACTER MAIYAMOK */ ++{"Thai_moma", 0x0dc1}, /* U+0E21 THAI CHARACTER MO MA */ ++{"Thai_ngongu", 0x0da7}, /* U+0E07 THAI CHARACTER NGO NGU */ ++{"Thai_nikhahit", 0x0ded}, /* U+0E4D THAI CHARACTER NIKHAHIT */ ++{"Thai_nonen", 0x0db3}, /* U+0E13 THAI CHARACTER NO NEN */ ++{"Thai_nonu", 0x0db9}, /* U+0E19 THAI CHARACTER NO NU */ ++{"Thai_oang", 0x0dcd}, /* U+0E2D THAI CHARACTER O ANG */ ++{"Thai_paiyannoi", 0x0dcf}, /* U+0E2F THAI CHARACTER PAIYANNOI */ ++{"Thai_phinthu", 0x0dda}, /* U+0E3A THAI CHARACTER PHINTHU */ ++{"Thai_phophan", 0x0dbe}, /* U+0E1E THAI CHARACTER PHO PHAN */ ++{"Thai_phophung", 0x0dbc}, /* U+0E1C THAI CHARACTER PHO PHUNG */ ++{"Thai_phosamphao", 0x0dc0}, /* U+0E20 THAI CHARACTER PHO SAMPHAO */ ++{"Thai_popla", 0x0dbb}, /* U+0E1B THAI CHARACTER PO PLA */ ++{"Thai_rorua", 0x0dc3}, /* U+0E23 THAI CHARACTER RO RUA */ ++{"Thai_ru", 0x0dc4}, /* U+0E24 THAI CHARACTER RU */ ++{"Thai_saraa", 0x0dd0}, /* U+0E30 THAI CHARACTER SARA A */ ++{"Thai_saraaa", 0x0dd2}, /* U+0E32 THAI CHARACTER SARA AA */ ++{"Thai_saraae", 0x0de1}, /* U+0E41 THAI CHARACTER SARA AE */ ++{"Thai_saraaimaimalai", 0x0de4}, /* U+0E44 THAI CHARACTER SARA AI MAIMALAI */ ++{"Thai_saraaimaimuan", 0x0de3}, /* U+0E43 THAI CHARACTER SARA AI MAIMUAN */ ++{"Thai_saraam", 0x0dd3}, /* U+0E33 THAI CHARACTER SARA AM */ ++{"Thai_sarae", 0x0de0}, /* U+0E40 THAI CHARACTER SARA E */ ++{"Thai_sarai", 0x0dd4}, /* U+0E34 THAI CHARACTER SARA I */ ++{"Thai_saraii", 0x0dd5}, /* U+0E35 THAI CHARACTER SARA II */ ++{"Thai_sarao", 0x0de2}, /* U+0E42 THAI CHARACTER SARA O */ ++{"Thai_sarau", 0x0dd8}, /* U+0E38 THAI CHARACTER SARA U */ ++{"Thai_saraue", 0x0dd6}, /* U+0E36 THAI CHARACTER SARA UE */ ++{"Thai_sarauee", 0x0dd7}, /* U+0E37 THAI CHARACTER SARA UEE */ ++{"Thai_sarauu", 0x0dd9}, /* U+0E39 THAI CHARACTER SARA UU */ ++{"Thai_sorusi", 0x0dc9}, /* U+0E29 THAI CHARACTER SO RUSI */ ++{"Thai_sosala", 0x0dc8}, /* U+0E28 THAI CHARACTER SO SALA */ ++{"Thai_soso", 0x0dab}, /* U+0E0B THAI CHARACTER SO SO */ ++{"Thai_sosua", 0x0dca}, /* U+0E2A THAI CHARACTER SO SUA */ ++{"Thai_thanthakhat", 0x0dec}, /* U+0E4C THAI CHARACTER THANTHAKHAT */ ++{"Thai_thonangmontho", 0x0db1}, /* U+0E11 THAI CHARACTER THO NANGMONTHO */ ++{"Thai_thophuthao", 0x0db2}, /* U+0E12 THAI CHARACTER THO PHUTHAO */ ++{"Thai_thothahan", 0x0db7}, /* U+0E17 THAI CHARACTER THO THAHAN */ ++{"Thai_thothan", 0x0db0}, /* U+0E10 THAI CHARACTER THO THAN */ ++{"Thai_thothong", 0x0db8}, /* U+0E18 THAI CHARACTER THO THONG */ ++{"Thai_thothung", 0x0db6}, /* U+0E16 THAI CHARACTER THO THUNG */ ++{"Thai_topatak", 0x0daf}, /* U+0E0F THAI CHARACTER TO PATAK */ ++{"Thai_totao", 0x0db5}, /* U+0E15 THAI CHARACTER TO TAO */ ++{"Thai_wowaen", 0x0dc7}, /* U+0E27 THAI CHARACTER WO WAEN */ ++{"Thai_yoyak", 0x0dc2}, /* U+0E22 THAI CHARACTER YO YAK */ ++{"Thai_yoying", 0x0dad}, /* U+0E0D THAI CHARACTER YO YING */ ++{"threeeighths", 0x0ac4}, /* U+215C VULGAR FRACTION THREE EIGHTHS */ ++{"trademark", 0x0ac9}, /* U+2122 TRADE MARK SIGN */ ++{"tslash", 0x03bc}, /* U+0167 LATIN SMALL LETTER T WITH STROKE */ ++{"Tslash", 0x03ac}, /* U+0166 LATIN CAPITAL LETTER T WITH STROKE */ ++{"umacron", 0x03fe}, /* U+016B LATIN SMALL LETTER U WITH MACRON */ ++{"Umacron", 0x03de}, /* U+016A LATIN CAPITAL LETTER U WITH MACRON */ ++{"uogonek", 0x03f9}, /* U+0173 LATIN SMALL LETTER U WITH OGONEK */ ++{"Uogonek", 0x03d9}, /* U+0172 LATIN CAPITAL LETTER U WITH OGONEK */ ++{"uparrow", 0x08fc}, /* U+2191 UPWARDS ARROW */ ++{"voicedsound", 0x04de}, /* U+309B KATAKANA-HIRAGANA VOICED SOUND MARK */ ++{"Zcaron", 0x01ae}, /* U+017D LATIN CAPITAL LETTER Z WITH CARON */ ++ + {NULL,0}, + }; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-img-Use-strerror-for-generic-resize-error.patch b/SOURCES/kvm-qemu-img-Use-strerror-for-generic-resize-error.patch new file mode 100644 index 0000000..ae46d46 --- /dev/null +++ b/SOURCES/kvm-qemu-img-Use-strerror-for-generic-resize-error.patch @@ -0,0 +1,44 @@ +From 42138bf0821350fa4ebad59775fb1c73f514478b Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 27 Nov 2017 18:09:27 +0100 +Subject: [PATCH 8/9] qemu-img: Use strerror() for generic resize error + +RH-Author: Max Reitz +Message-id: <20171127180928.10364-2-mreitz@redhat.com> +Patchwork-id: 77917 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 1/2] qemu-img: Use strerror() for generic resize error +Bugzilla: 1459725 +RH-Acked-by: John Snow +RH-Acked-by: Fam Zheng +RH-Acked-by: Stefan Hajnoczi + +Emitting the plain error number is not very helpful. Use strerror() +instead. + +Signed-off-by: Max Reitz +Message-id: 20160615153630.2116-2-mreitz@redhat.com +Reviewed-by: Eric Blake +Signed-off-by: Max Reitz +(cherry picked from commit bcf23482ae00e040dbef46c44ff914bf788a0937) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + qemu-img.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/qemu-img.c b/qemu-img.c +index eb2d4cb..efbe16d 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -2645,7 +2645,7 @@ static int img_resize(int argc, char **argv) + error_report("Image is read-only"); + break; + default: +- error_report("Error resizing image (%d)", -ret); ++ error_report("Error resizing image: %s", strerror(-ret)); + break; + } + out: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-nbd-Ignore-SIGPIPE.patch b/SOURCES/kvm-qemu-nbd-Ignore-SIGPIPE.patch index 346de1f..3715bd2 100644 --- a/SOURCES/kvm-qemu-nbd-Ignore-SIGPIPE.patch +++ b/SOURCES/kvm-qemu-nbd-Ignore-SIGPIPE.patch @@ -1,4 +1,4 @@ -From bf7e8348d0594026abf9b17356a935b31bf07274 Mon Sep 17 00:00:00 2001 +From 18c4fbe13ce03654f763f6569bb740c57109555c Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 10 Jul 2017 17:52:18 +0200 Subject: [PATCH] qemu-nbd: Ignore SIGPIPE @@ -7,7 +7,7 @@ RH-Author: Eric Blake Message-id: <20170710175218.13682-1-eblake@redhat.com> Patchwork-id: 75718 O-Subject: [RHEL-7.4.z qemu-kvm PATCH] qemu-nbd: Ignore SIGPIPE -Bugzilla: 1468107 +Bugzilla: 1466463 RH-Acked-by: John Snow RH-Acked-by: Stefan Hajnoczi RH-Acked-by: Paolo Bonzini diff --git a/SOURCES/kvm-qemu-option-reject-empty-number-value.patch b/SOURCES/kvm-qemu-option-reject-empty-number-value.patch new file mode 100644 index 0000000..09bea06 --- /dev/null +++ b/SOURCES/kvm-qemu-option-reject-empty-number-value.patch @@ -0,0 +1,53 @@ +From 8fde4e2c8a03832087c7e006e35988245f55c57b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Fri, 3 Nov 2017 18:06:12 +0100 +Subject: [PATCH 2/2] qemu-option: reject empty number value +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171103180612.24523-1-marcandre.lureau@redhat.com> +Patchwork-id: 77500 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v2] qemu-option: reject empty number value +Bugzilla: 1417864 +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Laurent Vivier +RH-Acked-by: Laszlo Ersek + +(Upstream commit to fix this bug is +3403e5eb884f3a74c40fe7cccc103f848c040215, however, the patch relies on +qemu_strtou64() which was introduced later and had several iterations) + +Signed-off-by: Marc-André Lureau +--- +v2: +- add errno check (Laszlo Ersek) + +util/qemu-option.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +Signed-off-by: Miroslav Rezanina +--- + util/qemu-option.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/util/qemu-option.c b/util/qemu-option.c +index 4de5d13..5a85abd 100644 +--- a/util/qemu-option.c ++++ b/util/qemu-option.c +@@ -162,8 +162,9 @@ static void parse_option_number(const char *name, const char *value, + uint64_t number; + + if (value != NULL) { ++ errno = 0; + number = strtoull(value, &postfix, 0); +- if (*postfix != '\0') { ++ if (errno != 0 || *postfix != '\0' || postfix == value) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name, "a number"); + return; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qxl-add-migration-blocker-to-avoid-pre-save-assert.patch b/SOURCES/kvm-qxl-add-migration-blocker-to-avoid-pre-save-assert.patch new file mode 100644 index 0000000..4b16f21 --- /dev/null +++ b/SOURCES/kvm-qxl-add-migration-blocker-to-avoid-pre-save-assert.patch @@ -0,0 +1,99 @@ +From f84d8a785cd2309325476ae5e6a60170dac7c75a Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Tue, 23 Jan 2018 18:09:33 +0100 +Subject: [PATCH 3/3] qxl: add migration blocker to avoid pre-save assert +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Dr. David Alan Gilbert +Message-id: <20180123180933.26008-2-dgilbert@redhat.com> +Patchwork-id: 78698 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 1/1] qxl: add migration blocker to avoid pre-save assert +Bugzilla: 1536883 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Laurent Vivier +RH-Acked-by: Miroslav Rezanina + +From: Gerd Hoffmann + +Cc: 1635339@bugs.launchpad.net +Signed-off-by: Gerd Hoffmann +Reviewed-by: Marc-André Lureau +Message-id: 20170410113131.2585-1-kraxel@redhat.com +(cherry picked from commit 86dbcdd9c7590d06db89ca256c5eaf0b4aba8858) + dgilbert: Fixup change in migrate_add_blocker parameters + +Signed-off-by: Miroslav Rezanina +--- + hw/display/qxl.c | 27 +++++++++++++++++++++++++++ + hw/display/qxl.h | 1 + + 2 files changed, 28 insertions(+) + +diff --git a/hw/display/qxl.c b/hw/display/qxl.c +index 0a755df..0625a76 100644 +--- a/hw/display/qxl.c ++++ b/hw/display/qxl.c +@@ -26,6 +26,7 @@ + #include "qemu/atomic.h" + #include "monitor/monitor.h" + #include "sysemu/sysemu.h" ++#include "migration/migration.h" + #include "trace.h" + + #include "qxl.h" +@@ -637,6 +638,26 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) + qxl->guest_primary.commands++; + qxl_track_command(qxl, ext); + qxl_log_command(qxl, "cmd", ext); ++ { ++ /* ++ * Windows 8 drivers place qxl commands in the vram ++ * (instead of the ram) bar. We can't live migrate such a ++ * guest, so add a migration blocker in case we detect ++ * this, to avoid triggering the assert in pre_save(). ++ * ++ * https://cgit.freedesktop.org/spice/win32/qxl-wddm-dod/commit/?id=f6e099db39e7d0787f294d5fd0dce328b5210faa ++ */ ++ void *msg = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); ++ if (msg != NULL && ( ++ msg < (void *)qxl->vga.vram_ptr || ++ msg > ((void *)qxl->vga.vram_ptr + qxl->vga.vram_size))) { ++ if (!qxl->migration_blocker) { ++ error_setg(&qxl->migration_blocker, ++ "qxl: guest bug: command not in ram bar"); ++ migrate_add_blocker(qxl->migration_blocker); ++ } ++ } ++ } + trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode)); + return true; + default: +@@ -1215,6 +1236,12 @@ static void qxl_hard_reset(PCIQXLDevice *d, int loadvm) + qemu_spice_create_host_memslot(&d->ssd); + qxl_soft_reset(d); + ++ if (d->migration_blocker) { ++ migrate_del_blocker(d->migration_blocker); ++ error_free(d->migration_blocker); ++ d->migration_blocker = NULL; ++ } ++ + if (startstop) { + qemu_spice_display_start(); + } +diff --git a/hw/display/qxl.h b/hw/display/qxl.h +index f3f51e2..11cf2aa 100644 +--- a/hw/display/qxl.h ++++ b/hw/display/qxl.h +@@ -36,6 +36,7 @@ typedef struct PCIQXLDevice { + uint32_t cmdlog; + + uint32_t guest_bug; ++ Error *migration_blocker; + + enum qxl_mode mode; + uint32_t cmdflags; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-savevm-Improve-error-message-for-blocked-migration.patch b/SOURCES/kvm-savevm-Improve-error-message-for-blocked-migration.patch new file mode 100644 index 0000000..9a4ac3d --- /dev/null +++ b/SOURCES/kvm-savevm-Improve-error-message-for-blocked-migration.patch @@ -0,0 +1,101 @@ +From 88b94264928e180cad4067a55cb328fe594985b9 Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Fri, 26 Jan 2018 18:53:14 +0100 +Subject: [PATCH 3/4] savevm: Improve error message for blocked migration + +RH-Author: Dr. David Alan Gilbert +Message-id: <20180126185315.2342-2-dgilbert@redhat.com> +Patchwork-id: 78730 +O-Subject: [RHEL7.5 qemu-kvm PATCH 1/2] savevm: Improve error message for blocked migration +Bugzilla: 1536883 +RH-Acked-by: Peter Xu +RH-Acked-by: Kevin Wolf +RH-Acked-by: Miroslav Rezanina + +From: Kevin Wolf + +If an internal snapshot can't be saved because migration is blocked +(most commonly probably because of AHCI), we had a really bad error +message: + +$ echo -e "savevm foo\nquit" | qemu -M q35 /tmp/test.qcow2 -monitor stdio +QEMU 2.2.50 monitor - type 'help' for more information +(qemu) savevm foo +Error -22 while writing VM +(qemu) quit + +This patch converts qemu_savevm_state() to the Error infrastructure so +that a useful error pointing to the problematic device is produced now: + +$ echo -e "savevm foo\nquit" | qemu -M q35 /tmp/test.qcow2 -monitor stdio +QEMU 2.2.50 monitor - type 'help' for more information +(qemu) savevm foo +State blocked by non-migratable device '0000:00:1f.2/ich9_ahci' +(qemu) quit + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Message-id: 1423574702-23072-1-git-send-email-kwolf@redhat.com +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 5d80448c3fc566e505adfa2b566ec8074442c8e1) +Signed-off-by: Miroslav Rezanina +--- + savevm.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/savevm.c b/savevm.c +index 731d5c0..d34004e 100644 +--- a/savevm.c ++++ b/savevm.c +@@ -2199,7 +2199,7 @@ void qemu_savevm_state_cancel(void) + } + } + +-static int qemu_savevm_state(QEMUFile *f) ++static int qemu_savevm_state(QEMUFile *f, Error **errp) + { + int ret; + MigrationParams params = { +@@ -2207,7 +2207,7 @@ static int qemu_savevm_state(QEMUFile *f) + .shared = 0 + }; + +- if (qemu_savevm_state_blocked(NULL)) { ++ if (qemu_savevm_state_blocked(errp)) { + return -EINVAL; + } + +@@ -2228,6 +2228,7 @@ static int qemu_savevm_state(QEMUFile *f) + } + if (ret != 0) { + qemu_savevm_state_cancel(); ++ error_setg_errno(errp, -ret, "Error while writing VM state"); + } + return ret; + } +@@ -2603,6 +2604,7 @@ void do_savevm(Monitor *mon, const QDict *qdict) + qemu_timeval tv; + struct tm tm; + const char *name = qdict_get_try_str(qdict, "name"); ++ Error *local_err = NULL; + + /* Verify if there is a device that doesn't support snapshots and is writable */ + bs = NULL; +@@ -2661,11 +2663,12 @@ void do_savevm(Monitor *mon, const QDict *qdict) + monitor_printf(mon, "Could not open VM state file\n"); + goto the_end; + } +- ret = qemu_savevm_state(f); ++ ret = qemu_savevm_state(f, &local_err); + vm_state_size = qemu_ftell(f); + qemu_fclose(f); + if (ret < 0) { +- monitor_printf(mon, "Error %d while writing VM\n", ret); ++ monitor_printf(mon, "%s\n", error_get_pretty(local_err)); ++ error_free(local_err); + goto the_end; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-savevm-fail-if-migration-blockers-are-present.patch b/SOURCES/kvm-savevm-fail-if-migration-blockers-are-present.patch new file mode 100644 index 0000000..62adbba --- /dev/null +++ b/SOURCES/kvm-savevm-fail-if-migration-blockers-are-present.patch @@ -0,0 +1,117 @@ +From 51568d18bbfef1adce26d8cd33f3f4a4c12b1e78 Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Fri, 26 Jan 2018 18:53:15 +0100 +Subject: [PATCH 4/4] savevm: fail if migration blockers are present + +RH-Author: Dr. David Alan Gilbert +Message-id: <20180126185315.2342-3-dgilbert@redhat.com> +Patchwork-id: 78732 +O-Subject: [RHEL7.5 qemu-kvm PATCH 2/2] savevm: fail if migration blockers are present +Bugzilla: 1536883 +RH-Acked-by: Peter Xu +RH-Acked-by: Kevin Wolf +RH-Acked-by: Miroslav Rezanina + +From: Greg Kurz + +QEMU has currently two ways to prevent migration to occur: +- migration blocker when it depends on runtime state +- VMStateDescription.unmigratable when migration is not supported at all + +This patch gathers all the logic into a single function to be called from +both the savevm and the migrate paths. + +This fixes a bug with 9p, at least, where savevm would succeed and the +following would happen in the guest after loadvm: + +$ ls /host +ls: cannot access /host: Protocol error + +With this patch: + +(qemu) savevm foo +Migration is disabled when VirtFS export path '/' is mounted in the guest +using mount_tag 'host' + +Signed-off-by: Greg Kurz +Reviewed-by: Paolo Bonzini +Message-Id: <146239057139.11271.9011797645454781543.stgit@bahia.huguette.org> +[Update subject according to Paolo's suggestion - Amit] +(cherry picked from commit 24f3902b088cd4f2dbebfd90527b5d81d6a050e9) + dgilbert: Manual merge + +Signed-off-by: Amit Shah +Signed-off-by: Miroslav Rezanina +--- + include/migration/migration.h | 1 + + migration.c | 21 +++++++++++++++------ + savevm.c | 2 +- + 3 files changed, 17 insertions(+), 7 deletions(-) + +diff --git a/include/migration/migration.h b/include/migration/migration.h +index c99a67c..0760984 100644 +--- a/include/migration/migration.h ++++ b/include/migration/migration.h +@@ -90,6 +90,7 @@ int migrate_fd_close(MigrationState *s); + + void add_migration_state_change_notifier(Notifier *notify); + void remove_migration_state_change_notifier(Notifier *notify); ++bool migration_is_blocked(Error **errp); + bool migration_in_setup(MigrationState *); + bool migration_has_finished(MigrationState *); + bool migration_has_failed(MigrationState *); +diff --git a/migration.c b/migration.c +index e8c5939..5591601 100644 +--- a/migration.c ++++ b/migration.c +@@ -417,6 +417,20 @@ void migrate_del_blocker(Error *reason) + migration_blockers = g_slist_remove(migration_blockers, reason); + } + ++bool migration_is_blocked(Error **errp) ++{ ++ if (qemu_savevm_state_blocked(errp)) { ++ return true; ++ } ++ ++ if (migration_blockers) { ++ *errp = error_copy(migration_blockers->data); ++ return true; ++ } ++ ++ return false; ++} ++ + void qmp_migrate(const char *uri, bool has_blk, bool blk, + bool has_inc, bool inc, bool has_detach, bool detach, + Error **errp) +@@ -447,12 +461,7 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk, + return; + } + +- if (qemu_savevm_state_blocked(errp)) { +- return; +- } +- +- if (migration_blockers) { +- *errp = error_copy(migration_blockers->data); ++ if (migration_is_blocked(errp)) { + return; + } + +diff --git a/savevm.c b/savevm.c +index d34004e..0216df2 100644 +--- a/savevm.c ++++ b/savevm.c +@@ -2207,7 +2207,7 @@ static int qemu_savevm_state(QEMUFile *f, Error **errp) + .shared = 0 + }; + +- if (qemu_savevm_state_blocked(errp)) { ++ if (migration_is_blocked(errp)) { + return -EINVAL; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-scripts-dump-guest-memory.py-Cleanup-functions.patch b/SOURCES/kvm-scripts-dump-guest-memory.py-Cleanup-functions.patch new file mode 100644 index 0000000..9bb1025 --- /dev/null +++ b/SOURCES/kvm-scripts-dump-guest-memory.py-Cleanup-functions.patch @@ -0,0 +1,201 @@ +From e40871f4bf8ca981075eb7baa5a8ff0f3f8f4a67 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:39:07 +0100 +Subject: [PATCH 36/41] scripts/dump-guest-memory.py: Cleanup functions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-37-marcandre.lureau@redhat.com> +Patchwork-id: 78387 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 36/41] scripts/dump-guest-memory.py: Cleanup functions +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: Janosch Frank + +Increase readability by adding newlines and comments, as well as +removing wrong whitespaces and C style braces around conditionals and +loops. + +Reviewed-by: Laszlo Ersek +Signed-off-by: Janosch Frank +Message-Id: <1453464520-3882-5-git-send-email-frankja@linux.vnet.ibm.com> +Signed-off-by: Paolo Bonzini + +(cherry picked from commit 6782c0e785a0ba48cd96d99f2402cb87af027d26) + +RHEL: conflicts due to qtailq usage + +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + scripts/dump-guest-memory.py | 69 +++++++++++++++++++++++++++++--------------- + 1 file changed, 46 insertions(+), 23 deletions(-) + +diff --git a/scripts/dump-guest-memory.py b/scripts/dump-guest-memory.py +index d44de99..3d54d05 100644 +--- a/scripts/dump-guest-memory.py ++++ b/scripts/dump-guest-memory.py +@@ -69,35 +69,58 @@ ELF64_PHDR = ("I" # p_type + ) + + def int128_get64(val): +- assert (val["hi"] == 0) ++ """Returns low 64bit part of Int128 struct.""" ++ ++ assert val["hi"] == 0 + return val["lo"] + + def qtailq_foreach(head, field_str): ++ """Generator for qtails.""" ++ + var_p = head["tqh_first"] + while (var_p != 0): + var = var_p.dereference() +- yield var + var_p = var[field_str]["tqe_next"] ++ yield var + + def qemu_get_ram_block(ram_addr): ++ """Returns the RAMBlock struct to which the given address belongs.""" ++ + ram_blocks = gdb.parse_and_eval("ram_list.blocks") ++ + for block in qtailq_foreach(ram_blocks, "next"): + if (ram_addr - block["offset"] < block["length"]): + return block ++ + raise gdb.GdbError("Bad ram offset %x" % ram_addr) + ++ + def qemu_get_ram_ptr(ram_addr): ++ """Returns qemu vaddr for given guest physical address.""" ++ + block = qemu_get_ram_block(ram_addr) + return block["host"] + (ram_addr - block["offset"]) + +-def memory_region_get_ram_ptr(mr): +- if (mr["alias"] != 0): +- return (memory_region_get_ram_ptr(mr["alias"].dereference()) + +- mr["alias_offset"]) +- return qemu_get_ram_ptr(mr["ram_addr"] & TARGET_PAGE_MASK) ++ ++def memory_region_get_ram_ptr(memory_region): ++ if memory_region["alias"] != 0: ++ return (memory_region_get_ram_ptr(memory_region["alias"].dereference()) ++ + memory_region["alias_offset"]) ++ ++ return qemu_get_ram_ptr(memory_region["ram_addr"] & TARGET_PAGE_MASK) ++ + + def get_guest_phys_blocks(): ++ """Returns a list of ram blocks. ++ ++ Each block entry contains: ++ 'target_start': guest block phys start address ++ 'target_end': guest block phys end address ++ 'host_addr': qemu vaddr of the block's start ++ """ ++ + guest_phys_blocks = [] ++ + print("guest RAM blocks:") + print("target_start target_end host_addr message " + "count") +@@ -111,29 +134,29 @@ def get_guest_phys_blocks(): + # compatibility. Otherwise range doesn't cast the value itself and + # breaks. + for cur in range(int(current_map["nr"])): +- flat_range = (current_map["ranges"] + cur).dereference() +- mr = flat_range["mr"].dereference() ++ flat_range = (current_map["ranges"] + cur).dereference() ++ memory_region = flat_range["mr"].dereference() + + # we only care about RAM +- if (not mr["ram"]): ++ if not memory_region["ram"]: + continue + + section_size = int128_get64(flat_range["addr"]["size"]) + target_start = int128_get64(flat_range["addr"]["start"]) +- target_end = target_start + section_size +- host_addr = (memory_region_get_ram_ptr(mr) + +- flat_range["offset_in_region"]) ++ target_end = target_start + section_size ++ host_addr = (memory_region_get_ram_ptr(memory_region) ++ + flat_range["offset_in_region"]) + predecessor = None + + # find continuity in guest physical address space +- if (len(guest_phys_blocks) > 0): ++ if len(guest_phys_blocks) > 0: + predecessor = guest_phys_blocks[-1] + predecessor_size = (predecessor["target_end"] - + predecessor["target_start"]) + + # the memory API guarantees monotonically increasing + # traversal +- assert (predecessor["target_end"] <= target_start) ++ assert predecessor["target_end"] <= target_start + + # we want continuity in both guest-physical and + # host-virtual memory +@@ -141,11 +164,11 @@ def get_guest_phys_blocks(): + predecessor["host_addr"] + predecessor_size != host_addr): + predecessor = None + +- if (predecessor is None): ++ if predecessor is None: + # isolated mapping, add it to the list + guest_phys_blocks.append({"target_start": target_start, +- "target_end" : target_end, +- "host_addr" : host_addr}) ++ "target_end": target_end, ++ "host_addr": host_addr}) + message = "added" + else: + # expand predecessor until @target_end; predecessor's +@@ -282,7 +305,7 @@ shape and this command should mostly work.""" + # We should never reach PN_XNUM for paging=false dumps: there's + # just a handful of discontiguous ranges after merging. + self.phdr_num += len(self.guest_phys_blocks) +- assert (self.phdr_num < PN_XNUM) ++ assert self.phdr_num < PN_XNUM + + # Calculate the ELF file offset where the memory dump commences: + # +@@ -313,15 +336,15 @@ shape and this command should mostly work.""" + def dump_iterate(self, vmcore): + qemu_core = gdb.inferiors()[0] + for block in self.guest_phys_blocks: +- cur = block["host_addr"] ++ cur = block["host_addr"] + left = block["target_end"] - block["target_start"] + print("dumping range at %016x for length %016x" % + (cur.cast(UINTPTR_T), left)) +- while (left > 0): ++ while left > 0: + chunk_size = min(TARGET_PAGE_SIZE, left) + chunk = qemu_core.read_memory(cur, chunk_size) + vmcore.write(chunk) +- cur += chunk_size ++ cur += chunk_size + left -= chunk_size + + def create_vmcore(self, filename): +@@ -336,7 +359,7 @@ shape and this command should mostly work.""" + self.dont_repeat() + + argv = gdb.string_to_argv(args) +- if (len(argv) != 1): ++ if len(argv) != 1: + raise gdb.GdbError("usage: dump-guest-memory FILE") + + self.dump_init() +-- +1.8.3.1 + diff --git a/SOURCES/kvm-scripts-dump-guest-memory.py-Improve-python-3-compat.patch b/SOURCES/kvm-scripts-dump-guest-memory.py-Improve-python-3-compat.patch new file mode 100644 index 0000000..e8a2ab9 --- /dev/null +++ b/SOURCES/kvm-scripts-dump-guest-memory.py-Improve-python-3-compat.patch @@ -0,0 +1,98 @@ +From 58efb548d48964d4ff7bdcebdb97ec10e708e5ed Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:39:06 +0100 +Subject: [PATCH 35/41] scripts/dump-guest-memory.py: Improve python 3 + compatibility +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-36-marcandre.lureau@redhat.com> +Patchwork-id: 78385 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 35/41] scripts/dump-guest-memory.py: Improve python 3 compatibility +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: Janosch Frank + +This commit does not make the script python 3 compatible, it is a +preparation that fixes the easy and common incompatibilities. + +Print is a function in python 3 and therefore needs braces around its +arguments. + +Range does not cast a gdb.Value object to int in python 3, we have to +do it ourselves. + +Reviewed-by: Laszlo Ersek +Signed-off-by: Janosch Frank +Message-Id: <1453464520-3882-4-git-send-email-frankja@linux.vnet.ibm.com> +Signed-off-by: Paolo Bonzini + +(cherry picked from commit 7cb1089d5fbd7b2d9497f111ce948edef41df32d) +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + scripts/dump-guest-memory.py | 26 +++++++++++++++----------- + 1 file changed, 15 insertions(+), 11 deletions(-) + +diff --git a/scripts/dump-guest-memory.py b/scripts/dump-guest-memory.py +index 7d93d86..d44de99 100644 +--- a/scripts/dump-guest-memory.py ++++ b/scripts/dump-guest-memory.py +@@ -98,15 +98,19 @@ def memory_region_get_ram_ptr(mr): + + def get_guest_phys_blocks(): + guest_phys_blocks = [] +- print "guest RAM blocks:" +- print ("target_start target_end host_addr message " +- "count") +- print ("---------------- ---------------- ---------------- ------- " +- "-----") ++ print("guest RAM blocks:") ++ print("target_start target_end host_addr message " ++ "count") ++ print("---------------- ---------------- ---------------- ------- " ++ "-----") + + current_map_p = gdb.parse_and_eval("address_space_memory.current_map") + current_map = current_map_p.dereference() +- for cur in range(current_map["nr"]): ++ ++ # Conversion to int is needed for python 3 ++ # compatibility. Otherwise range doesn't cast the value itself and ++ # breaks. ++ for cur in range(int(current_map["nr"])): + flat_range = (current_map["ranges"] + cur).dereference() + mr = flat_range["mr"].dereference() + +@@ -149,9 +153,9 @@ def get_guest_phys_blocks(): + predecessor["target_end"] = target_end + message = "joined" + +- print ("%016x %016x %016x %-7s %5u" % +- (target_start, target_end, host_addr.cast(UINTPTR_T), +- message, len(guest_phys_blocks))) ++ print("%016x %016x %016x %-7s %5u" % ++ (target_start, target_end, host_addr.cast(UINTPTR_T), ++ message, len(guest_phys_blocks))) + + return guest_phys_blocks + +@@ -311,8 +315,8 @@ shape and this command should mostly work.""" + for block in self.guest_phys_blocks: + cur = block["host_addr"] + left = block["target_end"] - block["target_start"] +- print ("dumping range at %016x for length %016x" % +- (cur.cast(UINTPTR_T), left)) ++ print("dumping range at %016x for length %016x" % ++ (cur.cast(UINTPTR_T), left)) + while (left > 0): + chunk_size = min(TARGET_PAGE_SIZE, left) + chunk = qemu_core.read_memory(cur, chunk_size) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-scripts-dump-guest-memory.py-Introduce-multi-arch-su.patch b/SOURCES/kvm-scripts-dump-guest-memory.py-Introduce-multi-arch-su.patch new file mode 100644 index 0000000..18055c3 --- /dev/null +++ b/SOURCES/kvm-scripts-dump-guest-memory.py-Introduce-multi-arch-su.patch @@ -0,0 +1,612 @@ +From 0867b6efa038add3ce58fcec50b27cad8718d43a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:39:08 +0100 +Subject: [PATCH 37/41] scripts/dump-guest-memory.py: Introduce multi-arch + support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-38-marcandre.lureau@redhat.com> +Patchwork-id: 78386 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 37/41] scripts/dump-guest-memory.py: Introduce multi-arch support +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: Janosch Frank + +By modelling the ELF with ctypes we not only gain full python 3 +support but can also create dumps for different architectures more easily. + +Tested-by: Andrew Jones +Acked-by: Laszlo Ersek +Signed-off-by: Janosch Frank +Message-Id: <1453464520-3882-6-git-send-email-frankja@linux.vnet.ibm.com> +Signed-off-by: Paolo Bonzini + +(cherry picked from commit 368e3adc8928b2786939a25a336527f83f18e926) + +RHEL: Change it to be x86-64 only, to keep compatibility and limit the + feature exposure. + + Backport it because ctypes have various benefits simplifying the + following patch. + +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + scripts/dump-guest-memory.py | 488 ++++++++++++++++++++++++++++--------------- + 1 file changed, 323 insertions(+), 165 deletions(-) + +diff --git a/scripts/dump-guest-memory.py b/scripts/dump-guest-memory.py +index 3d54d05..308cfca 100644 +--- a/scripts/dump-guest-memory.py ++++ b/scripts/dump-guest-memory.py +@@ -6,6 +6,7 @@ + # + # Authors: + # Laszlo Ersek ++# Janosch Frank + # + # This work is licensed under the terms of the GNU GPL, version 2 or later. See + # the COPYING file in the top-level directory. +@@ -15,58 +16,303 @@ + # "help data" summary), and it should match how other help texts look in + # gdb. + +-import struct ++import ctypes + + UINTPTR_T = gdb.lookup_type("uintptr_t") + + TARGET_PAGE_SIZE = 0x1000 + TARGET_PAGE_MASK = 0xFFFFFFFFFFFFF000 + +-# Various ELF constants +-EM_X86_64 = 62 # AMD x86-64 target machine +-ELFDATA2LSB = 1 # little endian +-ELFCLASS64 = 2 +-ELFMAG = "\x7FELF" +-EV_CURRENT = 1 +-ET_CORE = 4 +-PT_LOAD = 1 +-PT_NOTE = 4 +- + # Special value for e_phnum. This indicates that the real number of + # program headers is too large to fit into e_phnum. Instead the real + # value is in the field sh_info of section 0. + PN_XNUM = 0xFFFF + +-# Format strings for packing and header size calculation. +-ELF64_EHDR = ("4s" # e_ident/magic +- "B" # e_ident/class +- "B" # e_ident/data +- "B" # e_ident/version +- "B" # e_ident/osabi +- "8s" # e_ident/pad +- "H" # e_type +- "H" # e_machine +- "I" # e_version +- "Q" # e_entry +- "Q" # e_phoff +- "Q" # e_shoff +- "I" # e_flags +- "H" # e_ehsize +- "H" # e_phentsize +- "H" # e_phnum +- "H" # e_shentsize +- "H" # e_shnum +- "H" # e_shstrndx +- ) +-ELF64_PHDR = ("I" # p_type +- "I" # p_flags +- "Q" # p_offset +- "Q" # p_vaddr +- "Q" # p_paddr +- "Q" # p_filesz +- "Q" # p_memsz +- "Q" # p_align +- ) ++EV_CURRENT = 1 ++ ++ELFCLASS32 = 1 ++ELFCLASS64 = 2 ++ ++ELFDATA2LSB = 1 ++ELFDATA2MSB = 2 ++ ++ET_CORE = 4 ++ ++PT_LOAD = 1 ++PT_NOTE = 4 ++ ++EM_386 = 3 ++EM_PPC = 20 ++EM_PPC64 = 21 ++EM_S390 = 22 ++EM_AARCH = 183 ++EM_X86_64 = 62 ++ ++class ELF(object): ++ """Representation of a ELF file.""" ++ ++ def __init__(self, arch): ++ self.ehdr = None ++ self.notes = [] ++ self.segments = [] ++ self.notes_size = 0 ++ self.endianess = None ++ self.elfclass = ELFCLASS64 ++ ++ if arch == 'aarch64-le': ++ self.endianess = ELFDATA2LSB ++ self.elfclass = ELFCLASS64 ++ self.ehdr = get_arch_ehdr(self.endianess, self.elfclass) ++ self.ehdr.e_machine = EM_AARCH ++ ++ elif arch == 'aarch64-be': ++ self.endianess = ELFDATA2MSB ++ self.ehdr = get_arch_ehdr(self.endianess, self.elfclass) ++ self.ehdr.e_machine = EM_AARCH ++ ++ elif arch == 'X86_64': ++ self.endianess = ELFDATA2LSB ++ self.ehdr = get_arch_ehdr(self.endianess, self.elfclass) ++ self.ehdr.e_machine = EM_X86_64 ++ ++ elif arch == '386': ++ self.endianess = ELFDATA2LSB ++ self.elfclass = ELFCLASS32 ++ self.ehdr = get_arch_ehdr(self.endianess, self.elfclass) ++ self.ehdr.e_machine = EM_386 ++ ++ elif arch == 's390': ++ self.endianess = ELFDATA2MSB ++ self.ehdr = get_arch_ehdr(self.endianess, self.elfclass) ++ self.ehdr.e_machine = EM_S390 ++ ++ elif arch == 'ppc64-le': ++ self.endianess = ELFDATA2LSB ++ self.ehdr = get_arch_ehdr(self.endianess, self.elfclass) ++ self.ehdr.e_machine = EM_PPC64 ++ ++ elif arch == 'ppc64-be': ++ self.endianess = ELFDATA2MSB ++ self.ehdr = get_arch_ehdr(self.endianess, self.elfclass) ++ self.ehdr.e_machine = EM_PPC64 ++ ++ else: ++ raise gdb.GdbError("No valid arch type specified.\n" ++ "Currently supported types:\n" ++ "aarch64-be, aarch64-le, X86_64, 386, s390, " ++ "ppc64-be, ppc64-le") ++ ++ self.add_segment(PT_NOTE, 0, 0) ++ ++ def add_note(self, n_name, n_desc, n_type): ++ """Adds a note to the ELF.""" ++ ++ note = get_arch_note(self.endianess, len(n_name), len(n_desc)) ++ note.n_namesz = len(n_name) + 1 ++ note.n_descsz = len(n_desc) ++ note.n_name = n_name.encode() ++ note.n_type = n_type ++ ++ # Desc needs to be 4 byte aligned (although the 64bit spec ++ # specifies 8 byte). When defining n_desc as uint32 it will be ++ # automatically aligned but we need the memmove to copy the ++ # string into it. ++ ctypes.memmove(note.n_desc, n_desc.encode(), len(n_desc)) ++ ++ self.notes.append(note) ++ self.segments[0].p_filesz += ctypes.sizeof(note) ++ self.segments[0].p_memsz += ctypes.sizeof(note) ++ ++ def add_segment(self, p_type, p_paddr, p_size): ++ """Adds a segment to the elf.""" ++ ++ phdr = get_arch_phdr(self.endianess, self.elfclass) ++ phdr.p_type = p_type ++ phdr.p_paddr = p_paddr ++ phdr.p_filesz = p_size ++ phdr.p_memsz = p_size ++ self.segments.append(phdr) ++ self.ehdr.e_phnum += 1 ++ ++ def to_file(self, elf_file): ++ """Writes all ELF structures to the the passed file. ++ ++ Structure: ++ Ehdr ++ Segment 0:PT_NOTE ++ Segment 1:PT_LOAD ++ Segment N:PT_LOAD ++ Note 0..N ++ Dump contents ++ """ ++ elf_file.write(self.ehdr) ++ off = ctypes.sizeof(self.ehdr) + \ ++ len(self.segments) * ctypes.sizeof(self.segments[0]) ++ ++ for phdr in self.segments: ++ phdr.p_offset = off ++ elf_file.write(phdr) ++ off += phdr.p_filesz ++ ++ for note in self.notes: ++ elf_file.write(note) ++ ++ ++def get_arch_note(endianess, len_name, len_desc): ++ """Returns a Note class with the specified endianess.""" ++ ++ if endianess == ELFDATA2LSB: ++ superclass = ctypes.LittleEndianStructure ++ else: ++ superclass = ctypes.BigEndianStructure ++ ++ len_name = len_name + 1 ++ ++ class Note(superclass): ++ """Represents an ELF note, includes the content.""" ++ ++ _fields_ = [("n_namesz", ctypes.c_uint32), ++ ("n_descsz", ctypes.c_uint32), ++ ("n_type", ctypes.c_uint32), ++ ("n_name", ctypes.c_char * len_name), ++ ("n_desc", ctypes.c_uint32 * ((len_desc + 3) // 4))] ++ return Note() ++ ++ ++class Ident(ctypes.Structure): ++ """Represents the ELF ident array in the ehdr structure.""" ++ ++ _fields_ = [('ei_mag0', ctypes.c_ubyte), ++ ('ei_mag1', ctypes.c_ubyte), ++ ('ei_mag2', ctypes.c_ubyte), ++ ('ei_mag3', ctypes.c_ubyte), ++ ('ei_class', ctypes.c_ubyte), ++ ('ei_data', ctypes.c_ubyte), ++ ('ei_version', ctypes.c_ubyte), ++ ('ei_osabi', ctypes.c_ubyte), ++ ('ei_abiversion', ctypes.c_ubyte), ++ ('ei_pad', ctypes.c_ubyte * 7)] ++ ++ def __init__(self, endianess, elfclass): ++ self.ei_mag0 = 0x7F ++ self.ei_mag1 = ord('E') ++ self.ei_mag2 = ord('L') ++ self.ei_mag3 = ord('F') ++ self.ei_class = elfclass ++ self.ei_data = endianess ++ self.ei_version = EV_CURRENT ++ ++ ++def get_arch_ehdr(endianess, elfclass): ++ """Returns a EHDR64 class with the specified endianess.""" ++ ++ if endianess == ELFDATA2LSB: ++ superclass = ctypes.LittleEndianStructure ++ else: ++ superclass = ctypes.BigEndianStructure ++ ++ class EHDR64(superclass): ++ """Represents the 64 bit ELF header struct.""" ++ ++ _fields_ = [('e_ident', Ident), ++ ('e_type', ctypes.c_uint16), ++ ('e_machine', ctypes.c_uint16), ++ ('e_version', ctypes.c_uint32), ++ ('e_entry', ctypes.c_uint64), ++ ('e_phoff', ctypes.c_uint64), ++ ('e_shoff', ctypes.c_uint64), ++ ('e_flags', ctypes.c_uint32), ++ ('e_ehsize', ctypes.c_uint16), ++ ('e_phentsize', ctypes.c_uint16), ++ ('e_phnum', ctypes.c_uint16), ++ ('e_shentsize', ctypes.c_uint16), ++ ('e_shnum', ctypes.c_uint16), ++ ('e_shstrndx', ctypes.c_uint16)] ++ ++ def __init__(self): ++ super(superclass, self).__init__() ++ self.e_ident = Ident(endianess, elfclass) ++ self.e_type = ET_CORE ++ self.e_version = EV_CURRENT ++ self.e_ehsize = ctypes.sizeof(self) ++ self.e_phoff = ctypes.sizeof(self) ++ self.e_phentsize = ctypes.sizeof(get_arch_phdr(endianess, elfclass)) ++ self.e_phnum = 0 ++ ++ ++ class EHDR32(superclass): ++ """Represents the 32 bit ELF header struct.""" ++ ++ _fields_ = [('e_ident', Ident), ++ ('e_type', ctypes.c_uint16), ++ ('e_machine', ctypes.c_uint16), ++ ('e_version', ctypes.c_uint32), ++ ('e_entry', ctypes.c_uint32), ++ ('e_phoff', ctypes.c_uint32), ++ ('e_shoff', ctypes.c_uint32), ++ ('e_flags', ctypes.c_uint32), ++ ('e_ehsize', ctypes.c_uint16), ++ ('e_phentsize', ctypes.c_uint16), ++ ('e_phnum', ctypes.c_uint16), ++ ('e_shentsize', ctypes.c_uint16), ++ ('e_shnum', ctypes.c_uint16), ++ ('e_shstrndx', ctypes.c_uint16)] ++ ++ def __init__(self): ++ super(superclass, self).__init__() ++ self.e_ident = Ident(endianess, elfclass) ++ self.e_type = ET_CORE ++ self.e_version = EV_CURRENT ++ self.e_ehsize = ctypes.sizeof(self) ++ self.e_phoff = ctypes.sizeof(self) ++ self.e_phentsize = ctypes.sizeof(get_arch_phdr(endianess, elfclass)) ++ self.e_phnum = 0 ++ ++ # End get_arch_ehdr ++ if elfclass == ELFCLASS64: ++ return EHDR64() ++ else: ++ return EHDR32() ++ ++ ++def get_arch_phdr(endianess, elfclass): ++ """Returns a 32 or 64 bit PHDR class with the specified endianess.""" ++ ++ if endianess == ELFDATA2LSB: ++ superclass = ctypes.LittleEndianStructure ++ else: ++ superclass = ctypes.BigEndianStructure ++ ++ class PHDR64(superclass): ++ """Represents the 64 bit ELF program header struct.""" ++ ++ _fields_ = [('p_type', ctypes.c_uint32), ++ ('p_flags', ctypes.c_uint32), ++ ('p_offset', ctypes.c_uint64), ++ ('p_vaddr', ctypes.c_uint64), ++ ('p_paddr', ctypes.c_uint64), ++ ('p_filesz', ctypes.c_uint64), ++ ('p_memsz', ctypes.c_uint64), ++ ('p_align', ctypes.c_uint64)] ++ ++ class PHDR32(superclass): ++ """Represents the 32 bit ELF program header struct.""" ++ ++ _fields_ = [('p_type', ctypes.c_uint32), ++ ('p_offset', ctypes.c_uint32), ++ ('p_vaddr', ctypes.c_uint32), ++ ('p_paddr', ctypes.c_uint32), ++ ('p_filesz', ctypes.c_uint32), ++ ('p_memsz', ctypes.c_uint32), ++ ('p_flags', ctypes.c_uint32), ++ ('p_align', ctypes.c_uint32)] ++ ++ # End get_arch_phdr ++ if elfclass == ELFCLASS64: ++ return PHDR64() ++ else: ++ return PHDR32() ++ + + def int128_get64(val): + """Returns low 64bit part of Int128 struct.""" +@@ -186,20 +432,22 @@ def get_guest_phys_blocks(): + class DumpGuestMemory(gdb.Command): + """Extract guest vmcore from qemu process coredump. + +-The sole argument is FILE, identifying the target file to write the +-guest vmcore to. ++The two required arguments are FILE and ARCH: ++FILE identifies the target file to write the guest vmcore to. ++ARCH specifies the architecture for which the core will be generated. + + This GDB command reimplements the dump-guest-memory QMP command in + python, using the representation of guest memory as captured in the qemu + coredump. The qemu process that has been dumped must have had the +-command line option "-machine dump-guest-core=on". ++command line option "-machine dump-guest-core=on" which is the default. + + For simplicity, the "paging", "begin" and "end" parameters of the QMP + command are not supported -- no attempt is made to get the guest's + internal paging structures (ie. paging=false is hard-wired), and guest + memory is always fully dumped. + +-Only x86_64 guests are supported. ++Currently aarch64-be, aarch64-le, X86_64, 386, s390, ppc64-be, ++ppc64-le guests are supported. + + The CORE/NT_PRSTATUS and QEMU notes (that is, the VCPUs' statuses) are + not written to the vmcore. Preparing these would require context that is +@@ -217,129 +465,39 @@ shape and this command should mostly work.""" + super(DumpGuestMemory, self).__init__("dump-guest-memory", + gdb.COMMAND_DATA, + gdb.COMPLETE_FILENAME) +- self.elf64_ehdr_le = struct.Struct("<%s" % ELF64_EHDR) +- self.elf64_phdr_le = struct.Struct("<%s" % ELF64_PHDR) ++ self.elf = None + self.guest_phys_blocks = None + +- def cpu_get_dump_info(self): +- # We can't synchronize the registers with KVM post-mortem, and +- # the bits in (first_x86_cpu->env.hflags) seem to be stale; they +- # may not reflect long mode for example. Hence just assume the +- # most common values. This also means that instruction pointer +- # etc. will be bogus in the dump, but at least the RAM contents +- # should be valid. +- self.dump_info = {"d_machine": EM_X86_64, +- "d_endian" : ELFDATA2LSB, +- "d_class" : ELFCLASS64} +- +- def encode_elf64_ehdr_le(self): +- return self.elf64_ehdr_le.pack( +- ELFMAG, # e_ident/magic +- self.dump_info["d_class"], # e_ident/class +- self.dump_info["d_endian"], # e_ident/data +- EV_CURRENT, # e_ident/version +- 0, # e_ident/osabi +- "", # e_ident/pad +- ET_CORE, # e_type +- self.dump_info["d_machine"], # e_machine +- EV_CURRENT, # e_version +- 0, # e_entry +- self.elf64_ehdr_le.size, # e_phoff +- 0, # e_shoff +- 0, # e_flags +- self.elf64_ehdr_le.size, # e_ehsize +- self.elf64_phdr_le.size, # e_phentsize +- self.phdr_num, # e_phnum +- 0, # e_shentsize +- 0, # e_shnum +- 0 # e_shstrndx +- ) +- +- def encode_elf64_note_le(self): +- return self.elf64_phdr_le.pack(PT_NOTE, # p_type +- 0, # p_flags +- (self.memory_offset - +- len(self.note)), # p_offset +- 0, # p_vaddr +- 0, # p_paddr +- len(self.note), # p_filesz +- len(self.note), # p_memsz +- 0 # p_align +- ) +- +- def encode_elf64_load_le(self, offset, start_hwaddr, range_size): +- return self.elf64_phdr_le.pack(PT_LOAD, # p_type +- 0, # p_flags +- offset, # p_offset +- 0, # p_vaddr +- start_hwaddr, # p_paddr +- range_size, # p_filesz +- range_size, # p_memsz +- 0 # p_align +- ) +- +- def note_init(self, name, desc, type): +- # name must include a trailing NUL +- namesz = (len(name) + 1 + 3) / 4 * 4 +- descsz = (len(desc) + 3) / 4 * 4 +- fmt = ("<" # little endian +- "I" # n_namesz +- "I" # n_descsz +- "I" # n_type +- "%us" # name +- "%us" # desc +- % (namesz, descsz)) +- self.note = struct.pack(fmt, +- len(name) + 1, len(desc), type, name, desc) +- +- def dump_init(self): +- self.guest_phys_blocks = get_guest_phys_blocks() +- self.cpu_get_dump_info() +- # we have no way to retrieve the VCPU status from KVM +- # post-mortem +- self.note_init("NONE", "EMPTY", 0) +- +- # Account for PT_NOTE. +- self.phdr_num = 1 +- +- # We should never reach PN_XNUM for paging=false dumps: there's +- # just a handful of discontiguous ranges after merging. +- self.phdr_num += len(self.guest_phys_blocks) +- assert self.phdr_num < PN_XNUM +- +- # Calculate the ELF file offset where the memory dump commences: +- # +- # ELF header +- # PT_NOTE +- # PT_LOAD: 1 +- # PT_LOAD: 2 +- # ... +- # PT_LOAD: len(self.guest_phys_blocks) +- # ELF note +- # memory dump +- self.memory_offset = (self.elf64_ehdr_le.size + +- self.elf64_phdr_le.size * self.phdr_num + +- len(self.note)) +- +- def dump_begin(self, vmcore): +- vmcore.write(self.encode_elf64_ehdr_le()) +- vmcore.write(self.encode_elf64_note_le()) +- running = self.memory_offset ++ def dump_init(self, vmcore): ++ """Prepares and writes ELF structures to core file.""" ++ ++ # Needed to make crash happy, data for more useful notes is ++ # not available in a qemu core. ++ self.elf.add_note("NONE", "EMPTY", 0) ++ ++ # We should never reach PN_XNUM for paging=false dumps, ++ # there's just a handful of discontiguous ranges after ++ # merging. ++ # The constant is needed to account for the PT_NOTE segment. ++ phdr_num = len(self.guest_phys_blocks) + 1 ++ assert phdr_num < PN_XNUM ++ + for block in self.guest_phys_blocks: +- range_size = block["target_end"] - block["target_start"] +- vmcore.write(self.encode_elf64_load_le(running, +- block["target_start"], +- range_size)) +- running += range_size +- vmcore.write(self.note) ++ block_size = block["target_end"] - block["target_start"] ++ self.elf.add_segment(PT_LOAD, block["target_start"], block_size) ++ ++ self.elf.to_file(vmcore) + + def dump_iterate(self, vmcore): ++ """Writes guest core to file.""" ++ + qemu_core = gdb.inferiors()[0] + for block in self.guest_phys_blocks: + cur = block["host_addr"] + left = block["target_end"] - block["target_start"] + print("dumping range at %016x for length %016x" % + (cur.cast(UINTPTR_T), left)) ++ + while left > 0: + chunk_size = min(TARGET_PAGE_SIZE, left) + chunk = qemu_core.read_memory(cur, chunk_size) +@@ -347,13 +505,9 @@ shape and this command should mostly work.""" + cur += chunk_size + left -= chunk_size + +- def create_vmcore(self, filename): +- vmcore = open(filename, "wb") +- self.dump_begin(vmcore) +- self.dump_iterate(vmcore) +- vmcore.close() +- + def invoke(self, args, from_tty): ++ """Handles command invocation from gdb.""" ++ + # Unwittingly pressing the Enter key after the command should + # not dump the same multi-gig coredump to the same file. + self.dont_repeat() +@@ -362,7 +516,11 @@ shape and this command should mostly work.""" + if len(argv) != 1: + raise gdb.GdbError("usage: dump-guest-memory FILE") + +- self.dump_init() +- self.create_vmcore(argv[0]) ++ self.elf = ELF("X86_64") ++ self.guest_phys_blocks = get_guest_phys_blocks() ++ ++ with open(argv[0], "wb") as vmcore: ++ self.dump_init(vmcore) ++ self.dump_iterate(vmcore) + + DumpGuestMemory() +-- +1.8.3.1 + diff --git a/SOURCES/kvm-scripts-dump-guest-memory.py-Make-methods-functions.patch b/SOURCES/kvm-scripts-dump-guest-memory.py-Make-methods-functions.patch new file mode 100644 index 0000000..41469ab --- /dev/null +++ b/SOURCES/kvm-scripts-dump-guest-memory.py-Make-methods-functions.patch @@ -0,0 +1,268 @@ +From 0e125906f0e8bd7015569e7c76b687e4aacb3cca Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:39:05 +0100 +Subject: [PATCH 34/41] scripts/dump-guest-memory.py: Make methods functions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-35-marcandre.lureau@redhat.com> +Patchwork-id: 78384 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 34/41] scripts/dump-guest-memory.py: Make methods functions +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: Janosch Frank + +The functions dealing with qemu components rarely used parts of the +class, so they were moved out of the class. + +As the uintptr_t variable is needed both within and outside the class, +it was made a constant and moved to the top. + +Reviewed-by: Laszlo Ersek +Signed-off-by: Janosch Frank +Message-Id: <1453464520-3882-3-git-send-email-frankja@linux.vnet.ibm.com> +Signed-off-by: Paolo Bonzini + +(cherry picked from commit 47890203842de8b29716bdffb406ca851e70829d) + +RHEL: conflicts due to qtailq->qlist, used_length->length + +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + scripts/dump-guest-memory.py | 184 ++++++++++++++++++++++--------------------- + 1 file changed, 93 insertions(+), 91 deletions(-) + +diff --git a/scripts/dump-guest-memory.py b/scripts/dump-guest-memory.py +index 29f7c5b..7d93d86 100644 +--- a/scripts/dump-guest-memory.py ++++ b/scripts/dump-guest-memory.py +@@ -17,6 +17,8 @@ + + import struct + ++UINTPTR_T = gdb.lookup_type("uintptr_t") ++ + TARGET_PAGE_SIZE = 0x1000 + TARGET_PAGE_MASK = 0xFFFFFFFFFFFFF000 + +@@ -66,6 +68,94 @@ ELF64_PHDR = ("I" # p_type + "Q" # p_align + ) + ++def int128_get64(val): ++ assert (val["hi"] == 0) ++ return val["lo"] ++ ++def qtailq_foreach(head, field_str): ++ var_p = head["tqh_first"] ++ while (var_p != 0): ++ var = var_p.dereference() ++ yield var ++ var_p = var[field_str]["tqe_next"] ++ ++def qemu_get_ram_block(ram_addr): ++ ram_blocks = gdb.parse_and_eval("ram_list.blocks") ++ for block in qtailq_foreach(ram_blocks, "next"): ++ if (ram_addr - block["offset"] < block["length"]): ++ return block ++ raise gdb.GdbError("Bad ram offset %x" % ram_addr) ++ ++def qemu_get_ram_ptr(ram_addr): ++ block = qemu_get_ram_block(ram_addr) ++ return block["host"] + (ram_addr - block["offset"]) ++ ++def memory_region_get_ram_ptr(mr): ++ if (mr["alias"] != 0): ++ return (memory_region_get_ram_ptr(mr["alias"].dereference()) + ++ mr["alias_offset"]) ++ return qemu_get_ram_ptr(mr["ram_addr"] & TARGET_PAGE_MASK) ++ ++def get_guest_phys_blocks(): ++ guest_phys_blocks = [] ++ print "guest RAM blocks:" ++ print ("target_start target_end host_addr message " ++ "count") ++ print ("---------------- ---------------- ---------------- ------- " ++ "-----") ++ ++ current_map_p = gdb.parse_and_eval("address_space_memory.current_map") ++ current_map = current_map_p.dereference() ++ for cur in range(current_map["nr"]): ++ flat_range = (current_map["ranges"] + cur).dereference() ++ mr = flat_range["mr"].dereference() ++ ++ # we only care about RAM ++ if (not mr["ram"]): ++ continue ++ ++ section_size = int128_get64(flat_range["addr"]["size"]) ++ target_start = int128_get64(flat_range["addr"]["start"]) ++ target_end = target_start + section_size ++ host_addr = (memory_region_get_ram_ptr(mr) + ++ flat_range["offset_in_region"]) ++ predecessor = None ++ ++ # find continuity in guest physical address space ++ if (len(guest_phys_blocks) > 0): ++ predecessor = guest_phys_blocks[-1] ++ predecessor_size = (predecessor["target_end"] - ++ predecessor["target_start"]) ++ ++ # the memory API guarantees monotonically increasing ++ # traversal ++ assert (predecessor["target_end"] <= target_start) ++ ++ # we want continuity in both guest-physical and ++ # host-virtual memory ++ if (predecessor["target_end"] < target_start or ++ predecessor["host_addr"] + predecessor_size != host_addr): ++ predecessor = None ++ ++ if (predecessor is None): ++ # isolated mapping, add it to the list ++ guest_phys_blocks.append({"target_start": target_start, ++ "target_end" : target_end, ++ "host_addr" : host_addr}) ++ message = "added" ++ else: ++ # expand predecessor until @target_end; predecessor's ++ # start doesn't change ++ predecessor["target_end"] = target_end ++ message = "joined" ++ ++ print ("%016x %016x %016x %-7s %5u" % ++ (target_start, target_end, host_addr.cast(UINTPTR_T), ++ message, len(guest_phys_blocks))) ++ ++ return guest_phys_blocks ++ ++ + class DumpGuestMemory(gdb.Command): + """Extract guest vmcore from qemu process coredump. + +@@ -100,96 +190,9 @@ shape and this command should mostly work.""" + super(DumpGuestMemory, self).__init__("dump-guest-memory", + gdb.COMMAND_DATA, + gdb.COMPLETE_FILENAME) +- self.uintptr_t = gdb.lookup_type("uintptr_t") + self.elf64_ehdr_le = struct.Struct("<%s" % ELF64_EHDR) + self.elf64_phdr_le = struct.Struct("<%s" % ELF64_PHDR) +- +- def int128_get64(self, val): +- assert (val["hi"] == 0) +- return val["lo"] +- +- def qtailq_foreach(self, head, field_str): +- var_p = head["tqh_first"] +- while (var_p != 0): +- var = var_p.dereference() +- yield var +- var_p = var[field_str]["tqe_next"] +- +- def qemu_get_ram_block(self, ram_addr): +- ram_blocks = gdb.parse_and_eval("ram_list.blocks") +- for block in self.qtailq_foreach(ram_blocks, "next"): +- if (ram_addr - block["offset"] < block["length"]): +- return block +- raise gdb.GdbError("Bad ram offset %x" % ram_addr) +- +- def qemu_get_ram_ptr(self, ram_addr): +- block = self.qemu_get_ram_block(ram_addr) +- return block["host"] + (ram_addr - block["offset"]) +- +- def memory_region_get_ram_ptr(self, mr): +- if (mr["alias"] != 0): +- return (self.memory_region_get_ram_ptr(mr["alias"].dereference()) + +- mr["alias_offset"]) +- return self.qemu_get_ram_ptr(mr["ram_addr"] & TARGET_PAGE_MASK) +- +- def guest_phys_blocks_init(self): +- self.guest_phys_blocks = [] +- +- def guest_phys_blocks_append(self): +- print "guest RAM blocks:" +- print ("target_start target_end host_addr message " +- "count") +- print ("---------------- ---------------- ---------------- ------- " +- "-----") +- +- current_map_p = gdb.parse_and_eval("address_space_memory.current_map") +- current_map = current_map_p.dereference() +- for cur in range(current_map["nr"]): +- flat_range = (current_map["ranges"] + cur).dereference() +- mr = flat_range["mr"].dereference() +- +- # we only care about RAM +- if (not mr["ram"]): +- continue +- +- section_size = self.int128_get64(flat_range["addr"]["size"]) +- target_start = self.int128_get64(flat_range["addr"]["start"]) +- target_end = target_start + section_size +- host_addr = (self.memory_region_get_ram_ptr(mr) + +- flat_range["offset_in_region"]) +- predecessor = None +- +- # find continuity in guest physical address space +- if (len(self.guest_phys_blocks) > 0): +- predecessor = self.guest_phys_blocks[-1] +- predecessor_size = (predecessor["target_end"] - +- predecessor["target_start"]) +- +- # the memory API guarantees monotonically increasing +- # traversal +- assert (predecessor["target_end"] <= target_start) +- +- # we want continuity in both guest-physical and +- # host-virtual memory +- if (predecessor["target_end"] < target_start or +- predecessor["host_addr"] + predecessor_size != host_addr): +- predecessor = None +- +- if (predecessor is None): +- # isolated mapping, add it to the list +- self.guest_phys_blocks.append({"target_start": target_start, +- "target_end" : target_end, +- "host_addr" : host_addr}) +- message = "added" +- else: +- # expand predecessor until @target_end; predecessor's +- # start doesn't change +- predecessor["target_end"] = target_end +- message = "joined" +- +- print ("%016x %016x %016x %-7s %5u" % +- (target_start, target_end, host_addr.cast(self.uintptr_t), +- message, len(self.guest_phys_blocks))) ++ self.guest_phys_blocks = None + + def cpu_get_dump_info(self): + # We can't synchronize the registers with KVM post-mortem, and +@@ -263,8 +266,7 @@ shape and this command should mostly work.""" + len(name) + 1, len(desc), type, name, desc) + + def dump_init(self): +- self.guest_phys_blocks_init() +- self.guest_phys_blocks_append() ++ self.guest_phys_blocks = get_guest_phys_blocks() + self.cpu_get_dump_info() + # we have no way to retrieve the VCPU status from KVM + # post-mortem +@@ -310,7 +312,7 @@ shape and this command should mostly work.""" + cur = block["host_addr"] + left = block["target_end"] - block["target_start"] + print ("dumping range at %016x for length %016x" % +- (cur.cast(self.uintptr_t), left)) ++ (cur.cast(UINTPTR_T), left)) + while (left > 0): + chunk_size = min(TARGET_PAGE_SIZE, left) + chunk = qemu_core.read_memory(cur, chunk_size) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-scripts-dump-guest-memory.py-Move-constants-to-the-t.patch b/SOURCES/kvm-scripts-dump-guest-memory.py-Move-constants-to-the-t.patch new file mode 100644 index 0000000..665e98c --- /dev/null +++ b/SOURCES/kvm-scripts-dump-guest-memory.py-Move-constants-to-the-t.patch @@ -0,0 +1,236 @@ +From 231682fd6a7ca6fc5eecbec3df2f96133b9f3729 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:39:04 +0100 +Subject: [PATCH 33/41] scripts/dump-guest-memory.py: Move constants to the top +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-34-marcandre.lureau@redhat.com> +Patchwork-id: 78378 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 33/41] scripts/dump-guest-memory.py: Move constants to the top +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +From: Janosch Frank + +The constants bloated the class definition and were therefore moved to +the top. + +Reviewed-by: Laszlo Ersek +Signed-off-by: Janosch Frank +Message-Id: <1453464520-3882-2-git-send-email-frankja@linux.vnet.ibm.com> +Signed-off-by: Paolo Bonzini + +(cherry picked from commit ca81ce72b4d12494424d1813c6437035c1f89a8c) +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + scripts/dump-guest-memory.py | 126 +++++++++++++++++++++---------------------- + 1 file changed, 63 insertions(+), 63 deletions(-) + +diff --git a/scripts/dump-guest-memory.py b/scripts/dump-guest-memory.py +index 1ed8b67..29f7c5b 100644 +--- a/scripts/dump-guest-memory.py ++++ b/scripts/dump-guest-memory.py +@@ -17,6 +17,55 @@ + + import struct + ++TARGET_PAGE_SIZE = 0x1000 ++TARGET_PAGE_MASK = 0xFFFFFFFFFFFFF000 ++ ++# Various ELF constants ++EM_X86_64 = 62 # AMD x86-64 target machine ++ELFDATA2LSB = 1 # little endian ++ELFCLASS64 = 2 ++ELFMAG = "\x7FELF" ++EV_CURRENT = 1 ++ET_CORE = 4 ++PT_LOAD = 1 ++PT_NOTE = 4 ++ ++# Special value for e_phnum. This indicates that the real number of ++# program headers is too large to fit into e_phnum. Instead the real ++# value is in the field sh_info of section 0. ++PN_XNUM = 0xFFFF ++ ++# Format strings for packing and header size calculation. ++ELF64_EHDR = ("4s" # e_ident/magic ++ "B" # e_ident/class ++ "B" # e_ident/data ++ "B" # e_ident/version ++ "B" # e_ident/osabi ++ "8s" # e_ident/pad ++ "H" # e_type ++ "H" # e_machine ++ "I" # e_version ++ "Q" # e_entry ++ "Q" # e_phoff ++ "Q" # e_shoff ++ "I" # e_flags ++ "H" # e_ehsize ++ "H" # e_phentsize ++ "H" # e_phnum ++ "H" # e_shentsize ++ "H" # e_shnum ++ "H" # e_shstrndx ++ ) ++ELF64_PHDR = ("I" # p_type ++ "I" # p_flags ++ "Q" # p_offset ++ "Q" # p_vaddr ++ "Q" # p_paddr ++ "Q" # p_filesz ++ "Q" # p_memsz ++ "Q" # p_align ++ ) ++ + class DumpGuestMemory(gdb.Command): + """Extract guest vmcore from qemu process coredump. + +@@ -47,62 +96,13 @@ deliberately called abort(), or it was dumped in response to a signal at + a halfway fortunate point, then its coredump should be in reasonable + shape and this command should mostly work.""" + +- TARGET_PAGE_SIZE = 0x1000 +- TARGET_PAGE_MASK = 0xFFFFFFFFFFFFF000 +- +- # Various ELF constants +- EM_X86_64 = 62 # AMD x86-64 target machine +- ELFDATA2LSB = 1 # little endian +- ELFCLASS64 = 2 +- ELFMAG = "\x7FELF" +- EV_CURRENT = 1 +- ET_CORE = 4 +- PT_LOAD = 1 +- PT_NOTE = 4 +- +- # Special value for e_phnum. This indicates that the real number of +- # program headers is too large to fit into e_phnum. Instead the real +- # value is in the field sh_info of section 0. +- PN_XNUM = 0xFFFF +- +- # Format strings for packing and header size calculation. +- ELF64_EHDR = ("4s" # e_ident/magic +- "B" # e_ident/class +- "B" # e_ident/data +- "B" # e_ident/version +- "B" # e_ident/osabi +- "8s" # e_ident/pad +- "H" # e_type +- "H" # e_machine +- "I" # e_version +- "Q" # e_entry +- "Q" # e_phoff +- "Q" # e_shoff +- "I" # e_flags +- "H" # e_ehsize +- "H" # e_phentsize +- "H" # e_phnum +- "H" # e_shentsize +- "H" # e_shnum +- "H" # e_shstrndx +- ) +- ELF64_PHDR = ("I" # p_type +- "I" # p_flags +- "Q" # p_offset +- "Q" # p_vaddr +- "Q" # p_paddr +- "Q" # p_filesz +- "Q" # p_memsz +- "Q" # p_align +- ) +- + def __init__(self): + super(DumpGuestMemory, self).__init__("dump-guest-memory", + gdb.COMMAND_DATA, + gdb.COMPLETE_FILENAME) + self.uintptr_t = gdb.lookup_type("uintptr_t") +- self.elf64_ehdr_le = struct.Struct("<%s" % self.ELF64_EHDR) +- self.elf64_phdr_le = struct.Struct("<%s" % self.ELF64_PHDR) ++ self.elf64_ehdr_le = struct.Struct("<%s" % ELF64_EHDR) ++ self.elf64_phdr_le = struct.Struct("<%s" % ELF64_PHDR) + + def int128_get64(self, val): + assert (val["hi"] == 0) +@@ -130,7 +130,7 @@ shape and this command should mostly work.""" + if (mr["alias"] != 0): + return (self.memory_region_get_ram_ptr(mr["alias"].dereference()) + + mr["alias_offset"]) +- return self.qemu_get_ram_ptr(mr["ram_addr"] & self.TARGET_PAGE_MASK) ++ return self.qemu_get_ram_ptr(mr["ram_addr"] & TARGET_PAGE_MASK) + + def guest_phys_blocks_init(self): + self.guest_phys_blocks = [] +@@ -198,21 +198,21 @@ shape and this command should mostly work.""" + # most common values. This also means that instruction pointer + # etc. will be bogus in the dump, but at least the RAM contents + # should be valid. +- self.dump_info = {"d_machine": self.EM_X86_64, +- "d_endian" : self.ELFDATA2LSB, +- "d_class" : self.ELFCLASS64} ++ self.dump_info = {"d_machine": EM_X86_64, ++ "d_endian" : ELFDATA2LSB, ++ "d_class" : ELFCLASS64} + + def encode_elf64_ehdr_le(self): + return self.elf64_ehdr_le.pack( +- self.ELFMAG, # e_ident/magic ++ ELFMAG, # e_ident/magic + self.dump_info["d_class"], # e_ident/class + self.dump_info["d_endian"], # e_ident/data +- self.EV_CURRENT, # e_ident/version ++ EV_CURRENT, # e_ident/version + 0, # e_ident/osabi + "", # e_ident/pad +- self.ET_CORE, # e_type ++ ET_CORE, # e_type + self.dump_info["d_machine"], # e_machine +- self.EV_CURRENT, # e_version ++ EV_CURRENT, # e_version + 0, # e_entry + self.elf64_ehdr_le.size, # e_phoff + 0, # e_shoff +@@ -226,7 +226,7 @@ shape and this command should mostly work.""" + ) + + def encode_elf64_note_le(self): +- return self.elf64_phdr_le.pack(self.PT_NOTE, # p_type ++ return self.elf64_phdr_le.pack(PT_NOTE, # p_type + 0, # p_flags + (self.memory_offset - + len(self.note)), # p_offset +@@ -238,7 +238,7 @@ shape and this command should mostly work.""" + ) + + def encode_elf64_load_le(self, offset, start_hwaddr, range_size): +- return self.elf64_phdr_le.pack(self.PT_LOAD, # p_type ++ return self.elf64_phdr_le.pack(PT_LOAD, # p_type + 0, # p_flags + offset, # p_offset + 0, # p_vaddr +@@ -276,7 +276,7 @@ shape and this command should mostly work.""" + # We should never reach PN_XNUM for paging=false dumps: there's + # just a handful of discontiguous ranges after merging. + self.phdr_num += len(self.guest_phys_blocks) +- assert (self.phdr_num < self.PN_XNUM) ++ assert (self.phdr_num < PN_XNUM) + + # Calculate the ELF file offset where the memory dump commences: + # +@@ -312,7 +312,7 @@ shape and this command should mostly work.""" + print ("dumping range at %016x for length %016x" % + (cur.cast(self.uintptr_t), left)) + while (left > 0): +- chunk_size = min(self.TARGET_PAGE_SIZE, left) ++ chunk_size = min(TARGET_PAGE_SIZE, left) + chunk = qemu_core.read_memory(cur, chunk_size) + vmcore.write(chunk) + cur += chunk_size +-- +1.8.3.1 + diff --git a/SOURCES/kvm-scripts-dump-guest-memory.py-add-vmcoreinfo.patch b/SOURCES/kvm-scripts-dump-guest-memory.py-add-vmcoreinfo.patch new file mode 100644 index 0000000..49e4645 --- /dev/null +++ b/SOURCES/kvm-scripts-dump-guest-memory.py-add-vmcoreinfo.patch @@ -0,0 +1,134 @@ +From 8a0fb382404cba1a4d88dd489a14d585fc95f3cf Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:39:10 +0100 +Subject: [PATCH 39/41] scripts/dump-guest-memory.py: add vmcoreinfo +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-40-marcandre.lureau@redhat.com> +Patchwork-id: 78389 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 39/41] scripts/dump-guest-memory.py: add vmcoreinfo +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +Add a vmcoreinfo ELF note in the dump if vmcoreinfo device has the +memory location details. + +Signed-off-by: Marc-André Lureau +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin + +(cherry picked from commit d23bfa91b7789534d16ede6cb7d925bfac3f3c4c) +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + scripts/dump-guest-memory.py | 61 ++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 61 insertions(+) + +diff --git a/scripts/dump-guest-memory.py b/scripts/dump-guest-memory.py +index 03d692d..471aa73 100644 +--- a/scripts/dump-guest-memory.py ++++ b/scripts/dump-guest-memory.py +@@ -17,6 +17,7 @@ + # gdb. + + import ctypes ++import struct + + UINTPTR_T = gdb.lookup_type("uintptr_t") + +@@ -48,6 +49,17 @@ EM_S390 = 22 + EM_AARCH = 183 + EM_X86_64 = 62 + ++VMCOREINFO_FORMAT_ELF = 1 ++ ++def le16_to_cpu(val): ++ return struct.unpack(" 1 << 20: ++ print('warning: invalid vmcoreinfo size') ++ return ++ # now get the full note ++ note = get_arch_note(self.endianness, ++ header.n_namesz - 1, header.n_descsz) ++ ctypes.memmove(ctypes.pointer(note), vmcoreinfo, ctypes.sizeof(note)) ++ ++ self.notes.append(note) ++ self.segments[0].p_filesz += ctypes.sizeof(note) ++ self.segments[0].p_memsz += ctypes.sizeof(note) ++ + def add_segment(self, p_type, p_paddr, p_size): + """Adds a segment to the elf.""" + +@@ -505,6 +536,35 @@ shape and this command should mostly work.""" + cur += chunk_size + left -= chunk_size + ++ def phys_memory_read(self, addr, size): ++ qemu_core = gdb.inferiors()[0] ++ for block in self.guest_phys_blocks: ++ if block["target_start"] <= addr \ ++ and addr + size <= block["target_end"]: ++ haddr = block["host_addr"] + (addr - block["target_start"]) ++ return qemu_core.read_memory(haddr, size) ++ return None ++ ++ def add_vmcoreinfo(self): ++ if not gdb.parse_and_eval("vmcoreinfo_find()") \ ++ or not gdb.parse_and_eval("vmcoreinfo_find()->has_vmcoreinfo"): ++ return ++ ++ fmt = gdb.parse_and_eval("vmcoreinfo_find()->vmcoreinfo.guest_format") ++ addr = gdb.parse_and_eval("vmcoreinfo_find()->vmcoreinfo.paddr") ++ size = gdb.parse_and_eval("vmcoreinfo_find()->vmcoreinfo.size") ++ ++ fmt = le16_to_cpu(fmt) ++ addr = le64_to_cpu(addr) ++ size = le32_to_cpu(size) ++ ++ if fmt != VMCOREINFO_FORMAT_ELF: ++ return ++ ++ vmcoreinfo = self.phys_memory_read(addr, size) ++ if vmcoreinfo: ++ self.elf.add_vmcoreinfo_note(vmcoreinfo.tobytes()) ++ + def invoke(self, args, from_tty): + """Handles command invocation from gdb.""" + +@@ -518,6 +578,7 @@ shape and this command should mostly work.""" + + self.elf = ELF("X86_64") + self.guest_phys_blocks = get_guest_phys_blocks() ++ self.add_vmcoreinfo() + + with open(argv[0], "wb") as vmcore: + self.dump_init(vmcore) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-slirp-Fix-access-to-freed-memory.patch b/SOURCES/kvm-slirp-Fix-access-to-freed-memory.patch new file mode 100644 index 0000000..df5f1ff --- /dev/null +++ b/SOURCES/kvm-slirp-Fix-access-to-freed-memory.patch @@ -0,0 +1,62 @@ +From 8c490d636f5dbe289b43cd0c34413aca3e62e2a9 Mon Sep 17 00:00:00 2001 +From: Xiao Wang +Date: Mon, 27 Nov 2017 07:07:56 +0100 +Subject: [PATCH 5/9] slirp: Fix access to freed memory + +RH-Author: Xiao Wang +Message-id: <1511766477-29559-4-git-send-email-jasowang@redhat.com> +Patchwork-id: 77898 +O-Subject: [RHEL7.5 qemu-kvm PATCH 3/4] slirp: Fix access to freed memory +Bugzilla: 1508745 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: wexu@redhat.com +RH-Acked-by: Miroslav Rezanina + +From: Samuel Thibault + +if_start() goes through the slirp->if_fastq and slirp->if_batchq +list of pending messages, and accesses ifm->ifq_so->so_nqueued of its +elements if ifm->ifq_so != NULL. When freeing a socket, we thus need +to make sure that any pending message for this socket does not refer +to the socket any more. + +Signed-off-by: Samuel Thibault +Tested-by: Brian Candler +Reviewed-by: Stefan Hajnoczi +(cherry picked from commit ea64d5f08817b5e79e17135dce516c7583107f91) +Signed-off-by: Miroslav Rezanina +--- + slirp/socket.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/slirp/socket.c b/slirp/socket.c +index 8e8819c..09b5d3d 100644 +--- a/slirp/socket.c ++++ b/slirp/socket.c +@@ -63,6 +63,23 @@ void + sofree(struct socket *so) + { + Slirp *slirp = so->slirp; ++ struct mbuf *ifm; ++ ++ for (ifm = (struct mbuf *) slirp->if_fastq.qh_link; ++ (struct quehead *) ifm != &slirp->if_fastq; ++ ifm = ifm->ifq_next) { ++ if (ifm->ifq_so == so) { ++ ifm->ifq_so = NULL; ++ } ++ } ++ ++ for (ifm = (struct mbuf *) slirp->if_batchq.qh_link; ++ (struct quehead *) ifm != &slirp->if_batchq; ++ ifm = ifm->ifq_next) { ++ if (ifm->ifq_so == so) { ++ ifm->ifq_so = NULL; ++ } ++ } + + if (so->so_emu==EMU_RSH && so->extra) { + sofree(so->extra); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-slirp-cleanup-leftovers-from-misc.h.patch b/SOURCES/kvm-slirp-cleanup-leftovers-from-misc.h.patch new file mode 100644 index 0000000..a04db3a --- /dev/null +++ b/SOURCES/kvm-slirp-cleanup-leftovers-from-misc.h.patch @@ -0,0 +1,64 @@ +From def99e39e5f759343634b0f0047343744a0e0c36 Mon Sep 17 00:00:00 2001 +From: Xiao Wang +Date: Mon, 27 Nov 2017 07:07:54 +0100 +Subject: [PATCH 3/9] slirp: cleanup leftovers from misc.h + +RH-Author: Xiao Wang +Message-id: <1511766477-29559-2-git-send-email-jasowang@redhat.com> +Patchwork-id: 77897 +O-Subject: [RHEL7.5 qemu-kvm PATCH 1/4] slirp: cleanup leftovers from misc.h +Bugzilla: 1508745 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: wexu@redhat.com +RH-Acked-by: Miroslav Rezanina + +From: Michael Tokarev + +There are quite a few leftover declarations in slirp/misc.h. +Remove them. + +Signed-off-by: Michael Tokarev +(cherry picked from commit a9c34e4485ef0a8a61e88f1c9f9bb87f00ba2c72) +Signed-off-by: Miroslav Rezanina +--- + slirp/misc.h | 14 -------------- + 1 file changed, 14 deletions(-) + +diff --git a/slirp/misc.h b/slirp/misc.h +index cc36aeb..ba8beb1 100644 +--- a/slirp/misc.h ++++ b/slirp/misc.h +@@ -20,8 +20,6 @@ struct ex_list { + char *strdup(const char *); + #endif + +-void do_wait(int); +- + #define EMU_NONE 0x0 + + /* TCP emulations */ +@@ -51,21 +49,9 @@ struct emu_t { + struct emu_t *next; + }; + +-extern int x_port, x_server, x_display; +- +-int show_x(char *, struct socket *); +-void redir_x(uint32_t, int, int, int); + void slirp_insque(void *, void *); + void slirp_remque(void *); + int add_exec(struct ex_list **, int, char *, struct in_addr, int); +-int slirp_openpty(int *, int *); + int fork_exec(struct socket *so, const char *ex, int do_pty); +-void snooze_hup(int); +-void snooze(void); +-void relay(int); +-void add_emu(char *); +-void fd_nonblock(int); +-void fd_block(int); +-int rsh_exec(struct socket *, struct socket *, char *, char *, char *); + + #endif +-- +1.8.3.1 + diff --git a/SOURCES/kvm-slirp-fix-clearing-ifq_so-from-pending-packets.patch b/SOURCES/kvm-slirp-fix-clearing-ifq_so-from-pending-packets.patch new file mode 100644 index 0000000..f63c8f6 --- /dev/null +++ b/SOURCES/kvm-slirp-fix-clearing-ifq_so-from-pending-packets.patch @@ -0,0 +1,93 @@ +From 082c19eeb7917a141bae4cf98d0ef941956adab6 Mon Sep 17 00:00:00 2001 +From: Xiao Wang +Date: Mon, 27 Nov 2017 07:07:57 +0100 +Subject: [PATCH 6/9] slirp: fix clearing ifq_so from pending packets +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Xiao Wang +Message-id: <1511766477-29559-5-git-send-email-jasowang@redhat.com> +Patchwork-id: 77901 +O-Subject: [RHEL7.5 qemu-kvm PATCH 4/4] slirp: fix clearing ifq_so from pending packets +Bugzilla: 1508745 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: wexu@redhat.com +RH-Acked-by: Miroslav Rezanina + +From: Samuel Thibault + +The if_fastq and if_batchq contain not only packets, but queues of packets +for the same socket. When sofree frees a socket, it thus has to clear ifq_so +from all the packets from the queues, not only the first. + +Signed-off-by: Samuel Thibault +Reviewed-by: Philippe Mathieu-Daudé +Cc: qemu-stable@nongnu.org +Signed-off-by: Peter Maydell +(cherry picked from commit 1201d308519f1e915866d7583d5136d03cc1d384) +Signed-off-by: Miroslav Rezanina +--- + slirp/socket.c | 39 +++++++++++++++++++++++---------------- + 1 file changed, 23 insertions(+), 16 deletions(-) + +diff --git a/slirp/socket.c b/slirp/socket.c +index 09b5d3d..7837664 100644 +--- a/slirp/socket.c ++++ b/slirp/socket.c +@@ -57,29 +57,36 @@ socreate(Slirp *slirp) + } + + /* ++ * Remove references to so from the given message queue. ++ */ ++static void ++soqfree(struct socket *so, struct quehead *qh) ++{ ++ struct mbuf *ifq; ++ ++ for (ifq = (struct mbuf *) qh->qh_link; ++ (struct quehead *) ifq != qh; ++ ifq = ifq->ifq_next) { ++ if (ifq->ifq_so == so) { ++ struct mbuf *ifm; ++ ifq->ifq_so = NULL; ++ for (ifm = ifq->ifs_next; ifm != ifq; ifm = ifm->ifs_next) { ++ ifm->ifq_so = NULL; ++ } ++ } ++ } ++} ++ ++/* + * remque and free a socket, clobber cache + */ + void + sofree(struct socket *so) + { + Slirp *slirp = so->slirp; +- struct mbuf *ifm; +- +- for (ifm = (struct mbuf *) slirp->if_fastq.qh_link; +- (struct quehead *) ifm != &slirp->if_fastq; +- ifm = ifm->ifq_next) { +- if (ifm->ifq_so == so) { +- ifm->ifq_so = NULL; +- } +- } + +- for (ifm = (struct mbuf *) slirp->if_batchq.qh_link; +- (struct quehead *) ifm != &slirp->if_batchq; +- ifm = ifm->ifq_next) { +- if (ifm->ifq_so == so) { +- ifm->ifq_so = NULL; +- } +- } ++ soqfree(so, &slirp->if_fastq); ++ soqfree(so, &slirp->if_batchq); + + if (so->so_emu==EMU_RSH && so->extra) { + sofree(so->extra); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-target-i386-Add-Intel-SHA_NI-instruction-support.patch b/SOURCES/kvm-target-i386-Add-Intel-SHA_NI-instruction-support.patch new file mode 100644 index 0000000..09943b4 --- /dev/null +++ b/SOURCES/kvm-target-i386-Add-Intel-SHA_NI-instruction-support.patch @@ -0,0 +1,61 @@ +From 481923b5c3cd124ba38ee34e803f15afae39c793 Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Thu, 5 Oct 2017 22:39:07 +0200 +Subject: [PATCH 24/27] target-i386: Add Intel SHA_NI instruction support. + +RH-Author: Eduardo Habkost +Message-id: <20171005223908.431-2-ehabkost@redhat.com> +Patchwork-id: 76832 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 1/2] target-i386: Add Intel SHA_NI instruction support. +Bugzilla: 1450396 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Igor Mammedov +RH-Acked-by: Bandan Das + +From: Yi Sun + +Add SHA_NI feature bit. Its spec can be found at: +https://software.intel.com/sites/default/files/managed/39/c5/325462-sdm-vol-1-2abcd-3abcd.pdf + +Backport notes: +* target/i386 is target-i386 in the QEMU 1.5.3 tree + +Signed-off-by: Yi Sun +Message-Id: <1481683803-10051-1-git-send-email-yi.y.sun@linux.intel.com> +Signed-off-by: Paolo Bonzini +(cherry picked from commit 638cbd452d3a92a2ab18caee73078483d90f64eb) +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + target-i386/cpu.c | 2 +- + target-i386/cpu.h | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/target-i386/cpu.c b/target-i386/cpu.c +index fbd3117..e0749c0 100644 +--- a/target-i386/cpu.c ++++ b/target-i386/cpu.c +@@ -151,7 +151,7 @@ static const char *cpuid_7_0_ebx_feature_name[] = { + "avx512f", "avx512dq", "rdseed", "adx", + "smap", "avx512ifma", NULL, NULL, + NULL, NULL, "avx512pf", "avx512er", +- "avx512cd", NULL, "avx512bw", "avx512vl", ++ "avx512cd", "sha-ni", "avx512bw", "avx512vl", + }; + + static const char *cpuid_7_0_ecx_feature_name[] = { +diff --git a/target-i386/cpu.h b/target-i386/cpu.h +index 7a12c0d..78b8072 100644 +--- a/target-i386/cpu.h ++++ b/target-i386/cpu.h +@@ -575,6 +575,7 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; + #define CPUID_7_0_EBX_AVX512ER (1U << 27) /* AVX-512 Exponential and Reciprocal */ + #define CPUID_7_0_EBX_AVX512CD (1U << 28) /* AVX-512 Conflict Detection */ + #define CPUID_7_0_EBX_AVX512BW (1U << 30) /* AVX-512 Byte and Word Instructions */ ++#define CPUID_7_0_EBX_SHA_NI (1U << 29) /* SHA1/SHA256 Instruction Extensions */ + #define CPUID_7_0_EBX_AVX512VL (1U << 31) /* AVX-512 Vector Length Extensions */ + + #define CPUID_7_0_ECX_VBMI (1U << 1) /* AVX-512 Vector Byte Manipulation Instrs */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-target-i386-Add-PKU-and-and-OSPKE-support.patch b/SOURCES/kvm-target-i386-Add-PKU-and-and-OSPKE-support.patch new file mode 100644 index 0000000..7143ed0 --- /dev/null +++ b/SOURCES/kvm-target-i386-Add-PKU-and-and-OSPKE-support.patch @@ -0,0 +1,186 @@ +From 27f52a18ed8503f5a0333106c38e44f911052d4d Mon Sep 17 00:00:00 2001 +From: "plai@redhat.com" +Date: Mon, 11 Sep 2017 21:57:36 +0200 +Subject: [PATCH 4/4] target-i386: Add PKU and and OSPKE support + +RH-Author: plai@redhat.com +Message-id: <1505167056-5861-1-git-send-email-plai@redhat.com> +Patchwork-id: 76308 +O-Subject: [RHEL7.5 PATCH BZ 1387648 v2] target-i386: Add PKU and and OSPKE support +Bugzilla: 1387648 +RH-Acked-by: Eduardo Habkost +RH-Acked-by: Bandan Das +RH-Acked-by: Miroslav Rezanina + +From: Huaitong Han + +------ v2 comment +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1387648 +BREW: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=14031692 + +In v1, Eduardo noticed "avx512-vpopcntdq" moved in +target-i386/cpu.c:cpuid_7_0_ecx_feature_name[]. +Corrected the patch typo here in v2. + +Tested on intel-purley-fpgabmp-01.khw.lab.eng.bos.redhat.com. +VM guest was fedora-26 image (linux 4.11.0-300). +Tests Run (of tools/testing/selftests/x86/protection_keys.c): + 1. Successful test on host, + 2. Successful negative test w/ current qemu-kvm in VM guest. + 3. Successful test w/ test build qemu-kvm in VM guest. +------ + +Add PKU and OSPKE CPUID features, including xsave state and +migration support. + +Signed-off-by: Huaitong Han +Reviewed-by: Eduardo Habkost +[ehabkost: squashed 3 patches together, edited patch description] +Signed-off-by: Eduardo Habkost + +(cherry picked from commit f74eefe0b98cd7e13825de8e8d9f32e22aed102c) +Signed-off-by: Paul Lai + +Resolved Conflicts: + target-i386/cpu.c + target-i386/cpu.h + target-i386/kvm.c + target-i386/machine.c + +Signed-off-by: Miroslav Rezanina +--- + target-i386/cpu.c | 6 ++++-- + target-i386/cpu.h | 6 ++++++ + target-i386/kvm.c | 3 +++ + target-i386/machine.c | 25 +++++++++++++++++++++++++ + 4 files changed, 38 insertions(+), 2 deletions(-) + +diff --git a/target-i386/cpu.c b/target-i386/cpu.c +index ae56995..fbd3117 100644 +--- a/target-i386/cpu.c ++++ b/target-i386/cpu.c +@@ -155,8 +155,8 @@ static const char *cpuid_7_0_ebx_feature_name[] = { + }; + + static const char *cpuid_7_0_ecx_feature_name[] = { +- NULL, "avx512vbmi", NULL, NULL, +- NULL, NULL, NULL, NULL, ++ NULL, "avx512vbmi", NULL, "pku", ++ "ospke", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, "avx512-vpopcntdq", NULL, + NULL, NULL, NULL, NULL, +@@ -361,6 +361,8 @@ static const ExtSaveArea ext_save_areas[] = { + .offset = 0x480, .size = 0x200 }, + [7] = { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F, + .offset = 0x680, .size = 0x400 }, ++ [9] = { .feature = FEAT_7_0_ECX, .bits = CPUID_7_0_ECX_PKU, ++ .offset = 0xA80, .size = 0x8 }, + }; + + const char *get_register_name_32(unsigned int reg) +diff --git a/target-i386/cpu.h b/target-i386/cpu.h +index ac60309..7a12c0d 100644 +--- a/target-i386/cpu.h ++++ b/target-i386/cpu.h +@@ -394,6 +394,7 @@ + #define XSTATE_OPMASK (1ULL << 5) + #define XSTATE_ZMM_Hi256 (1ULL << 6) + #define XSTATE_Hi16_ZMM (1ULL << 7) ++#define XSTATE_PKRU (1ULL << 9) + + + /* CPUID feature words */ +@@ -586,6 +587,9 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; + #define CPUID_7_0_EDX_AVX512_4VNNIW (1U << 2) /* AVX512 Neural Network Instructions */ + #define CPUID_7_0_EDX_AVX512_4FMAPS (1U << 3) /* AVX512 Multiply Accumulation Single Precision */ + ++#define CPUID_7_0_ECX_PKU (1U << 3) ++#define CPUID_7_0_ECX_OSPKE (1U << 4) ++ + #define CPUID_XSAVE_XSAVEOPT (1U << 0) + #define CPUID_XSAVE_XSAVEC (1U << 1) + #define CPUID_XSAVE_XGETBV1 (1U << 2) +@@ -1029,6 +1033,8 @@ typedef struct CPUX86State { + uint64_t xcr0; + uint64_t xss; + ++ uint32_t pkru; ++ + TPRAccess tpr_access_type; + } CPUX86State; + +diff --git a/target-i386/kvm.c b/target-i386/kvm.c +index 6a479f4..0dc0e79 100644 +--- a/target-i386/kvm.c ++++ b/target-i386/kvm.c +@@ -1008,6 +1008,7 @@ static int kvm_put_fpu(X86CPU *cpu) + #define XSAVE_OPMASK 272 + #define XSAVE_ZMM_Hi256 288 + #define XSAVE_Hi16_ZMM 416 ++#define XSAVE_PKRU 672 + + static int kvm_put_xsave(X86CPU *cpu) + { +@@ -1051,6 +1052,7 @@ static int kvm_put_xsave(X86CPU *cpu) + #ifdef TARGET_X86_64 + memcpy(&xsave->region[XSAVE_Hi16_ZMM], env->hi16_zmm_regs, + sizeof env->hi16_zmm_regs); ++ memcpy(&xsave->region[XSAVE_PKRU], &env->pkru, sizeof env->pkru); + #endif + r = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_XSAVE, xsave); + return r; +@@ -1388,6 +1390,7 @@ static int kvm_get_xsave(X86CPU *cpu) + #ifdef TARGET_X86_64 + memcpy(env->hi16_zmm_regs, &xsave->region[XSAVE_Hi16_ZMM], + sizeof env->hi16_zmm_regs); ++ memcpy(&env->pkru, &xsave->region[XSAVE_PKRU], sizeof env->pkru); + #endif + return 0; + } +diff --git a/target-i386/machine.c b/target-i386/machine.c +index ce7fcd3..ba34088 100644 +--- a/target-i386/machine.c ++++ b/target-i386/machine.c +@@ -722,6 +722,26 @@ static const VMStateDescription vmstate_xss = { + } + }; + ++#ifdef TARGET_X86_64 ++static bool pkru_needed(void *opaque) ++{ ++ X86CPU *cpu = opaque; ++ CPUX86State *env = &cpu->env; ++ ++ return env->pkru != 0; ++} ++ ++static const VMStateDescription vmstate_pkru = { ++ .name = "cpu/pkru", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField[]){ ++ VMSTATE_UINT32(env.pkru, X86CPU), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++#endif ++ + const VMStateDescription vmstate_x86_cpu = { + .name = "cpu", + .version_id = 12, +@@ -871,6 +891,11 @@ const VMStateDescription vmstate_x86_cpu = { + }, { + .vmsd = &vmstate_xss, + .needed = xss_needed, ++#ifdef TARGET_X86_64 ++ }, { ++ .vmsd = &vmstate_pkru, ++ .needed = pkru_needed, ++#endif + } , { + /* empty */ + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-target-i386-Enable-clflushopt-clwb-pcommit-instructi.patch b/SOURCES/kvm-target-i386-Enable-clflushopt-clwb-pcommit-instructi.patch new file mode 100644 index 0000000..e4b696a --- /dev/null +++ b/SOURCES/kvm-target-i386-Enable-clflushopt-clwb-pcommit-instructi.patch @@ -0,0 +1,50 @@ +From 9381f1943a9e2c5273e32a76fae36daf67ab7089 Mon Sep 17 00:00:00 2001 +From: Miroslav Rezanina +Date: Tue, 24 Oct 2017 05:33:03 +0200 +Subject: [PATCH 26/27] target-i386: Enable clflushopt/clwb/pcommit + instructions + +RH-Author: Eduardo Habkost +Message-id: <20171017203653.28578-2-ehabkost@redhat.com> +Patchwork-id: 77349 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 1/2] target-i386: Enable clflushopt/clwb/pcommit instructions +Bugzilla: 1501510 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Igor Mammedov +RH-Acked-by: Bandan Das + +From: Xiao Guangrong + +These instructions are used by NVDIMM drivers and the specification is +located at: +https://software.intel.com/sites/default/files/managed/0d/53/319433-022.pdf + +There instructions are available on Skylake Server. + +Signed-off-by: Xiao Guangrong +Reviewed-by: Richard Henderson +Signed-off-by: Eduardo Habkost +(cherry picked from commit f7fda280948a5e74aeb076ef346b991ecb173c56) +Signed-off-by: Eduardo Habkost +--- + target-i386/cpu.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/target-i386/cpu.c b/target-i386/cpu.c +index 914fc66..e739647 100644 +--- a/target-i386/cpu.c ++++ b/target-i386/cpu.c +@@ -149,8 +149,8 @@ static const char *cpuid_7_0_ebx_feature_name[] = { + "bmi2", "erms", "invpcid", "rtm", + NULL, NULL, "mpx", NULL, + "avx512f", "avx512dq", "rdseed", "adx", +- "smap", "avx512ifma", NULL, NULL, +- NULL, NULL, "avx512pf", "avx512er", ++ "smap", "avx512ifma", "pcommit", "clflushopt", ++ "clwb", NULL, "avx512pf", "avx512er", + "avx512cd", "sha-ni", "avx512bw", "avx512vl", + }; + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-target-i386-add-support-for-SPEC_CTRL-MSR.patch b/SOURCES/kvm-target-i386-add-support-for-SPEC_CTRL-MSR.patch new file mode 100644 index 0000000..d0a50e9 --- /dev/null +++ b/SOURCES/kvm-target-i386-add-support-for-SPEC_CTRL-MSR.patch @@ -0,0 +1,143 @@ +From 9875f9aaef996083064bf6a7afa1bfa30ff7d953 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Wed, 13 Dec 2017 15:43:40 -0200 +Subject: [PATCH 2/3] target-i386: add support for SPEC_CTRL MSR + +RH-Author: Eduardo Habkost +Message-id: <20171213174341.20684-3-ehabkost@redhat.com> +Patchwork-id: n/a +O-Subject: [CONFIDENTIAL][RHEL-7.5 qemu-kvm PATCH v2 2/3] target-i386: add + support for SPEC_CTRL MSR +Bugzilla: CVE-2017-5715 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Miroslav Rezanina +--- + target-i386/cpu.h | 4 ++++ + target-i386/kvm.c | 14 ++++++++++++++ + target-i386/machine.c | 21 +++++++++++++++++++++ + 3 files changed, 39 insertions(+) + +diff --git a/target-i386/cpu.h b/target-i386/cpu.h +index 1e5c980..7d815cd 100644 +--- a/target-i386/cpu.h ++++ b/target-i386/cpu.h +@@ -304,6 +304,7 @@ + #define MSR_IA32_APICBASE_ENABLE (1<<11) + #define MSR_IA32_APICBASE_BASE (0xfffff<<12) + #define MSR_TSC_ADJUST 0x0000003b ++#define MSR_IA32_SPEC_CTRL 0x48 + #define MSR_IA32_TSCDEADLINE 0x6e0 + + #define MSR_P6_PERFCTR0 0xc1 +@@ -963,6 +964,7 @@ typedef struct CPUX86State { + uint64_t msr_fixed_counters[MAX_FIXED_COUNTERS]; + uint64_t msr_gp_counters[MAX_GP_COUNTERS]; + uint64_t msr_gp_evtsel[MAX_GP_COUNTERS]; ++ + uint64_t msr_hv_hypercall; + uint64_t msr_hv_guest_os_id; + uint64_t msr_hv_vapic; +@@ -1037,6 +1039,8 @@ typedef struct CPUX86State { + + uint32_t pkru; + ++ uint64_t spec_ctrl; ++ + TPRAccess tpr_access_type; + } CPUX86State; + +diff --git a/target-i386/kvm.c b/target-i386/kvm.c +index 0dc0e79..24d17ad 100644 +--- a/target-i386/kvm.c ++++ b/target-i386/kvm.c +@@ -77,6 +77,7 @@ static bool has_msr_hv_vapic; + static bool has_msr_hv_tsc; + static bool has_msr_mtrr; + static bool has_msr_xss; ++static bool has_msr_spec_ctrl; + + static bool has_msr_architectural_pmu; + static uint32_t num_architectural_pmu_counters; +@@ -800,6 +801,10 @@ static int kvm_get_supported_msrs(KVMState *s) + has_msr_xss = true; + continue; + } ++ if (kvm_msr_list->indices[i] == MSR_IA32_SPEC_CTRL) { ++ has_msr_spec_ctrl = true; ++ continue; ++ } + } + } + +@@ -1187,6 +1192,9 @@ static int kvm_put_msrs(X86CPU *cpu, int level) + if (has_msr_xss) { + kvm_msr_entry_set(&msrs[n++], MSR_IA32_XSS, env->xss); + } ++ if (has_msr_spec_ctrl) { ++ kvm_msr_entry_set(&msrs[n++], MSR_IA32_SPEC_CTRL, env->spec_ctrl); ++ } + #ifdef TARGET_X86_64 + if (lm_capable_kernel) { + kvm_msr_entry_set(&msrs[n++], MSR_CSTAR, env->cstar); +@@ -1544,6 +1552,9 @@ static int kvm_get_msrs(X86CPU *cpu) + if (has_msr_xss) { + msrs[n++].index = MSR_IA32_XSS; + } ++ if (has_msr_spec_ctrl) { ++ msrs[n++].index = MSR_IA32_SPEC_CTRL; ++ } + + + if (!env->tsc_valid) { +@@ -1786,6 +1797,9 @@ static int kvm_get_msrs(X86CPU *cpu) + env->mtrr_var[MSR_MTRRphysIndex(index)].base = msrs[i].data; + } + break; ++ case MSR_IA32_SPEC_CTRL: ++ env->spec_ctrl = msrs[i].data; ++ break; + } + } + +diff --git a/target-i386/machine.c b/target-i386/machine.c +index ba34088..d883c86 100644 +--- a/target-i386/machine.c ++++ b/target-i386/machine.c +@@ -742,6 +742,24 @@ static const VMStateDescription vmstate_pkru = { + }; + #endif + ++static bool spec_ctrl_needed(void *opaque) ++{ ++ X86CPU *cpu = opaque; ++ CPUX86State *env = &cpu->env; ++ ++ return env->spec_ctrl != 0; ++} ++ ++static const VMStateDescription vmstate_spec_ctrl = { ++ .name = "cpu/spec_ctrl", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField[]){ ++ VMSTATE_UINT64(env.spec_ctrl, X86CPU), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ + const VMStateDescription vmstate_x86_cpu = { + .name = "cpu", + .version_id = 12, +@@ -896,6 +914,9 @@ const VMStateDescription vmstate_x86_cpu = { + .vmsd = &vmstate_pkru, + .needed = pkru_needed, + #endif ++ }, { ++ .vmsd = &vmstate_spec_ctrl, ++ .needed = spec_ctrl_needed, + } , { + /* empty */ + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-target-i386-cpu-Add-new-EPYC-CPU-model.patch b/SOURCES/kvm-target-i386-cpu-Add-new-EPYC-CPU-model.patch new file mode 100644 index 0000000..9e83d76 --- /dev/null +++ b/SOURCES/kvm-target-i386-cpu-Add-new-EPYC-CPU-model.patch @@ -0,0 +1,104 @@ +From 15c5cb87402b646349a6cc535cc74cefd01dbf1e Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Thu, 5 Oct 2017 22:39:08 +0200 +Subject: [PATCH 25/27] target-i386/cpu: Add new EPYC CPU model + +RH-Author: Eduardo Habkost +Message-id: <20171005223908.431-3-ehabkost@redhat.com> +Patchwork-id: 76833 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 2/2] target-i386/cpu: Add new EPYC CPU model +Bugzilla: 1450396 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Igor Mammedov +RH-Acked-by: Bandan Das + +From: Brijesh Singh + +Add a new base CPU model called 'EPYC' to model processors from AMD EPYC +family (which includes EPYC 76xx,75xx,74xx, 73xx and 72xx). + +The following features bits have been added/removed compare to Opteron_G5 + +Added: monitor, movbe, rdrand, mmxext, ffxsr, rdtscp, cr8legacy, osvw, + fsgsbase, bmi1, avx2, smep, bmi2, rdseed, adx, smap, clfshopt, sha + xsaveopt, xsavec, xgetbv1, arat + +Removed: xop, fma4, tbm + +Backport notes: +* ARAT feature removed. It is already disabled by the rhel7.2.0 + compat code in qemu-kvm-rhev, so it keeps migration compatibility + with qemu-kvm-rhev. + +Signed-off-by: Brijesh Singh +Message-Id: <20170815170051.127257-1-brijesh.singh@amd.com> +Reviewed-by: Eduardo Habkost +Signed-off-by: Eduardo Habkost +(cherry picked from commit 2e2efc7dbe2b0adc1200b5aa286cdbed729f6751) +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + target-i386/cpu.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 47 insertions(+) + +diff --git a/target-i386/cpu.c b/target-i386/cpu.c +index e0749c0..914fc66 100644 +--- a/target-i386/cpu.c ++++ b/target-i386/cpu.c +@@ -1218,6 +1218,53 @@ static x86_def_t builtin_x86_defs[] = { + .xlevel = 0x8000001A, + .model_id = "AMD Opteron 63xx class CPU", + }, ++ { ++ .name = "EPYC", ++ .level = 0xd, ++ .vendor = CPUID_VENDOR_AMD, ++ .family = 23, ++ .model = 1, ++ .stepping = 2, ++ .features[FEAT_1_EDX] = ++ CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | CPUID_CLFLUSH | ++ CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | CPUID_PGE | ++ CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | CPUID_MCE | ++ CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | CPUID_DE | ++ CPUID_VME | CPUID_FP87, ++ .features[FEAT_1_ECX] = ++ CPUID_EXT_RDRAND | CPUID_EXT_F16C | CPUID_EXT_AVX | ++ CPUID_EXT_XSAVE | CPUID_EXT_AES | CPUID_EXT_POPCNT | ++ CPUID_EXT_MOVBE | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 | ++ CPUID_EXT_CX16 | CPUID_EXT_FMA | CPUID_EXT_SSSE3 | ++ CPUID_EXT_MONITOR | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3, ++ .features[FEAT_8000_0001_EDX] = ++ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_PDPE1GB | ++ CPUID_EXT2_FFXSR | CPUID_EXT2_MMXEXT | CPUID_EXT2_NX | ++ CPUID_EXT2_SYSCALL, ++ .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, ++ .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 | ++ CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLFLUSHOPT | ++ CPUID_7_0_EBX_SHA_NI, ++ /* Missing: XSAVES (not supported by some Linux versions, ++ * including v4.1 to v4.12). ++ * KVM doesn't yet expose any XSAVES state save component. ++ */ ++ .features[FEAT_XSAVE] = ++ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | ++ CPUID_XSAVE_XGETBV1, ++ /* Missing: ARAT (not supported by QEMU 1.5.3) */ ++#if 0 ++ .features[FEAT_6_EAX] = ++ CPUID_6_EAX_ARAT, ++#endif ++ .xlevel = 0x8000000A, ++ .model_id = "AMD EPYC Processor", ++ }, + }; + + /** +-- +1.8.3.1 + diff --git a/SOURCES/kvm-target-i386-cpu-add-new-CPU-models-for-indirect-bran.patch b/SOURCES/kvm-target-i386-cpu-add-new-CPU-models-for-indirect-bran.patch new file mode 100644 index 0000000..e0e53f8 --- /dev/null +++ b/SOURCES/kvm-target-i386-cpu-add-new-CPU-models-for-indirect-bran.patch @@ -0,0 +1,523 @@ +From 4f2a39dd988cfae0210dfa7a84be00617ba17bef Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Wed, 13 Dec 2017 15:43:41 -0200 +Subject: [PATCH 3/3] target-i386: cpu: add new CPU models for indirect branch + predictor restrictions + +RH-Author: Eduardo Habkost +Message-id: <20171213174341.20684-4-ehabkost@redhat.com> +Patchwork-id: n/a +O-Subject: [CONFIDENTIAL][RHEL-7.5 qemu-kvm PATCH v2 3/3] target-i386: cpu: add + new CPU models for indirect branch predictor restrictions +Bugzilla: CVE-2017-5715 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Miroslav Rezanina + +Changes v1 -> v2: +* Copied the original CPU models from the same source file, just adding + SPEC_CTRL and updating level/xlevel/model_id/stepping, to keep compatibility + code exactly the same. +* Update compat_props so we can be sure the same compat rules will apply to the + original CPU models and to the *-IBRS ones + +To ensure the New CPU models won't introduce any unexpected +changes except for the spec-ctrl feature (even if people are +running older machine-types), copy all compat_props entries for +existing CPU models to their *-IBRS versions. + +The only entries that are not being copied are the ones touching +"(min-)level" and "(min-)xlevel" because it's an expected result +of the CPU model change (otherwise the spec-ctrl feature would +remain unavailable to the guest). + +The entries that had to be copied can be found using: + $ git grep -E 'Nehalem|Westmere|SandyBridge|IvyBridge|Haswell-noTSX|Haswell|Broadwell-noTSX|Broadwell|Skylake-Client|Skylake-Server|EPYC' + +Note that the upstream-only PC_COMPAT_* macros are not being +touched as they are not used by the RHEL machine-types. +--- + hw/i386/pc_piix.c | 17 +++ + hw/i386/pc_q35.c | 1 + + target-i386/cpu.c | 328 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + target-i386/cpu.h | 3 + + 4 files changed, 349 insertions(+) + +diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c +index b043124..c53a6d4 100644 +--- a/hw/i386/pc_piix.c ++++ b/hw/i386/pc_piix.c +@@ -753,7 +753,9 @@ static void pc_compat_rhel700(QEMUMachineInitArgs *args) + x86_cpu_compat_set_features("Conroe", FEAT_1_ECX, CPUID_EXT_X2APIC, 0); + x86_cpu_compat_set_features("Penryn", FEAT_1_ECX, CPUID_EXT_X2APIC, 0); + x86_cpu_compat_set_features("Nehalem", FEAT_1_ECX, CPUID_EXT_X2APIC, 0); ++ x86_cpu_compat_set_features("Nehalem-IBRS", FEAT_1_ECX, CPUID_EXT_X2APIC, 0); + x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, CPUID_EXT_X2APIC, 0); ++ x86_cpu_compat_set_features("Westmere-IBRS", FEAT_1_ECX, CPUID_EXT_X2APIC, 0); + /* SandyBridge and Haswell already have x2apic enabled */ + x86_cpu_compat_set_features("Opteron_G1", FEAT_1_ECX, CPUID_EXT_X2APIC, 0); + x86_cpu_compat_set_features("Opteron_G2", FEAT_1_ECX, CPUID_EXT_X2APIC, 0); +@@ -928,18 +930,31 @@ static void pc_compat_rhel660(QEMUMachineInitArgs *args) + x86_cpu_compat_set_features("Conroe", FEAT_1_ECX, CPUID_EXT_X2APIC, 0); + x86_cpu_compat_set_features("Penryn", FEAT_1_ECX, CPUID_EXT_X2APIC, 0); + x86_cpu_compat_set_features("Nehalem", FEAT_1_ECX, CPUID_EXT_X2APIC, 0); ++ x86_cpu_compat_set_features("Nehalem-IBRS", FEAT_1_ECX, CPUID_EXT_X2APIC, 0); + x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, CPUID_EXT_X2APIC, 0); ++ x86_cpu_compat_set_features("Westmere-IBRS", FEAT_1_ECX, CPUID_EXT_X2APIC, 0); + x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ); ++ x86_cpu_compat_set_features("Westmere-IBRS", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ); + x86_cpu_compat_set_features("Westmere", FEAT_8000_0001_EDX, + CPUID_EXT2_FXSR | CPUID_EXT2_MMX | CPUID_EXT2_PAT | + CPUID_EXT2_CMOV | CPUID_EXT2_PGE | CPUID_EXT2_APIC | + CPUID_EXT2_CX8 | CPUID_EXT2_MCE | CPUID_EXT2_PAE | CPUID_EXT2_MSR | + CPUID_EXT2_TSC | CPUID_EXT2_PSE | CPUID_EXT2_DE | CPUID_EXT2_FPU, + 0); ++ x86_cpu_compat_set_features("Westmere-IBRS", FEAT_8000_0001_EDX, ++ CPUID_EXT2_FXSR | CPUID_EXT2_MMX | CPUID_EXT2_PAT | ++ CPUID_EXT2_CMOV | CPUID_EXT2_PGE | CPUID_EXT2_APIC | ++ CPUID_EXT2_CX8 | CPUID_EXT2_MCE | CPUID_EXT2_PAE | CPUID_EXT2_MSR | ++ CPUID_EXT2_TSC | CPUID_EXT2_PSE | CPUID_EXT2_DE | CPUID_EXT2_FPU, ++ 0); + x86_cpu_compat_set_features("Broadwell", FEAT_8000_0001_EDX, + 0, CPUID_EXT2_RDTSCP); ++ x86_cpu_compat_set_features("Broadwell-IBRS", FEAT_8000_0001_EDX, ++ 0, CPUID_EXT2_RDTSCP); + x86_cpu_compat_set_features("Broadwell", FEAT_7_0_EBX, + 0, CPUID_7_0_EBX_SMAP); ++ x86_cpu_compat_set_features("Broadwell-IBRS", FEAT_7_0_EBX, ++ 0, CPUID_7_0_EBX_SMAP); + + /* RHEL-6 kernel never supported exposing RDTSCP */ + x86_cpu_compat_set_features(NULL, FEAT_8000_0001_EDX, 0, CPUID_EXT2_RDTSCP); +@@ -1122,6 +1137,8 @@ static void pc_compat_rhel630(QEMUMachineInitArgs *args) + enable_compat_apic_id_mode(); + x86_cpu_compat_set_features("SandyBridge", FEAT_1_ECX, + 0, CPUID_EXT_TSC_DEADLINE_TIMER); ++ x86_cpu_compat_set_features("SandyBridge-IBRS", FEAT_1_ECX, ++ 0, CPUID_EXT_TSC_DEADLINE_TIMER); + } + + static void pc_init_rhel630(QEMUMachineInitArgs *args) +diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c +index 850a25a..e6043df 100644 +--- a/hw/i386/pc_q35.c ++++ b/hw/i386/pc_q35.c +@@ -228,6 +228,7 @@ static void pc_q35_init_1_4(QEMUMachineInitArgs *args) + { + x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE); + x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ); ++ x86_cpu_compat_set_features("Westmere-IBRS", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ); + pc_q35_init_1_5(args); + } + +diff --git a/target-i386/cpu.c b/target-i386/cpu.c +index 335689b..08b43f5 100644 +--- a/target-i386/cpu.c ++++ b/target-i386/cpu.c +@@ -884,6 +884,31 @@ static x86_def_t builtin_x86_defs[] = { + .model_id = "Intel Core i7 9xx (Nehalem Class Core i7)", + }, + { ++ .name = "Nehalem-IBRS", ++ .level = 11, ++ .vendor = CPUID_VENDOR_INTEL, ++ .family = 6, ++ .model = 26, ++ .stepping = 3, ++ .features[FEAT_1_EDX] = ++ CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | ++ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | ++ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | ++ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | ++ CPUID_DE | CPUID_FP87, ++ .features[FEAT_1_ECX] = ++ CPUID_EXT_POPCNT | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 | ++ CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_SSE3, ++ .features[FEAT_7_0_EDX] = ++ CPUID_7_0_EDX_SPEC_CTRL, ++ .features[FEAT_8000_0001_EDX] = ++ CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX, ++ .features[FEAT_8000_0001_ECX] = ++ CPUID_EXT3_LAHF_LM, ++ .xlevel = 0x80000008, ++ .model_id = "Intel Core i7 9xx (Nehalem Core i7, IBRS update)", ++ }, ++ { + .name = "Westmere", + .level = 11, + .vendor = CPUID_VENDOR_INTEL, +@@ -908,6 +933,32 @@ static x86_def_t builtin_x86_defs[] = { + .model_id = "Westmere E56xx/L56xx/X56xx (Nehalem-C)", + }, + { ++ .name = "Westmere-IBRS", ++ .level = 11, ++ .vendor = CPUID_VENDOR_INTEL, ++ .family = 6, ++ .model = 44, ++ .stepping = 1, ++ .features[FEAT_1_EDX] = ++ CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | ++ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | ++ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | ++ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | ++ CPUID_DE | CPUID_FP87, ++ .features[FEAT_1_ECX] = ++ CPUID_EXT_AES | CPUID_EXT_POPCNT | CPUID_EXT_SSE42 | ++ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | ++ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3, ++ .features[FEAT_8000_0001_EDX] = ++ CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX, ++ .features[FEAT_8000_0001_ECX] = ++ CPUID_EXT3_LAHF_LM, ++ .features[FEAT_7_0_EDX] = ++ CPUID_7_0_EDX_SPEC_CTRL, ++ .xlevel = 0x80000008, ++ .model_id = "Westmere E56xx/L56xx/X56xx (IBRS update)", ++ }, ++ { + .name = "SandyBridge", + .level = 0xd, + .vendor = CPUID_VENDOR_INTEL, +@@ -937,6 +988,37 @@ static x86_def_t builtin_x86_defs[] = { + .model_id = "Intel Xeon E312xx (Sandy Bridge)", + }, + { ++ .name = "SandyBridge-IBRS", ++ .level = 0xd, ++ .vendor = CPUID_VENDOR_INTEL, ++ .family = 6, ++ .model = 42, ++ .stepping = 1, ++ .features[FEAT_1_EDX] = ++ CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | ++ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | ++ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | ++ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | ++ CPUID_DE | CPUID_FP87, ++ .features[FEAT_1_ECX] = ++ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES | ++ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_POPCNT | ++ CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 | ++ CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ | ++ CPUID_EXT_SSE3, ++ .features[FEAT_8000_0001_EDX] = ++ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX | ++ CPUID_EXT2_SYSCALL, ++ .features[FEAT_8000_0001_ECX] = ++ CPUID_EXT3_LAHF_LM, ++ .features[FEAT_7_0_EDX] = ++ CPUID_7_0_EDX_SPEC_CTRL, ++ .features[FEAT_XSAVE] = ++ CPUID_XSAVE_XSAVEOPT, ++ .xlevel = 0x80000008, ++ .model_id = "Intel Xeon E312xx (Sandy Bridge, IBRS update)", ++ }, ++ { + .name = "IvyBridge", + .level = 0xd, + .vendor = CPUID_VENDOR_INTEL, +@@ -969,6 +1051,40 @@ static x86_def_t builtin_x86_defs[] = { + .model_id = "Intel Xeon E3-12xx v2 (Ivy Bridge)", + }, + { ++ .name = "IvyBridge-IBRS", ++ .level = 0xd, ++ .vendor = CPUID_VENDOR_INTEL, ++ .family = 6, ++ .model = 58, ++ .stepping = 9, ++ .features[FEAT_1_EDX] = ++ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | ++ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | ++ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | ++ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | ++ CPUID_DE | CPUID_FP87, ++ .features[FEAT_1_ECX] = ++ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES | ++ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_POPCNT | ++ CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 | ++ CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ | ++ CPUID_EXT_SSE3 | CPUID_EXT_F16C | CPUID_EXT_RDRAND, ++ .features[FEAT_7_0_EBX] = ++ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_SMEP | ++ CPUID_7_0_EBX_ERMS, ++ .features[FEAT_8000_0001_EDX] = ++ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX | ++ CPUID_EXT2_SYSCALL, ++ .features[FEAT_8000_0001_ECX] = ++ CPUID_EXT3_LAHF_LM, ++ .features[FEAT_7_0_EDX] = ++ CPUID_7_0_EDX_SPEC_CTRL, ++ .features[FEAT_XSAVE] = ++ CPUID_XSAVE_XSAVEOPT, ++ .xlevel = 0x80000008, ++ .model_id = "Intel Xeon E3-12xx v2 (Ivy Bridge, IBRS)", ++ }, ++ { + .name = "Haswell", + .level = 0xd, + .vendor = CPUID_VENDOR_INTEL, +@@ -1004,6 +1120,43 @@ static x86_def_t builtin_x86_defs[] = { + .model_id = "Intel Core Processor (Haswell)", + }, + { ++ .name = "Haswell-IBRS", ++ .level = 0xd, ++ .vendor = CPUID_VENDOR_INTEL, ++ .family = 6, ++ .model = 60, ++ .stepping = 4, ++ .features[FEAT_1_EDX] = ++ CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | ++ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | ++ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | ++ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | ++ CPUID_DE | CPUID_FP87, ++ .features[FEAT_1_ECX] = ++ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES | ++ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | ++ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | ++ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 | ++ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE | ++ CPUID_EXT_PCID, ++ .features[FEAT_8000_0001_EDX] = ++ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX | ++ CPUID_EXT2_SYSCALL, ++ .features[FEAT_8000_0001_ECX] = ++ CPUID_EXT3_LAHF_LM, ++ .features[FEAT_7_0_EDX] = ++ CPUID_7_0_EDX_SPEC_CTRL, ++ .features[FEAT_7_0_EBX] = ++ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | ++ CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | ++ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | ++ CPUID_7_0_EBX_RTM, ++ .features[FEAT_XSAVE] = ++ CPUID_XSAVE_XSAVEOPT, ++ .xlevel = 0x80000008, ++ .model_id = "Intel Core Processor (Haswell, IBRS)", ++ }, ++ { + .name = "Broadwell", + .level = 0xd, + .vendor = CPUID_VENDOR_INTEL, +@@ -1040,6 +1193,44 @@ static x86_def_t builtin_x86_defs[] = { + .model_id = "Intel Core Processor (Broadwell)", + }, + { ++ .name = "Broadwell-IBRS", ++ .level = 0xd, ++ .vendor = CPUID_VENDOR_INTEL, ++ .family = 6, ++ .model = 61, ++ .stepping = 2, ++ .features[FEAT_1_EDX] = ++ CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | ++ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | ++ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | ++ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | ++ CPUID_DE | CPUID_FP87, ++ .features[FEAT_1_ECX] = ++ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES | ++ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | ++ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | ++ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 | ++ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE | ++ CPUID_EXT_PCID, ++ .features[FEAT_8000_0001_EDX] = ++ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX | ++ CPUID_EXT2_SYSCALL, ++ .features[FEAT_8000_0001_ECX] = ++ CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH, ++ .features[FEAT_7_0_EDX] = ++ CPUID_7_0_EDX_SPEC_CTRL, ++ .features[FEAT_7_0_EBX] = ++ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | ++ CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | ++ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | ++ CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | ++ CPUID_7_0_EBX_SMAP, ++ .features[FEAT_XSAVE] = ++ CPUID_XSAVE_XSAVEOPT, ++ .xlevel = 0x80000008, ++ .model_id = "Intel Core Processor (Broadwell, IBRS)", ++ }, ++ { + .name = "Skylake-Client", + .level = 0xd, + .vendor = CPUID_VENDOR_INTEL, +@@ -1083,6 +1274,51 @@ static x86_def_t builtin_x86_defs[] = { + .model_id = "Intel Core Processor (Skylake)", + }, + { ++ .name = "Skylake-Client-IBRS", ++ .level = 0xd, ++ .vendor = CPUID_VENDOR_INTEL, ++ .family = 6, ++ .model = 94, ++ .stepping = 3, ++ .features[FEAT_1_EDX] = ++ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | ++ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | ++ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | ++ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | ++ CPUID_DE | CPUID_FP87, ++ .features[FEAT_1_ECX] = ++ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES | ++ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | ++ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | ++ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 | ++ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE | ++ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND, ++ .features[FEAT_8000_0001_EDX] = ++ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX | ++ CPUID_EXT2_SYSCALL, ++ .features[FEAT_8000_0001_ECX] = ++ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH, ++ .features[FEAT_7_0_EDX] = ++ CPUID_7_0_EDX_SPEC_CTRL, ++ .features[FEAT_7_0_EBX] = ++ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | ++ CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | ++ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | ++ CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | ++ CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_MPX, ++ /* Missing: XSAVES (not supported by some Linux versions, ++ * including v4.1 to v4.12). ++ * KVM doesn't yet expose any XSAVES state save component, ++ * and the only one defined in Skylake (processor tracing) ++ * probably will block migration anyway. ++ */ ++ .features[FEAT_XSAVE] = ++ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | ++ CPUID_XSAVE_XGETBV1, ++ .xlevel = 0x80000008, ++ .model_id = "Intel Core Processor (Skylake, IBRS)", ++ }, ++ { + .name = "Skylake-Server", + .level = 0xd, + .vendor = CPUID_VENDOR_INTEL, +@@ -1133,6 +1369,54 @@ static x86_def_t builtin_x86_defs[] = { + .model_id = "Intel Xeon Processor (Skylake)", + }, + { ++ .name = "Skylake-Server-IBRS", ++ .level = 0xd, ++ .vendor = CPUID_VENDOR_INTEL, ++ .family = 6, ++ .model = 85, ++ .stepping = 4, ++ .features[FEAT_1_EDX] = ++ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | ++ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | ++ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | ++ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | ++ CPUID_DE | CPUID_FP87, ++ .features[FEAT_1_ECX] = ++ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES | ++ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | ++ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | ++ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 | ++ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE | ++ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND, ++ .features[FEAT_8000_0001_EDX] = ++ CPUID_EXT2_LM | CPUID_EXT2_PDPE1GB | CPUID_EXT2_RDTSCP | ++ CPUID_EXT2_NX | CPUID_EXT2_SYSCALL, ++ .features[FEAT_8000_0001_ECX] = ++ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH, ++ .features[FEAT_7_0_EDX] = ++ CPUID_7_0_EDX_SPEC_CTRL, ++ .features[FEAT_7_0_EBX] = ++ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | ++ CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | ++ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | ++ CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | ++ CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_CLWB | ++ CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512DQ | ++ CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512CD | ++ CPUID_7_0_EBX_AVX512VL, ++ /* Missing: XSAVES (not supported by some Linux versions, ++ * including v4.1 to v4.12). ++ * KVM doesn't yet expose any XSAVES state save component, ++ * and the only one defined in Skylake (processor tracing) ++ * probably will block migration anyway. ++ */ ++ .features[FEAT_XSAVE] = ++ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | ++ CPUID_XSAVE_XGETBV1, ++ .xlevel = 0x80000008, ++ .model_id = "Intel Xeon Processor (Skylake, IBRS)", ++ }, ++ { + .name = "Opteron_G1", + .level = 5, + .vendor = CPUID_VENDOR_AMD, +@@ -1332,6 +1616,50 @@ static x86_def_t builtin_x86_defs[] = { + .xlevel = 0x8000000A, + .model_id = "AMD EPYC Processor", + }, ++ { ++ .name = "EPYC-IBPB", ++ .level = 0xd, ++ .vendor = CPUID_VENDOR_AMD, ++ .family = 23, ++ .model = 1, ++ .stepping = 2, ++ .features[FEAT_1_EDX] = ++ CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | CPUID_CLFLUSH | ++ CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | CPUID_PGE | ++ CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | CPUID_MCE | ++ CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | CPUID_DE | ++ CPUID_VME | CPUID_FP87, ++ .features[FEAT_1_ECX] = ++ CPUID_EXT_RDRAND | CPUID_EXT_F16C | CPUID_EXT_AVX | ++ CPUID_EXT_XSAVE | CPUID_EXT_AES | CPUID_EXT_POPCNT | ++ CPUID_EXT_MOVBE | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 | ++ CPUID_EXT_CX16 | CPUID_EXT_FMA | CPUID_EXT_SSSE3 | ++ CPUID_EXT_MONITOR | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3, ++ .features[FEAT_8000_0001_EDX] = ++ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_PDPE1GB | ++ CPUID_EXT2_FFXSR | CPUID_EXT2_MMXEXT | CPUID_EXT2_NX | ++ CPUID_EXT2_SYSCALL, ++ .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, ++ .features[FEAT_8000_0008_EBX] = ++ CPUID_8000_0008_EBX_IBPB, ++ .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 | ++ CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLFLUSHOPT | ++ CPUID_7_0_EBX_SHA_NI, ++ /* Missing: XSAVES (not supported by some Linux versions, ++ * including v4.1 to v4.12). ++ * KVM doesn't yet expose any XSAVES state save component. ++ */ ++ .features[FEAT_XSAVE] = ++ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | ++ CPUID_XSAVE_XGETBV1, ++ .xlevel = 0x8000000A, ++ .model_id = "AMD EPYC Processor (with IBPB)", ++ }, + }; + + /** +diff --git a/target-i386/cpu.h b/target-i386/cpu.h +index 7d815cd..a8a640a 100644 +--- a/target-i386/cpu.h ++++ b/target-i386/cpu.h +@@ -589,6 +589,9 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; + + #define CPUID_7_0_EDX_AVX512_4VNNIW (1U << 2) /* AVX512 Neural Network Instructions */ + #define CPUID_7_0_EDX_AVX512_4FMAPS (1U << 3) /* AVX512 Multiply Accumulation Single Precision */ ++#define CPUID_7_0_EDX_SPEC_CTRL (1U << 26) /* Indirect Branch - Restrict Speculation */ ++ ++#define CPUID_8000_0008_EBX_IBPB (1U << 12) /* Indirect Branch Prediction Barrier */ + + #define CPUID_7_0_ECX_PKU (1U << 3) + #define CPUID_7_0_ECX_OSPKE (1U << 4) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-target-i386-cpu-add-new-CPUID-bits-for-indirect-bran.patch b/SOURCES/kvm-target-i386-cpu-add-new-CPUID-bits-for-indirect-bran.patch new file mode 100644 index 0000000..38fadcb --- /dev/null +++ b/SOURCES/kvm-target-i386-cpu-add-new-CPUID-bits-for-indirect-bran.patch @@ -0,0 +1,78 @@ +From 151cbf5d444ab746d05dc0757ec972df8880d0ec Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Wed, 13 Dec 2017 15:43:39 -0200 +Subject: [PATCH 1/3] target-i386: cpu: add new CPUID bits for indirect branch + predictor restrictions + +RH-Author: Eduardo Habkost +Message-id: <20171213174341.20684-2-ehabkost@redhat.com> +Patchwork-id: n/a +O-Subject: [CONFIDENTIAL][RHEL-7.5 qemu-kvm PATCH v2 1/3] target-i386: cpu: + add new CPUID bits for indirect branch predictor restrictions +Bugzilla: CVE-2017-5715 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Miroslav Rezanina +--- + target-i386/cpu.c | 19 ++++++++++++++++++- + target-i386/cpu.h | 1 + + 2 files changed, 19 insertions(+), 1 deletion(-) + +diff --git a/target-i386/cpu.c b/target-i386/cpu.c +index 539d659..335689b 100644 +--- a/target-i386/cpu.c ++++ b/target-i386/cpu.c +@@ -172,6 +172,17 @@ static const char *cpuid_7_0_edx_feature_name[] = { + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, ++ NULL, NULL, "spec-ctrl", "stibp", ++ NULL, "arch-facilities", NULL, NULL, ++}; ++ ++static const char *cpuid_80000008_ebx_feature_name[] = { ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ "ibpb", NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }; +@@ -314,6 +325,12 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + .cpuid_reg = R_EDX, + .tcg_features = TCG_7_0_EDX_FEATURES, + }, ++ [FEAT_8000_0008_EBX] = { ++ .feat_names = cpuid_80000008_ebx_feature_name, ++ .cpuid_eax = 0x80000008, ++ .cpuid_needs_ecx = false, .cpuid_ecx = 0, ++ .cpuid_reg = R_EBX, ++ }, + [FEAT_XSAVE] = { + .feat_names = cpuid_xsave_feature_name, + .cpuid_eax = 0xd, +@@ -2470,7 +2487,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + *eax = 0x00000020; /* 32 bits physical */ + } + } +- *ebx = 0; ++ *ebx = env->features[FEAT_8000_0008_EBX]; + *ecx = 0; + *edx = 0; + if (cs->nr_cores * cs->nr_threads > 1) { +diff --git a/target-i386/cpu.h b/target-i386/cpu.h +index 78b8072..1e5c980 100644 +--- a/target-i386/cpu.h ++++ b/target-i386/cpu.h +@@ -406,6 +406,7 @@ typedef enum FeatureWord { + FEAT_7_0_EDX, /* CPUID[EAX=7,ECX=0].EDX */ + FEAT_8000_0001_EDX, /* CPUID[8000_0001].EDX */ + FEAT_8000_0001_ECX, /* CPUID[8000_0001].ECX */ ++ FEAT_8000_0008_EBX, /* CPUID[8000_0008].EBX */ + FEAT_C000_0001_EDX, /* CPUID[C000_0001].EDX */ + FEAT_KVM, /* CPUID[4000_0001].EAX (KVM_CPUID_FEATURES) */ + FEAT_SVM, /* CPUID[8000_000A].EDX */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-ui-avoid-pointless-VNC-updates-if-framebuffer-isn-t-.patch b/SOURCES/kvm-ui-avoid-pointless-VNC-updates-if-framebuffer-isn-t-.patch new file mode 100644 index 0000000..1007023 --- /dev/null +++ b/SOURCES/kvm-ui-avoid-pointless-VNC-updates-if-framebuffer-isn-t-.patch @@ -0,0 +1,54 @@ +From cbfdbd7430e27c24d55b880144d5df05ef949417 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:31 +0100 +Subject: [PATCH 17/27] ui: avoid pointless VNC updates if framebuffer isn't + dirty +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-18-berrange@redhat.com> +Patchwork-id: 78946 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 17/27] ui: avoid pointless VNC updates if framebuffer isn't dirty +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +From: "Daniel P. Berrange" + +The vnc_update_client() method checks the 'has_dirty' flag to see if there are +dirty regions that are pending to send to the client. Regardless of this flag, +if a forced update is requested, updates must be sent. For unknown reasons +though, the code also tries to sent updates if audio capture is enabled. This +makes no sense as audio capture state does not impact framebuffer contents, so +this check is removed. + +Signed-off-by: Daniel P. Berrange +Reviewed-by: Darren Kenny +Reviewed-by: Marc-André Lureau +Message-id: 20171218191228.31018-5-berrange@redhat.com +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 3541b08475d51bddf8aded36576a0ff5a547a978) +Signed-off-by: Miroslav Rezanina +--- + ui/vnc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ui/vnc.c b/ui/vnc.c +index aebaa37..eea5702 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -869,7 +869,7 @@ static int vnc_update_client(VncState *vs, int has_dirty) + return 0; + } + +- if (!vs->has_dirty && !vs->audio_cap && !vs->force_update) { ++ if (!vs->has_dirty && !vs->force_update) { + return 0; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-ui-avoid-sign-extension-using-client-width-height.patch b/SOURCES/kvm-ui-avoid-sign-extension-using-client-width-height.patch new file mode 100644 index 0000000..c5b8cbb --- /dev/null +++ b/SOURCES/kvm-ui-avoid-sign-extension-using-client-width-height.patch @@ -0,0 +1,115 @@ +From 023a741e196fd99b532f69df9560730425b174a0 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:39 +0100 +Subject: [PATCH 25/27] ui: avoid sign extension using client width/height + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-26-berrange@redhat.com> +Patchwork-id: 78960 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 25/27] ui: avoid sign extension using client width/height +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +From: "Daniel P. Berrange" + +Pixman returns a signed int for the image width/height, but the VNC +protocol only permits a unsigned int16. Effective framebuffer size +is determined by the guest, limited by the video RAM size, so the +dimensions are unlikely to exceed the range of an unsigned int16, +but this is not currently validated. + +With the current use of 'int' for client width/height, the calculation +of offsets in vnc_update_throttle_offset() suffers from integer size +promotion and sign extension, causing coverity warnings + +*** CID 1385147: Integer handling issues (SIGN_EXTENSION) +/ui/vnc.c: 979 in vnc_update_throttle_offset() +973 * than that the client would already suffering awful audio +974 * glitches, so dropping samples is no worse really). +975 */ +976 static void vnc_update_throttle_offset(VncState *vs) +977 { +978 size_t offset = +>>> CID 1385147: Integer handling issues (SIGN_EXTENSION) +>>> Suspicious implicit sign extension: + "vs->client_pf.bytes_per_pixel" with type "unsigned char" (8 bits, + unsigned) is promoted in "vs->client_width * vs->client_height * + vs->client_pf.bytes_per_pixel" to type "int" (32 bits, signed), then + sign-extended to type "unsigned long" (64 bits, unsigned). If + "vs->client_width * vs->client_height * vs->client_pf.bytes_per_pixel" + is greater than 0x7FFFFFFF, the upper bits of the result will all be 1. +979 vs->client_width * vs->client_height * vs->client_pf.bytes_per_pixel; + +Change client_width / client_height to be a size_t to avoid sign +extension and integer promotion. Then validate that dimensions are in +range wrt the RFB protocol u16 limits. + +Signed-off-by: Daniel P. Berrange +Message-id: 20180118155254.17053-1-berrange@redhat.com +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 4c956bd81e2e16afd19d38d1fdeba6d9faa8a1ae) + + Conflicts: + ui/vnc.c + ui/vnc.h - context differences + +RHEL-7 note: The context difference in VncState is because downstream +lacks commit 14768eba46e4 ("input: mouse: switch vnc ui to new core", +2014-03-05), part of v2.0.0. The context difference in +protocol_client_init() is because downstream lacks e5f34cdd2da5 ("vnc: +track & limit connections", 2015-01-22), part of v2.3.0. Neither +upstream commit is necessary for this backport. + +Signed-off-by: Miroslav Rezanina +--- + ui/vnc.c | 9 +++++++++ + ui/vnc.h | 4 ++-- + 2 files changed, 11 insertions(+), 2 deletions(-) + +diff --git a/ui/vnc.c b/ui/vnc.c +index 61fbec2..2be87b8 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -570,6 +570,11 @@ static void vnc_desktop_resize(VncState *vs) + vs->client_height == pixman_image_get_height(vs->vd->server)) { + return; + } ++ ++ assert(pixman_image_get_width(vs->vd->server) < 65536 && ++ pixman_image_get_width(vs->vd->server) >= 0); ++ assert(pixman_image_get_height(vs->vd->server) < 65536 && ++ pixman_image_get_height(vs->vd->server) >= 0); + vs->client_width = pixman_image_get_width(vs->vd->server); + vs->client_height = pixman_image_get_height(vs->vd->server); + vnc_lock_output(vs); +@@ -2387,6 +2392,10 @@ static int protocol_client_init(VncState *vs, uint8_t *data, size_t len) + } + vnc_set_share_mode(vs, mode); + ++ assert(pixman_image_get_width(vs->vd->server) < 65536 && ++ pixman_image_get_width(vs->vd->server) >= 0); ++ assert(pixman_image_get_height(vs->vd->server) < 65536 && ++ pixman_image_get_height(vs->vd->server) >= 0); + vs->client_width = pixman_image_get_width(vs->vd->server); + vs->client_height = pixman_image_get_height(vs->vd->server); + vnc_write_u16(vs, vs->client_width); +diff --git a/ui/vnc.h b/ui/vnc.h +index 70316ba..f9c5f89 100644 +--- a/ui/vnc.h ++++ b/ui/vnc.h +@@ -274,8 +274,8 @@ struct VncState + int absolute; + int last_x; + int last_y; +- int client_width; +- int client_height; ++ size_t client_width; /* limited to u16 by RFB proto */ ++ size_t client_height; /* limited to u16 by RFB proto */ + VncShareMode share_mode; + + uint32_t vnc_encoding; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-ui-correctly-advance-output-buffer-when-writing-SASL.patch b/SOURCES/kvm-ui-correctly-advance-output-buffer-when-writing-SASL.patch new file mode 100644 index 0000000..98853de --- /dev/null +++ b/SOURCES/kvm-ui-correctly-advance-output-buffer-when-writing-SASL.patch @@ -0,0 +1,66 @@ +From 1bf158dc510fc63f11725f2350369d06a3fff929 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:40 +0100 +Subject: [PATCH 26/27] ui: correctly advance output buffer when writing SASL + data +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-27-berrange@redhat.com> +Patchwork-id: 78955 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 26/27] ui: correctly advance output buffer when writing SASL data +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +In this previous commit: + + commit 8f61f1c5a6bc06438a1172efa80bc7606594fa07 + Author: Daniel P. Berrange + Date: Mon Dec 18 19:12:20 2017 +0000 + + ui: track how much decoded data we consumed when doing SASL encoding + +I attempted to fix a flaw with tracking how much data had actually been +processed when encoding with SASL. With that flaw, the VNC server could +mistakenly discard queued data that had not been sent. + +The fix was not quite right though, because it merely decremented the +vs->output.offset value. This is effectively discarding data from the +end of the pending output buffer. We actually need to discard data from +the start of the pending output buffer. We also want to free memory that +is no longer required. The correct way to handle this is to use the +buffer_advance() helper method instead of directly manipulating the +offset value. + +Reported-by: Laszlo Ersek +Signed-off-by: Daniel P. Berrangé +Reviewed-by: Eric Blake +Reviewed-by: Laszlo Ersek +Message-id: 20180201155841.27509-1-berrange@redhat.com +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 627ebec208a8809818589e17f4fce55a59420ad2) +Signed-off-by: Miroslav Rezanina +--- + ui/vnc-auth-sasl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c +index 8188081..c39f588 100644 +--- a/ui/vnc-auth-sasl.c ++++ b/ui/vnc-auth-sasl.c +@@ -81,7 +81,7 @@ long vnc_client_write_sasl(VncState *vs) + } else { + vs->force_update_offset -= vs->sasl.encodedRawLength; + } +- vs->output.offset -= vs->sasl.encodedRawLength; ++ buffer_advance(&vs->output, vs->sasl.encodedRawLength); + vs->sasl.encoded = NULL; + vs->sasl.encodedOffset = vs->sasl.encodedLength = 0; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-ui-correctly-reset-framebuffer-update-state-after-pr.patch b/SOURCES/kvm-ui-correctly-reset-framebuffer-update-state-after-pr.patch new file mode 100644 index 0000000..945a3aa --- /dev/null +++ b/SOURCES/kvm-ui-correctly-reset-framebuffer-update-state-after-pr.patch @@ -0,0 +1,62 @@ +From 3d48415578c65490675616d41a32a1e9e3a71f43 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:34 +0100 +Subject: [PATCH 20/27] ui: correctly reset framebuffer update state after + processing dirty regions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-21-berrange@redhat.com> +Patchwork-id: 78941 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 20/27] ui: correctly reset framebuffer update state after processing dirty regions +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +From: "Daniel P. Berrange" + +According to the RFB protocol, a client sends one or more framebuffer update +requests to the server. The server can reply with a single framebuffer update +response, that covers all previously received requests. Once the client has +read this update from the server, it may send further framebuffer update +requests to monitor future changes. The client is free to delay sending the +framebuffer update request if it needs to throttle the amount of data it is +reading from the server. + +The QEMU VNC server, however, has never correctly handled the framebuffer +update requests. Once QEMU has received an update request, it will continue to +send client updates forever, even if the client hasn't asked for further +updates. This prevents the client from throttling back data it gets from the +server. This change fixes the flawed logic such that after a set of updates are +sent out, QEMU waits for a further update request before sending more data. + +Signed-off-by: Daniel P. Berrange +Reviewed-by: Darren Kenny +Reviewed-by: Marc-André Lureau +Message-id: 20171218191228.31018-8-berrange@redhat.com +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 728a7ac95484a7ba5e624ccbac4c1326571576b0) +Signed-off-by: Miroslav Rezanina +--- + ui/vnc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ui/vnc.c b/ui/vnc.c +index 7239602..075def1 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -910,7 +910,7 @@ static int vnc_update_client(VncState *vs, int has_dirty) + } + + vnc_job_push(job); +- vs->update = VNC_STATE_UPDATE_INCREMENTAL; ++ vs->update = VNC_STATE_UPDATE_NONE; + vs->has_dirty = 0; + return n; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-ui-fix-VNC-client-throttling-when-audio-capture-is-a.patch b/SOURCES/kvm-ui-fix-VNC-client-throttling-when-audio-capture-is-a.patch new file mode 100644 index 0000000..ec38157 --- /dev/null +++ b/SOURCES/kvm-ui-fix-VNC-client-throttling-when-audio-capture-is-a.patch @@ -0,0 +1,228 @@ +From a12ad57f4b108dc98987b2002169ccfbbd76721d Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:36 +0100 +Subject: [PATCH 22/27] ui: fix VNC client throttling when audio capture is + active +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-23-berrange@redhat.com> +Patchwork-id: 78958 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 22/27] ui: fix VNC client throttling when audio capture is active +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +From: "Daniel P. Berrange" + +The VNC server must throttle data sent to the client to prevent the 'output' +buffer size growing without bound, if the client stops reading data off the +socket (either maliciously or due to stalled/slow network connection). + +The current throttling is very crude because it simply checks whether the +output buffer offset is zero. This check must be disabled if audio capture is +enabled, because when streaming audio the output buffer offset will rarely be +zero due to queued audio data, and so this would starve framebuffer updates. + +As a result, the VNC client can cause QEMU to allocate arbitrary amounts of RAM. +They can first start something in the guest that triggers lots of framebuffer +updates eg play a youtube video. Then enable audio capture, and simply never +read data back from the server. This can easily make QEMU's VNC server send +buffer consume 100MB of RAM per second, until the OOM killer starts reaping +processes (hopefully the rogue QEMU process, but it might pick others...). + +To address this we make the throttling more intelligent, so we can throttle +when audio capture is active too. To determine how to throttle incremental +updates or audio data, we calculate a size threshold. Normally the threshold is +the approximate number of bytes associated with a single complete framebuffer +update. ie width * height * bytes per pixel. We'll send incremental updates +until we hit this threshold, at which point we'll stop sending updates until +data has been written to the wire, causing the output buffer offset to fall +back below the threshold. + +If audio capture is enabled, we increase the size of the threshold to also +allow for upto 1 seconds worth of audio data samples. ie nchannels * bytes +per sample * frequency. This allows the output buffer to have a mixture of +incremental framebuffer updates and audio data queued, but once the threshold +is exceeded, audio data will be dropped and incremental updates will be +throttled. + +This unbounded memory growth affects all VNC server configurations supported by +QEMU, with no workaround possible. The mitigating factor is that it can only be +triggered by a client that has authenticated with the VNC server, and who is +able to trigger a large quantity of framebuffer updates or audio samples from +the guest OS. Mostly they'll just succeed in getting the OOM killer to kill +their own QEMU process, but its possible other processes can get taken out as +collateral damage. + +This is a more general variant of the similar unbounded memory usage flaw in +the websockets server, that was previously assigned CVE-2017-15268, and fixed +in 2.11 by: + + commit a7b20a8efa28e5f22c26c06cd06c2f12bc863493 + Author: Daniel P. Berrange + Date: Mon Oct 9 14:43:42 2017 +0100 + + io: monitor encoutput buffer size from websocket GSource + +This new general memory usage flaw has been assigned CVE-2017-15124, and is +partially fixed by this patch. + +RHEL-7 note: minimal context differences in "struct VncState" due to +downstream lacking (a) commit fb6ba0d5256c ("qapi event: convert VNC +events", 2014-06-23), part of v2.1.0, and (b) commit 8e9b0d24fb98 ("ui: +convert VNC websockets to use crypto APIs", 2015-07-08), part of v2.4.0. + +Signed-off-by: Daniel P. Berrange +Reviewed-by: Darren Kenny +Reviewed-by: Marc-André Lureau +Message-id: 20171218191228.31018-10-berrange@redhat.com +Signed-off-by: Gerd Hoffmann +(cherry picked from commit e2b72cb6e0443d90d7ab037858cb6834b6cca852) +Signed-off-by: Miroslav Rezanina +--- + ui/vnc.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- + ui/vnc.h | 6 ++++++ + 2 files changed, 70 insertions(+), 8 deletions(-) + +diff --git a/ui/vnc.c b/ui/vnc.c +index a7ec8cc..952a051 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -47,6 +47,7 @@ static VncDisplay *vnc_display; /* needed for info vnc */ + + static int vnc_cursor_define(VncState *vs); + static void vnc_release_modifiers(VncState *vs); ++static void vnc_update_throttle_offset(VncState *vs); + + static void vnc_set_share_mode(VncState *vs, VncShareMode mode) + { +@@ -664,6 +665,7 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl, + vnc_set_area_dirty(vs->dirty, vd, 0, 0, + vnc_width(vd), + vnc_height(vd)); ++ vnc_update_throttle_offset(vs); + } + } + +@@ -846,16 +848,67 @@ static int find_and_clear_dirty_height(struct VncState *vs, + return h; + } + ++/* ++ * Figure out how much pending data we should allow in the output ++ * buffer before we throttle incremental display updates, and/or ++ * drop audio samples. ++ * ++ * We allow for equiv of 1 full display's worth of FB updates, ++ * and 1 second of audio samples. If audio backlog was larger ++ * than that the client would already suffering awful audio ++ * glitches, so dropping samples is no worse really). ++ */ ++static void vnc_update_throttle_offset(VncState *vs) ++{ ++ size_t offset = ++ vs->client_width * vs->client_height * vs->client_pf.bytes_per_pixel; ++ ++ if (vs->audio_cap) { ++ int freq = vs->as.freq; ++ /* We don't limit freq when reading settings from client, so ++ * it could be upto MAX_INT in size. 48khz is a sensible ++ * upper bound for trustworthy clients */ ++ int bps; ++ if (freq > 48000) { ++ freq = 48000; ++ } ++ switch (vs->as.fmt) { ++ default: ++ case AUD_FMT_U8: ++ case AUD_FMT_S8: ++ bps = 1; ++ break; ++ case AUD_FMT_U16: ++ case AUD_FMT_S16: ++ bps = 2; ++ break; ++ case AUD_FMT_U32: ++ case AUD_FMT_S32: ++ bps = 4; ++ break; ++ } ++ offset += freq * bps * vs->as.nchannels; ++ } ++ ++ /* Put a floor of 1MB on offset, so that if we have a large pending ++ * buffer and the display is resized to a small size & back again ++ * we don't suddenly apply a tiny send limit ++ */ ++ offset = MAX(offset, 1024 * 1024); ++ ++ vs->throttle_output_offset = offset; ++} ++ + static bool vnc_should_update(VncState *vs) + { + switch (vs->update) { + case VNC_STATE_UPDATE_NONE: + break; + case VNC_STATE_UPDATE_INCREMENTAL: +- /* Only allow incremental updates if the output buffer +- * is empty, or if audio capture is enabled. ++ /* Only allow incremental updates if the pending send queue ++ * is less than the permitted threshold + */ +- if (!vs->output.offset || vs->audio_cap) { ++ if (vs->output.offset < vs->throttle_output_offset) { + return true; + } + break; +@@ -963,11 +1016,13 @@ static void audio_capture(void *opaque, void *buf, int size) + VncState *vs = opaque; + + vnc_lock_output(vs); +- vnc_write_u8(vs, VNC_MSG_SERVER_QEMU); +- vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO); +- vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_DATA); +- vnc_write_u32(vs, size); +- vnc_write(vs, buf, size); ++ if (vs->output.offset < vs->throttle_output_offset) { ++ vnc_write_u8(vs, VNC_MSG_SERVER_QEMU); ++ vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO); ++ vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_DATA); ++ vnc_write_u32(vs, size); ++ vnc_write(vs, buf, size); ++ } + vnc_unlock_output(vs); + vnc_flush(vs); + } +@@ -2214,6 +2269,7 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) + break; + } + ++ vnc_update_throttle_offset(vs); + vnc_read_when(vs, protocol_client_msg, 1); + return 0; + } +diff --git a/ui/vnc.h b/ui/vnc.h +index f19fd0a..d7eede3 100644 +--- a/ui/vnc.h ++++ b/ui/vnc.h +@@ -301,6 +301,12 @@ struct VncState + + QObject *info; + ++ /* We allow multiple incremental updates or audio capture ++ * samples to be queued in output buffer, provided the ++ * buffer size doesn't exceed this threshold. The value ++ * is calculating dynamically based on framebuffer size ++ * and audio sample settings in vnc_update_throttle_offset() */ ++ size_t throttle_output_offset; + Buffer output; + Buffer input; + #ifdef CONFIG_VNC_WS +-- +1.8.3.1 + diff --git a/SOURCES/kvm-ui-fix-VNC-client-throttling-when-forced-update-is-r.patch b/SOURCES/kvm-ui-fix-VNC-client-throttling-when-forced-update-is-r.patch new file mode 100644 index 0000000..aecf6a0 --- /dev/null +++ b/SOURCES/kvm-ui-fix-VNC-client-throttling-when-forced-update-is-r.patch @@ -0,0 +1,207 @@ +From 0f463c3d8c457d6a0bf3b91e48fc4e9162061cf6 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:37 +0100 +Subject: [PATCH 23/27] ui: fix VNC client throttling when forced update is + requested +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-24-berrange@redhat.com> +Patchwork-id: 78949 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 23/27] ui: fix VNC client throttling when forced update is requested +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +From: "Daniel P. Berrange" + +The VNC server must throttle data sent to the client to prevent the 'output' +buffer size growing without bound, if the client stops reading data off the +socket (either maliciously or due to stalled/slow network connection). + +The current throttling is very crude because it simply checks whether the +output buffer offset is zero. This check is disabled if the client has requested +a forced update, because we want to send these as soon as possible. + +As a result, the VNC client can cause QEMU to allocate arbitrary amounts of RAM. +They can first start something in the guest that triggers lots of framebuffer +updates eg play a youtube video. Then repeatedly send full framebuffer update +requests, but never read data back from the server. This can easily make QEMU's +VNC server send buffer consume 100MB of RAM per second, until the OOM killer +starts reaping processes (hopefully the rogue QEMU process, but it might pick +others...). + +To address this we make the throttling more intelligent, so we can throttle +full updates. When we get a forced update request, we keep track of exactly how +much data we put on the output buffer. We will not process a subsequent forced +update request until this data has been fully sent on the wire. We always allow +one forced update request to be in flight, regardless of what data is queued +for incremental updates or audio data. The slight complication is that we do +not initially know how much data an update will send, as this is done in the +background by the VNC job thread. So we must track the fact that the job thread +has an update pending, and not process any further updates until this job is +has been completed & put data on the output buffer. + +This unbounded memory growth affects all VNC server configurations supported by +QEMU, with no workaround possible. The mitigating factor is that it can only be +triggered by a client that has authenticated with the VNC server, and who is +able to trigger a large quantity of framebuffer updates or audio samples from +the guest OS. Mostly they'll just succeed in getting the OOM killer to kill +their own QEMU process, but its possible other processes can get taken out as +collateral damage. + +This is a more general variant of the similar unbounded memory usage flaw in +the websockets server, that was previously assigned CVE-2017-15268, and fixed +in 2.11 by: + + commit a7b20a8efa28e5f22c26c06cd06c2f12bc863493 + Author: Daniel P. Berrange + Date: Mon Oct 9 14:43:42 2017 +0100 + + io: monitor encoutput buffer size from websocket GSource + +This new general memory usage flaw has been assigned CVE-2017-15124, and is +partially fixed by this patch. + +RHEL-7 note: context differences in "struct VncState" and +vnc_jobs_consume_buffer() due to downstream lacking (a) commit +fb6ba0d5256c ("qapi event: convert VNC events", 2014-06-23), part of +v2.1.0, and (b) commit 04d2529da27d ("ui: convert VNC server to use +QIOChannelSocket", 2015-12-18), part of v2.6.0. + +Signed-off-by: Daniel P. Berrange +Reviewed-by: Darren Kenny +Reviewed-by: Marc-André Lureau +Message-id: 20171218191228.31018-11-berrange@redhat.com +Signed-off-by: Gerd Hoffmann +(cherry picked from commit ada8d2e4369ea49677d8672ac81bce73eefd5b54) +Signed-off-by: Miroslav Rezanina +--- + ui/vnc-auth-sasl.c | 5 +++++ + ui/vnc-jobs.c | 5 +++++ + ui/vnc.c | 28 ++++++++++++++++++++++++---- + ui/vnc.h | 7 +++++++ + 4 files changed, 41 insertions(+), 4 deletions(-) + +diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c +index 804b8e7..8188081 100644 +--- a/ui/vnc-auth-sasl.c ++++ b/ui/vnc-auth-sasl.c +@@ -76,6 +76,11 @@ long vnc_client_write_sasl(VncState *vs) + + vs->sasl.encodedOffset += ret; + if (vs->sasl.encodedOffset == vs->sasl.encodedLength) { ++ if (vs->sasl.encodedRawLength >= vs->force_update_offset) { ++ vs->force_update_offset = 0; ++ } else { ++ vs->force_update_offset -= vs->sasl.encodedRawLength; ++ } + vs->output.offset -= vs->sasl.encodedRawLength; + vs->sasl.encoded = NULL; + vs->sasl.encodedOffset = vs->sasl.encodedLength = 0; +diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c +index e553bd9..9705899 100644 +--- a/ui/vnc-jobs.c ++++ b/ui/vnc-jobs.c +@@ -170,6 +170,11 @@ void vnc_jobs_consume_buffer(VncState *vs) + vnc_client_write, vs); + } + buffer_move(&vs->output, &vs->jobs_buffer); ++ ++ if (vs->job_update == VNC_STATE_UPDATE_FORCE) { ++ vs->force_update_offset = vs->output.offset; ++ } ++ vs->job_update = VNC_STATE_UPDATE_NONE; + } + flush = vs->csock != -1 && vs->abort != true; + vnc_unlock_output(vs); +diff --git a/ui/vnc.c b/ui/vnc.c +index 952a051..96b6caf 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -906,14 +906,28 @@ static bool vnc_should_update(VncState *vs) + break; + case VNC_STATE_UPDATE_INCREMENTAL: + /* Only allow incremental updates if the pending send queue +- * is less than the permitted threshold ++ * is less than the permitted threshold, and the job worker ++ * is completely idle. + */ +- if (vs->output.offset < vs->throttle_output_offset) { ++ if (vs->output.offset < vs->throttle_output_offset && ++ vs->job_update == VNC_STATE_UPDATE_NONE) { + return true; + } + break; + case VNC_STATE_UPDATE_FORCE: +- return true; ++ /* Only allow forced updates if the pending send queue ++ * does not contain a previous forced update, and the ++ * job worker is completely idle. ++ * ++ * Note this means we'll queue a forced update, even if ++ * the output buffer size is otherwise over the throttle ++ * output limit. ++ */ ++ if (vs->force_update_offset == 0 && ++ vs->job_update == VNC_STATE_UPDATE_NONE) { ++ return true; ++ } ++ break; + } + return false; + } +@@ -975,8 +989,9 @@ static int vnc_update_client(VncState *vs, int has_dirty) + } + } + +- vnc_job_push(job); ++ vs->job_update = vs->update; + vs->update = VNC_STATE_UPDATE_NONE; ++ vnc_job_push(job); + vs->has_dirty = 0; + return n; + } +@@ -1241,6 +1256,11 @@ static long vnc_client_write_plain(VncState *vs) + if (!ret) + return 0; + ++ if (ret >= vs->force_update_offset) { ++ vs->force_update_offset = 0; ++ } else { ++ vs->force_update_offset -= ret; ++ } + buffer_advance(&vs->output, ret); + + if (vs->output.offset == 0) { +diff --git a/ui/vnc.h b/ui/vnc.h +index d7eede3..70316ba 100644 +--- a/ui/vnc.h ++++ b/ui/vnc.h +@@ -268,6 +268,7 @@ struct VncState + + VncDisplay *vd; + VncStateUpdate update; /* Most recent pending request from client */ ++ VncStateUpdate job_update; /* Currently processed by job thread */ + int has_dirty; + uint32_t features; + int absolute; +@@ -301,6 +302,12 @@ struct VncState + + QObject *info; + ++ /* Job thread bottom half has put data for a forced update ++ * into the output buffer. This offset points to the end of ++ * the update data in the output buffer. This lets us determine ++ * when a force update is fully sent to the client, allowing ++ * us to process further forced updates. */ ++ size_t force_update_offset; + /* We allow multiple incremental updates or audio capture + * samples to be queued in output buffer, provided the + * buffer size doesn't exceed this threshold. The value +-- +1.8.3.1 + diff --git a/SOURCES/kvm-ui-fix-refresh-of-VNC-server-surface.patch b/SOURCES/kvm-ui-fix-refresh-of-VNC-server-surface.patch new file mode 100644 index 0000000..e6a799d --- /dev/null +++ b/SOURCES/kvm-ui-fix-refresh-of-VNC-server-surface.patch @@ -0,0 +1,119 @@ +From 3fa0b44ff46eccd3c22729a6e5d4ed044d22ab8a Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:28 +0100 +Subject: [PATCH 14/27] ui: fix refresh of VNC server surface + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-15-berrange@redhat.com> +Patchwork-id: 78948 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 14/27] ui: fix refresh of VNC server surface +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +From: "Daniel P. Berrange" + +In previous commit + + commit c7628bff4138ce906a3620d12e0820c1cf6c140d + Author: Gerd Hoffmann + Date: Fri Oct 30 12:10:09 2015 +0100 + + vnc: only alloc server surface with clients connected + +the VNC server was changed so that the 'vd->server' pixman +image was only allocated when a client is connected. + +Since then if a client disconnects and then reconnects to +the VNC server all they will see is a black screen until +they do something that triggers a refresh. On a graphical +desktop this is not often noticed since there's many things +going on which cause a refresh. On a plain text console it +is really obvious since nothing refreshes frequently. + +The problem is that the VNC server didn't update the guest +dirty bitmap, so still believes its server image is in sync +with the guest contents. + +To fix this we must explicitly mark the entire guest desktop +as dirty after re-creating the server surface. Move this +logic into vnc_update_server_surface() so it is guaranteed +to be call in all code paths that re-create the surface +instead of only in vnc_dpy_switch() + +Signed-off-by: Daniel P. Berrange +Reviewed-by: Peter Lieven +Tested-by: Peter Lieven +Message-id: 1471365032-18096-1-git-send-email-berrange@redhat.com +Signed-off-by: Peter Maydell +(cherry picked from commit b69a553b4af9bc87a8b2e0a7b7a7de4cc7f0557e) +Signed-off-by: Miroslav Rezanina +--- + ui/vnc.c | 20 +++++++++++--------- + 1 file changed, 11 insertions(+), 9 deletions(-) + +diff --git a/ui/vnc.c b/ui/vnc.c +index dc09089..ec7bb0c 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -617,6 +617,8 @@ void *vnc_server_fb_ptr(VncDisplay *vd, int x, int y) + + static void vnc_update_server_surface(VncDisplay *vd) + { ++ int width, height; ++ + qemu_pixman_image_unref(vd->server); + vd->server = NULL; + +@@ -624,10 +626,15 @@ static void vnc_update_server_surface(VncDisplay *vd) + return; + } + ++ width = vnc_width(vd); ++ height = vnc_height(vd); + vd->server = pixman_image_create_bits(VNC_SERVER_FB_FORMAT, +- vnc_width(vd), +- vnc_height(vd), ++ width, height, + NULL, 0); ++ ++ memset(vd->guest.dirty, 0x00, sizeof(vd->guest.dirty)); ++ vnc_set_area_dirty(vd->guest.dirty, vd, 0, 0, ++ width, height); + } + + static void vnc_dpy_switch(DisplayChangeListener *dcl, +@@ -635,7 +642,6 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl, + { + VncDisplay *vd = container_of(dcl, VncDisplay, dcl); + VncState *vs; +- int width, height; + + vnc_abort_display_jobs(vd); + vd->ds = surface; +@@ -647,11 +653,6 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl, + qemu_pixman_image_unref(vd->guest.fb); + vd->guest.fb = pixman_image_ref(surface->image); + vd->guest.format = surface->format; +- width = vnc_width(vd); +- height = vnc_height(vd); +- memset(vd->guest.dirty, 0x00, sizeof(vd->guest.dirty)); +- vnc_set_area_dirty(vd->guest.dirty, vd, 0, 0, +- width, height); + + QTAILQ_FOREACH(vs, &vd->clients, next) { + vnc_colordepth(vs); +@@ -661,7 +662,8 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl, + } + memset(vs->dirty, 0x00, sizeof(vs->dirty)); + vnc_set_area_dirty(vs->dirty, vd, 0, 0, +- width, height); ++ vnc_width(vd), ++ vnc_height(vd)); + } + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-ui-introduce-enum-to-track-VNC-client-framebuffer-up.patch b/SOURCES/kvm-ui-introduce-enum-to-track-VNC-client-framebuffer-up.patch new file mode 100644 index 0000000..d49d491 --- /dev/null +++ b/SOURCES/kvm-ui-introduce-enum-to-track-VNC-client-framebuffer-up.patch @@ -0,0 +1,121 @@ +From bb6e65d667f1bbc28cfab0ba2626880cee8e7741 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:33 +0100 +Subject: [PATCH 19/27] ui: introduce enum to track VNC client framebuffer + update request state +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-20-berrange@redhat.com> +Patchwork-id: 78953 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 19/27] ui: introduce enum to track VNC client framebuffer update request state +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +From: "Daniel P. Berrange" + +Currently the VNC servers tracks whether a client has requested an incremental +or forced update with two boolean flags. There are only really 3 distinct +states to track, so create an enum to more accurately reflect permitted states. + +Signed-off-by: Daniel P. Berrange +Reviewed-by: Darren Kenny +Reviewed-by: Marc-André Lureau +Message-id: 20171218191228.31018-7-berrange@redhat.com +Signed-off-by: Gerd Hoffmann +(cherry picked from commit fef1bbadfb2c3027208eb3d14b43e1bdb51166ca) +Signed-off-by: Miroslav Rezanina +--- + ui/vnc.c | 21 +++++++++++---------- + ui/vnc.h | 9 +++++++-- + 2 files changed, 18 insertions(+), 12 deletions(-) + +diff --git a/ui/vnc.c b/ui/vnc.c +index eea5702..7239602 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -860,16 +860,17 @@ static int vnc_update_client(VncState *vs, int has_dirty) + } + + vs->has_dirty += has_dirty; +- if (!vs->need_update) { ++ if (vs->update == VNC_STATE_UPDATE_NONE) { + return 0; + } + +- if (vs->output.offset && !vs->audio_cap && !vs->force_update) { ++ if (vs->output.offset && !vs->audio_cap && ++ vs->update != VNC_STATE_UPDATE_FORCE) { + /* kernel send buffers are full -> drop frames to throttle */ + return 0; + } + +- if (!vs->has_dirty && !vs->force_update) { ++ if (!vs->has_dirty && vs->update != VNC_STATE_UPDATE_FORCE) { + return 0; + } + +@@ -909,7 +910,7 @@ static int vnc_update_client(VncState *vs, int has_dirty) + } + + vnc_job_push(job); +- vs->force_update = 0; ++ vs->update = VNC_STATE_UPDATE_INCREMENTAL; + vs->has_dirty = 0; + return n; + } +@@ -1832,14 +1833,14 @@ static void ext_key_event(VncState *vs, int down, + static void framebuffer_update_request(VncState *vs, int incremental, + int x, int y, int w, int h) + { +- vs->need_update = 1; +- + if (incremental) { +- return; ++ if (vs->update != VNC_STATE_UPDATE_FORCE) { ++ vs->update = VNC_STATE_UPDATE_INCREMENTAL; ++ } ++ } else { ++ vs->update = VNC_STATE_UPDATE_FORCE; ++ vnc_set_area_dirty(vs->dirty, vs->vd, x, y, w, h); + } +- +- vs->force_update = 1; +- vnc_set_area_dirty(vs->dirty, vs->vd, x, y, w, h); + } + + static void send_ext_key_event_ack(VncState *vs) +diff --git a/ui/vnc.h b/ui/vnc.h +index d8465ba..f19fd0a 100644 +--- a/ui/vnc.h ++++ b/ui/vnc.h +@@ -252,6 +252,12 @@ struct VncJob + QTAILQ_ENTRY(VncJob) next; + }; + ++typedef enum { ++ VNC_STATE_UPDATE_NONE, ++ VNC_STATE_UPDATE_INCREMENTAL, ++ VNC_STATE_UPDATE_FORCE, ++} VncStateUpdate; ++ + struct VncState + { + int csock; +@@ -261,8 +267,7 @@ struct VncState + * vnc-jobs-async.c */ + + VncDisplay *vd; +- int need_update; +- int force_update; ++ VncStateUpdate update; /* Most recent pending request from client */ + int has_dirty; + uint32_t features; + int absolute; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-ui-move-disconnecting-check-to-start-of-vnc_update_c.patch b/SOURCES/kvm-ui-move-disconnecting-check-to-start-of-vnc_update_c.patch new file mode 100644 index 0000000..93d0e41 --- /dev/null +++ b/SOURCES/kvm-ui-move-disconnecting-check-to-start-of-vnc_update_c.patch @@ -0,0 +1,77 @@ +From a56b8ac0a5917f0a2d007a9249a4ea299fc5c208 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:29 +0100 +Subject: [PATCH 15/27] ui: move disconnecting check to start of + vnc_update_client +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-16-berrange@redhat.com> +Patchwork-id: 78937 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 15/27] ui: move disconnecting check to start of vnc_update_client +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +This is superficially similar to the combination of + + commit 5a8be0f73d6f60ff08746377eb09ca459f39deab + Author: Gerd Hoffmann + Date: Wed Jul 13 12:21:20 2016 +0200 + + vnc: make sure we finish disconnect + +and + + commit c53df961617736f94731d94b62c2954c261d2bae + Author: Daniel P. Berrange + Date: Mon Dec 18 19:12:17 2017 +0000 + + ui: remove unreachable code in vnc_update_client + +We can't cherry-pick those changes, however, because they depend +on the QIOChannel conversion. Thus, this downstream only change +is done to make other following changes apply with fewer conflicts +during backport. + +Signed-off-by: Daniel P. Berrangé +Signed-off-by: Miroslav Rezanina +--- + ui/vnc.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/ui/vnc.c b/ui/vnc.c +index ec7bb0c..874900c 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -848,8 +848,13 @@ static int find_and_clear_dirty_height(struct VncState *vs, + + static int vnc_update_client(VncState *vs, int has_dirty) + { ++ if (vs->csock == -1) { ++ vnc_disconnect_finish(vs); ++ return 0; ++ } ++ + vs->has_dirty += has_dirty; +- if (vs->need_update && vs->csock != -1) { ++ if (vs->need_update) { + VncDisplay *vd = vs->vd; + VncJob *job; + int y; +@@ -904,9 +909,6 @@ static int vnc_update_client(VncState *vs, int has_dirty) + return n; + } + +- if (vs->csock == -1) +- vnc_disconnect_finish(vs); +- + return 0; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-ui-place-a-hard-cap-on-VNC-server-output-buffer-size.patch b/SOURCES/kvm-ui-place-a-hard-cap-on-VNC-server-output-buffer-size.patch new file mode 100644 index 0000000..03df9b4 --- /dev/null +++ b/SOURCES/kvm-ui-place-a-hard-cap-on-VNC-server-output-buffer-size.patch @@ -0,0 +1,112 @@ +From 52fe55e2bf9df408ebe127a670ee698642d3fcb4 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:38 +0100 +Subject: [PATCH 24/27] ui: place a hard cap on VNC server output buffer size +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-25-berrange@redhat.com> +Patchwork-id: 78957 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 24/27] ui: place a hard cap on VNC server output buffer size +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +From: "Daniel P. Berrange" + +The previous patches fix problems with throttling of forced framebuffer updates +and audio data capture that would cause the QEMU output buffer size to grow +without bound. Those fixes are graceful in that once the client catches up with +reading data from the server, everything continues operating normally. + +There is some data which the server sends to the client that is impractical to +throttle. Specifically there are various pseudo framebuffer update encodings to +inform the client of things like desktop resizes, pointer changes, audio +playback start/stop, LED state and so on. These generally only involve sending +a very small amount of data to the client, but a malicious guest might be able +to do things that trigger these changes at a very high rate. Throttling them is +not practical as missed or delayed events would cause broken behaviour for the +client. + +This patch thus takes a more forceful approach of setting an absolute upper +bound on the amount of data we permit to be present in the output buffer at +any time. The previous patch set a threshold for throttling the output buffer +by allowing an amount of data equivalent to one complete framebuffer update and +one seconds worth of audio data. On top of this it allowed for one further +forced framebuffer update to be queued. + +To be conservative, we thus take that throttling threshold and multiply it by +5 to form an absolute upper bound. If this bound is hit during vnc_write() we +forceably disconnect the client, refusing to queue further data. This limit is +high enough that it should never be hit unless a malicious client is trying to +exploit the sever, or the network is completely saturated preventing any sending +of data on the socket. + +This completes the fix for CVE-2017-15124 started in the previous patches. + +Signed-off-by: Daniel P. Berrange +Reviewed-by: Darren Kenny +Reviewed-by: Marc-André Lureau +Message-id: 20171218191228.31018-12-berrange@redhat.com +Signed-off-by: Gerd Hoffmann +(cherry picked from commit f887cf165db20f405cb8805c716bd363aaadf815) + + Conflicts: + ui/vnc.c - context differences and no 'vs->disconnecting' flag. + Using share_mode as a better check for the disconnecting state + than csock == -1, because the worker thread calls vnc_write() + with a fake VncState that has csock == -1. + +Signed-off-by: Miroslav Rezanina +--- + ui/vnc.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/ui/vnc.c b/ui/vnc.c +index 96b6caf..61fbec2 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -1460,8 +1460,37 @@ void vnc_client_read(void *opaque) + } + } + ++/* ++ * Scale factor to apply to vs->throttle_output_offset when checking for ++ * hard limit. Worst case normal usage could be x2, if we have a complete ++ * incremental update and complete forced update in the output buffer. ++ * So x3 should be good enough, but we pick x5 to be conservative and thus ++ * (hopefully) never trigger incorrectly. ++ */ ++#define VNC_THROTTLE_OUTPUT_LIMIT_SCALE 5 ++ + void vnc_write(VncState *vs, const void *data, size_t len) + { ++ if (vs->share_mode == VNC_SHARE_MODE_DISCONNECTED) { ++ return; ++ } ++ /* Protection against malicious client/guest to prevent our output ++ * buffer growing without bound if client stops reading data. This ++ * should rarely trigger, because we have earlier throttling code ++ * which stops issuing framebuffer updates and drops audio data ++ * if the throttle_output_offset value is exceeded. So we only reach ++ * this higher level if a huge number of pseudo-encodings get ++ * triggered while data can't be sent on the socket. ++ * ++ * NB throttle_output_offset can be zero during early protocol ++ * handshake, or from the job thread's VncState clone ++ */ ++ if (vs->throttle_output_offset != 0 && ++ vs->output.offset > (vs->throttle_output_offset * ++ VNC_THROTTLE_OUTPUT_LIMIT_SCALE)) { ++ vnc_disconnect_start(vs); ++ return; ++ } + buffer_reserve(&vs->output, len); + + if (vs->csock != -1 && buffer_empty(&vs->output)) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-ui-refactor-code-for-determining-if-an-update-should.patch b/SOURCES/kvm-ui-refactor-code-for-determining-if-an-update-should.patch new file mode 100644 index 0000000..4fbe43c --- /dev/null +++ b/SOURCES/kvm-ui-refactor-code-for-determining-if-an-update-should.patch @@ -0,0 +1,83 @@ +From 3b0e5204ae4a681ed9f6bedd3cd18ecad877546c Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:35 +0100 +Subject: [PATCH 21/27] ui: refactor code for determining if an update should + be sent to the client +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-22-berrange@redhat.com> +Patchwork-id: 78954 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 21/27] ui: refactor code for determining if an update should be sent to the client +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +From: "Daniel P. Berrange" + +The logic for determining if it is possible to send an update to the client +will become more complicated shortly, so pull it out into a separate method +for easier extension later. + +Signed-off-by: Daniel P. Berrange +Reviewed-by: Darren Kenny +Reviewed-by: Marc-André Lureau +Message-id: 20171218191228.31018-9-berrange@redhat.com +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 0bad834228b9ee63e4239108d02dcb94568254d0) +Signed-off-by: Miroslav Rezanina +--- + ui/vnc.c | 27 ++++++++++++++++++++------- + 1 file changed, 20 insertions(+), 7 deletions(-) + +diff --git a/ui/vnc.c b/ui/vnc.c +index 075def1..a7ec8cc 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -846,6 +846,25 @@ static int find_and_clear_dirty_height(struct VncState *vs, + return h; + } + ++static bool vnc_should_update(VncState *vs) ++{ ++ switch (vs->update) { ++ case VNC_STATE_UPDATE_NONE: ++ break; ++ case VNC_STATE_UPDATE_INCREMENTAL: ++ /* Only allow incremental updates if the output buffer ++ * is empty, or if audio capture is enabled. ++ */ ++ if (!vs->output.offset || vs->audio_cap) { ++ return true; ++ } ++ break; ++ case VNC_STATE_UPDATE_FORCE: ++ return true; ++ } ++ return false; ++} ++ + static int vnc_update_client(VncState *vs, int has_dirty) + { + VncDisplay *vd = vs->vd; +@@ -860,13 +879,7 @@ static int vnc_update_client(VncState *vs, int has_dirty) + } + + vs->has_dirty += has_dirty; +- if (vs->update == VNC_STATE_UPDATE_NONE) { +- return 0; +- } +- +- if (vs->output.offset && !vs->audio_cap && +- vs->update != VNC_STATE_UPDATE_FORCE) { +- /* kernel send buffers are full -> drop frames to throttle */ ++ if (!vnc_should_update(vs)) { + return 0; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-ui-remove-redundant-indentation-in-vnc_client_update.patch b/SOURCES/kvm-ui-remove-redundant-indentation-in-vnc_client_update.patch new file mode 100644 index 0000000..14f16b0 --- /dev/null +++ b/SOURCES/kvm-ui-remove-redundant-indentation-in-vnc_client_update.patch @@ -0,0 +1,168 @@ +From 2f49f56062f802fd47bc1c1c81d811aa6c9e9cff Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:30 +0100 +Subject: [PATCH 16/27] ui: remove redundant indentation in vnc_client_update +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-17-berrange@redhat.com> +Patchwork-id: 78936 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 16/27] ui: remove redundant indentation in vnc_client_update +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +From: "Daniel P. Berrange" + +Now that previous dead / unreachable code has been removed, we can simplify +the indentation in the vnc_client_update method. + +Signed-off-by: Daniel P. Berrange +Reviewed-by: Darren Kenny +Reviewed-by: Marc-André Lureau +Message-id: 20171218191228.31018-4-berrange@redhat.com +Signed-off-by: Gerd Hoffmann +(cherry picked from commit b939eb89b6f320544a9328fa908d881d0024c1ee) + + Conflicts: + ui/vnc.c - context difference due to vs->csock no longer + existing and some other optimizations in + determining dirty rectangles. + +Signed-off-by: Miroslav Rezanina +--- + ui/vnc.c | 104 ++++++++++++++++++++++++++++++++------------------------------- + 1 file changed, 53 insertions(+), 51 deletions(-) + +diff --git a/ui/vnc.c b/ui/vnc.c +index 874900c..aebaa37 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -848,68 +848,70 @@ static int find_and_clear_dirty_height(struct VncState *vs, + + static int vnc_update_client(VncState *vs, int has_dirty) + { ++ VncDisplay *vd = vs->vd; ++ VncJob *job; ++ int y; ++ int height, width; ++ int n = 0; ++ + if (vs->csock == -1) { + vnc_disconnect_finish(vs); + return 0; + } + + vs->has_dirty += has_dirty; +- if (vs->need_update) { +- VncDisplay *vd = vs->vd; +- VncJob *job; +- int y; +- int height, width; +- int n = 0; +- +- if (vs->output.offset && !vs->audio_cap && !vs->force_update) +- /* kernel send buffers are full -> drop frames to throttle */ +- return 0; ++ if (!vs->need_update) { ++ return 0; ++ } + +- if (!vs->has_dirty && !vs->audio_cap && !vs->force_update) +- return 0; ++ if (vs->output.offset && !vs->audio_cap && !vs->force_update) { ++ /* kernel send buffers are full -> drop frames to throttle */ ++ return 0; ++ } + +- /* +- * Send screen updates to the vnc client using the server +- * surface and server dirty map. guest surface updates +- * happening in parallel don't disturb us, the next pass will +- * send them to the client. +- */ +- job = vnc_job_new(vs); +- +- height = pixman_image_get_height(vd->server); +- width = pixman_image_get_width(vd->server); +- +- y = 0; +- for (;;) { +- int x, h; +- unsigned long x2; +- unsigned long offset = find_next_bit((unsigned long *) &vs->dirty, +- height * VNC_DIRTY_BPL(vs), +- y * VNC_DIRTY_BPL(vs)); +- if (offset == height * VNC_DIRTY_BPL(vs)) { +- /* no more dirty bits */ +- break; +- } +- y = offset / VNC_DIRTY_BPL(vs); +- x = offset % VNC_DIRTY_BPL(vs); +- x2 = find_next_zero_bit((unsigned long *) &vs->dirty[y], +- VNC_DIRTY_BPL(vs), x); +- bitmap_clear(vs->dirty[y], x, x2 - x); +- h = find_and_clear_dirty_height(vs, y, x, x2, height); +- x2 = MIN(x2, width / VNC_DIRTY_PIXELS_PER_BIT); +- if (x2 > x) { +- n += vnc_job_add_rect(job, x * VNC_DIRTY_PIXELS_PER_BIT, y, +- (x2 - x) * VNC_DIRTY_PIXELS_PER_BIT, h); +- } +- } ++ if (!vs->has_dirty && !vs->audio_cap && !vs->force_update) { ++ return 0; ++ } ++ ++ /* ++ * Send screen updates to the vnc client using the server ++ * surface and server dirty map. guest surface updates ++ * happening in parallel don't disturb us, the next pass will ++ * send them to the client. ++ */ ++ job = vnc_job_new(vs); ++ ++ height = pixman_image_get_height(vd->server); ++ width = pixman_image_get_width(vd->server); + +- vnc_job_push(job); +- vs->force_update = 0; +- vs->has_dirty = 0; +- return n; ++ y = 0; ++ for (;;) { ++ int x, h; ++ unsigned long x2; ++ unsigned long offset = find_next_bit((unsigned long *) &vs->dirty, ++ height * VNC_DIRTY_BPL(vs), ++ y * VNC_DIRTY_BPL(vs)); ++ if (offset == height * VNC_DIRTY_BPL(vs)) { ++ /* no more dirty bits */ ++ break; ++ } ++ y = offset / VNC_DIRTY_BPL(vs); ++ x = offset % VNC_DIRTY_BPL(vs); ++ x2 = find_next_zero_bit((unsigned long *) &vs->dirty[y], ++ VNC_DIRTY_BPL(vs), x); ++ bitmap_clear(vs->dirty[y], x, x2 - x); ++ h = find_and_clear_dirty_height(vs, y, x, x2, height); ++ x2 = MIN(x2, width / VNC_DIRTY_PIXELS_PER_BIT); ++ if (x2 > x) { ++ n += vnc_job_add_rect(job, x * VNC_DIRTY_PIXELS_PER_BIT, y, ++ (x2 - x) * VNC_DIRTY_PIXELS_PER_BIT, h); ++ } + } + +- return 0; ++ vnc_job_push(job); ++ vs->force_update = 0; ++ vs->has_dirty = 0; ++ return n; + } + + /* audio */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-ui-track-how-much-decoded-data-we-consumed-when-doin.patch b/SOURCES/kvm-ui-track-how-much-decoded-data-we-consumed-when-doin.patch new file mode 100644 index 0000000..bb43a2d --- /dev/null +++ b/SOURCES/kvm-ui-track-how-much-decoded-data-we-consumed-when-doin.patch @@ -0,0 +1,88 @@ +From 3be810287878138e5f72568d1ba1160b5bad22f8 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:32 +0100 +Subject: [PATCH 18/27] ui: track how much decoded data we consumed when doing + SASL encoding +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-19-berrange@redhat.com> +Patchwork-id: 78951 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 18/27] ui: track how much decoded data we consumed when doing SASL encoding +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +From: "Daniel P. Berrange" + +When we encode data for writing with SASL, we encode the entire pending output +buffer. The subsequent write, however, may not be able to send the full encoded +data in one go though, particularly with a slow network. So we delay setting the +output buffer offset back to zero until all the SASL encoded data is sent. + +Between encoding the data and completing sending of the SASL encoded data, +however, more data might have been placed on the pending output buffer. So it +is not valid to set offset back to zero. Instead we must keep track of how much +data we consumed during encoding and subtract only that amount. + +With the current bug we would be throwing away some pending data without having +sent it at all. By sheer luck this did not previously cause any serious problem +because appending data to the send buffer is always an atomic action, so we +only ever throw away complete RFB protocol messages. In the case of frame buffer +updates we'd catch up fairly quickly, so no obvious problem was visible. + +RHEL-7 note: context difference in the last argument to +vnc_client_io_error() due to downstream lacking commit 04d2529da27d +("ui: convert VNC server to use QIOChannelSocket", 2015-12-18). + +Signed-off-by: Daniel P. Berrange +Reviewed-by: Darren Kenny +Reviewed-by: Marc-André Lureau +Message-id: 20171218191228.31018-6-berrange@redhat.com +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 8f61f1c5a6bc06438a1172efa80bc7606594fa07) +Signed-off-by: Miroslav Rezanina +--- + ui/vnc-auth-sasl.c | 3 ++- + ui/vnc-auth-sasl.h | 1 + + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c +index f3ad75d..804b8e7 100644 +--- a/ui/vnc-auth-sasl.c ++++ b/ui/vnc-auth-sasl.c +@@ -64,6 +64,7 @@ long vnc_client_write_sasl(VncState *vs) + if (err != SASL_OK) + return vnc_client_io_error(vs, -1, EIO); + ++ vs->sasl.encodedRawLength = vs->output.offset; + vs->sasl.encodedOffset = 0; + } + +@@ -75,7 +76,7 @@ long vnc_client_write_sasl(VncState *vs) + + vs->sasl.encodedOffset += ret; + if (vs->sasl.encodedOffset == vs->sasl.encodedLength) { +- vs->output.offset = 0; ++ vs->output.offset -= vs->sasl.encodedRawLength; + vs->sasl.encoded = NULL; + vs->sasl.encodedOffset = vs->sasl.encodedLength = 0; + } +diff --git a/ui/vnc-auth-sasl.h b/ui/vnc-auth-sasl.h +index 8091d68..4ec6fb5 100644 +--- a/ui/vnc-auth-sasl.h ++++ b/ui/vnc-auth-sasl.h +@@ -54,6 +54,7 @@ struct VncStateSASL { + */ + const uint8_t *encoded; + unsigned int encodedLength; ++ unsigned int encodedRawLength; + unsigned int encodedOffset; + char *username; + char *mechlist; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vfio-Add-sysfsdev-property-for-pci-platform.patch b/SOURCES/kvm-vfio-Add-sysfsdev-property-for-pci-platform.patch new file mode 100644 index 0000000..92137cb --- /dev/null +++ b/SOURCES/kvm-vfio-Add-sysfsdev-property-for-pci-platform.patch @@ -0,0 +1,367 @@ +From acd0e88a7222dac83caf4d507a1bfce7cd0ea734 Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Fri, 29 Sep 2017 21:45:14 +0200 +Subject: [PATCH 09/27] vfio: Add sysfsdev property for pci & platform + +RH-Author: Alex Williamson +Message-id: <20170929214514.16765.36252.stgit@gimli.home> +Patchwork-id: 76768 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 09/16] vfio: Add sysfsdev property for pci & platform +Bugzilla: 1494181 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Auger Eric +RH-Acked-by: Miroslav Rezanina + +Upstream: 7df9381b7aa56c897e344f3bfe43bf5848bbd3e0 +RHEL: Dropped platform + +vfio-pci currently requires a host= parameter, which comes in the +form of a PCI address in [domain:] notation. We +expect to find a matching entry in sysfs for that under +/sys/bus/pci/devices/. vfio-platform takes a similar approach, but +defines the host= parameter to be a string, which can be matched +directly under /sys/bus/platform/devices/. On the PCI side, we have +some interest in using vfio to expose vGPU devices. These are not +actual discrete PCI devices, so they don't have a compatible host PCI +bus address or a device link where QEMU wants to look for it. There's +also really no requirement that vfio can only be used to expose +physical devices, a new vfio bus and iommu driver could expose a +completely emulated device. To fit within the vfio framework, it +would need a kernel struct device and associated IOMMU group, but +those are easy constraints to manage. + +To support such devices, which would include vGPUs, that honor the +VFIO PCI programming API, but are not necessarily backed by a unique +PCI address, add support for specifying any device in sysfs. The +vfio API already has support for probing the device type to ensure +compatibility with either vfio-pci or vfio-platform. + +With this, a vfio-pci device could either be specified as: + +-device vfio-pci,host=02:00.0 + +or + +-device vfio-pci,sysfsdev=/sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.0 + +or even + +-device vfio-pci,sysfsdev=/sys/bus/pci/devices/0000:02:00.0 + +When vGPU support comes along, this might look something more like: + +-device vfio-pci,sysfsdev=/sys/devices/virtual/intel-vgpu/vgpu0@0000:00:02.0 + +NB - This is only a made up example path + +The same change is made for vfio-platform, specifying sysfsdev has +precedence over the old host option. + +Tested-by: Eric Auger +Reviewed-by: Eric Auger +Signed-off-by: Alex Williamson +Signed-off-by: Miroslav Rezanina +--- + hw/misc/vfio.c | 131 ++++++++++++++++++++++++--------------------------------- + 1 file changed, 54 insertions(+), 77 deletions(-) + +diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c +index 0d88313..64d4dc7 100644 +--- a/hw/misc/vfio.c ++++ b/hw/misc/vfio.c +@@ -187,6 +187,7 @@ typedef struct VFIODeviceOps VFIODeviceOps; + typedef struct VFIODevice { + QLIST_ENTRY(VFIODevice) next; + struct VFIOGroup *group; ++ char *sysfsdev; + char *name; + int fd; + int type; +@@ -1288,12 +1289,8 @@ static void vfio_pci_size_rom(VFIOPCIDevice *vdev) + if (vdev->pdev.romfile || !vdev->pdev.rom_bar) { + /* Since pci handles romfile, just print a message and return */ + if (vfio_blacklist_opt_rom(vdev) && vdev->pdev.romfile) { +- error_printf("Warning : Device at %04x:%02x:%02x.%x " +- "is known to cause system instability issues during " +- "option rom execution. " +- "Proceeding anyway since user specified romfile\n", +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function); ++ error_printf("Warning : Device at %s is known to cause system instability issues during option rom execution. Proceeding anyway since user specified romfile\n", ++ vdev->vbasedev.name); + } + return; + } +@@ -1306,9 +1303,7 @@ static void vfio_pci_size_rom(VFIOPCIDevice *vdev) + pwrite(fd, &size, 4, offset) != 4 || + pread(fd, &size, 4, offset) != 4 || + pwrite(fd, &orig, 4, offset) != 4) { +- error_report("%s(%04x:%02x:%02x.%x) failed: %m", +- __func__, vdev->host.domain, vdev->host.bus, +- vdev->host.slot, vdev->host.function); ++ error_report("%s(%s) failed: %m", __func__, vdev->vbasedev.name); + return; + } + +@@ -1320,29 +1315,18 @@ static void vfio_pci_size_rom(VFIOPCIDevice *vdev) + + if (vfio_blacklist_opt_rom(vdev)) { + if (dev->opts && qemu_opt_get(dev->opts, "rombar")) { +- error_printf("Warning : Device at %04x:%02x:%02x.%x " +- "is known to cause system instability issues during " +- "option rom execution. " +- "Proceeding anyway since user specified non zero value for " +- "rombar\n", +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function); ++ error_printf("Warning : Device at %s is known to cause system instability issues during option rom execution. Proceeding anyway since user specified non zero value for rombar\n", ++ vdev->vbasedev.name); + } else { +- error_printf("Warning : Rom loading for device at " +- "%04x:%02x:%02x.%x has been disabled due to " +- "system instability issues. " +- "Specify rombar=1 or romfile to force\n", +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function); ++ error_printf("Warning : Rom loading for device at %s has been disabled due to system instability issues. Specify rombar=1 or romfile to force\n", ++ vdev->vbasedev.name); + return; + } + } + + DPRINTF("%s ROM size 0x%x\n", vdev->vbasedev.name, size); + +- snprintf(name, sizeof(name), "vfio[%04x:%02x:%02x.%x].rom", +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function); ++ snprintf(name, sizeof(name), "vfio[%s].rom", vdev->vbasedev.name); + + memory_region_init_io(&vdev->pdev.rom, + &vfio_rom_ops, vdev, name, size); +@@ -2112,9 +2096,8 @@ static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len) + ret = pread(vdev->vbasedev.fd, &phys_val, len, + vdev->config_offset + addr); + if (ret != len) { +- error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x) failed: %m", +- __func__, vdev->host.domain, vdev->host.bus, +- vdev->host.slot, vdev->host.function, addr, len); ++ error_report("%s(%s, 0x%x, 0x%x) failed: %m", ++ __func__, vdev->vbasedev.name, addr, len); + return -errno; + } + phys_val = le32_to_cpu(phys_val); +@@ -2140,9 +2123,8 @@ static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr, + /* Write everything to VFIO, let it filter out what we can't write */ + if (pwrite(vdev->vbasedev.fd, &val_le, len, vdev->config_offset + addr) + != len) { +- error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x, 0x%x) failed: %m", +- __func__, vdev->host.domain, vdev->host.bus, +- vdev->host.slot, vdev->host.function, addr, val, len); ++ error_report("%s(%s, 0x%x, 0x%x, 0x%x) failed: %m", ++ __func__, vdev->vbasedev.name, addr, val, len); + } + + /* MSI/MSI-X Enabling/Disabling */ +@@ -2610,9 +2592,7 @@ static void vfio_map_bar(VFIOPCIDevice *vdev, int nr) + return; + } + +- snprintf(name, sizeof(name), "VFIO %04x:%02x:%02x.%x BAR %d", +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function, nr); ++ snprintf(name, sizeof(name), "VFIO %s BAR %d", vdev->vbasedev.name, nr); + + /* Determine what type of BAR this is for registration */ + ret = pread(vdev->vbasedev.fd, &pci_bar, sizeof(pci_bar), +@@ -2946,9 +2926,8 @@ static int vfio_add_std_cap(VFIOPCIDevice *vdev, uint8_t pos) + } + + if (ret < 0) { +- error_report("vfio: %04x:%02x:%02x.%x Error adding PCI capability " +- "0x%x[0x%x]@0x%x: %d", vdev->host.domain, +- vdev->host.bus, vdev->host.slot, vdev->host.function, ++ error_report("vfio: %s Error adding PCI capability " ++ "0x%x[0x%x]@0x%x: %d", vdev->vbasedev.name, + cap_id, size, pos, ret); + return ret; + } +@@ -3010,11 +2989,14 @@ static void vfio_pci_post_reset(VFIOPCIDevice *vdev) + vfio_enable_intx(vdev); + } + +-static bool vfio_pci_host_match(PCIHostDeviceAddress *host1, +- PCIHostDeviceAddress *host2) ++static bool vfio_pci_host_match(PCIHostDeviceAddress *addr, const char *name) + { +- return (host1->domain == host2->domain && host1->bus == host2->bus && +- host1->slot == host2->slot && host1->function == host2->function); ++ char tmp[13]; ++ ++ sprintf(tmp, "%04x:%02x:%02x.%1x", addr->domain, ++ addr->bus, addr->slot, addr->function); ++ ++ return (strcmp(tmp, name) == 0); + } + + static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single) +@@ -3040,9 +3022,8 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single) + if (ret && errno != ENOSPC) { + ret = -errno; + if (!vdev->has_pm_reset) { +- error_report("vfio: Cannot reset device %04x:%02x:%02x.%x, " +- "no available reset mechanism.", vdev->host.domain, +- vdev->host.bus, vdev->host.slot, vdev->host.function); ++ error_report("vfio: Cannot reset device %s, " ++ "no available reset mechanism.", vdev->vbasedev.name); + } + goto out_single; + } +@@ -3075,7 +3056,7 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single) + DPRINTF("\t%04x:%02x:%02x.%x group %d\n", host.domain, + host.bus, host.slot, host.function, devices[i].group_id); + +- if (vfio_pci_host_match(&host, &vdev->host)) { ++ if (vfio_pci_host_match(&host, vdev->vbasedev.name)) { + continue; + } + +@@ -3101,7 +3082,7 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single) + continue; + } + tmp = container_of(vbasedev_iter, VFIOPCIDevice, vbasedev); +- if (vfio_pci_host_match(&host, &tmp->host)) { ++ if (vfio_pci_host_match(&host, tmp->vbasedev.name)) { + if (single) { + DPRINTF("vfio: found another in-use device " + "%s\n", tmp->vbasedev.name); +@@ -3165,7 +3146,7 @@ out: + host.slot = PCI_SLOT(devices[i].devfn); + host.function = PCI_FUNC(devices[i].devfn); + +- if (vfio_pci_host_match(&host, &vdev->host)) { ++ if (vfio_pci_host_match(&host, vdev->vbasedev.name)) { + continue; + } + +@@ -3184,7 +3165,7 @@ out: + continue; + } + tmp = container_of(vbasedev_iter, VFIOPCIDevice, vbasedev); +- if (vfio_pci_host_match(&host, &tmp->host)) { ++ if (vfio_pci_host_match(&host, tmp->vbasedev.name)) { + vfio_pci_post_reset(tmp); + break; + } +@@ -3683,10 +3664,7 @@ static void vfio_err_notifier_handler(void *opaque) + * guest to contain the error. + */ + +- error_report("%s(%04x:%02x:%02x.%x) Unrecoverable error detected. " +- "Please collect any data possible and then kill the guest", +- __func__, vdev->host.domain, vdev->host.bus, +- vdev->host.slot, vdev->host.function); ++ error_report("%s(%s) Unrecoverable error detected. Please collect any data possible and then kill the guest", __func__, vdev->vbasedev.name); + + vm_stop(RUN_STATE_INTERNAL_ERROR); + } +@@ -3867,7 +3845,7 @@ static int vfio_initfn(PCIDevice *pdev) + VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); + VFIODevice *vbasedev_iter; + VFIOGroup *group; +- char path[PATH_MAX], iommu_group_path[PATH_MAX], *group_name; ++ char *tmp, group_path[PATH_MAX], *group_name; + ssize_t len; + struct stat st; + int groupid; +@@ -3885,36 +3863,37 @@ static int vfio_initfn(PCIDevice *pdev) + return -1; + } + +- /* Check that the host device exists */ +- snprintf(path, sizeof(path), +- "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/", +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function); +- if (stat(path, &st) < 0) { +- error_report("vfio: error: no such host device: %s", path); ++ if (!vdev->vbasedev.sysfsdev) { ++ vdev->vbasedev.sysfsdev = ++ g_strdup_printf("/sys/bus/pci/devices/%04x:%02x:%02x.%01x", ++ vdev->host.domain, vdev->host.bus, ++ vdev->host.slot, vdev->host.function); ++ } ++ ++ if (stat(vdev->vbasedev.sysfsdev, &st) < 0) { ++ error_report("vfio: error: no such host device: %s", ++ vdev->vbasedev.sysfsdev); + return -errno; + } + ++ vdev->vbasedev.name = g_strdup(basename(vdev->vbasedev.sysfsdev)); + vdev->vbasedev.ops = &vfio_pci_ops; +- + vdev->vbasedev.type = VFIO_DEVICE_TYPE_PCI; +- vdev->vbasedev.name = g_strdup_printf("%04x:%02x:%02x.%01x", +- vdev->host.domain, vdev->host.bus, +- vdev->host.slot, vdev->host.function); + +- strncat(path, "iommu_group", sizeof(path) - strlen(path) - 1); ++ tmp = g_strdup_printf("%s/iommu_group", vdev->vbasedev.sysfsdev); ++ len = readlink(tmp, group_path, sizeof(group_path)); ++ g_free(tmp); + +- len = readlink(path, iommu_group_path, sizeof(path)); +- if (len <= 0 || len >= sizeof(path)) { ++ if (len <= 0 || len >= sizeof(group_path)) { + error_report("vfio: error no iommu_group for device"); + return len < 0 ? -errno : -ENAMETOOLONG; + } + +- iommu_group_path[len] = 0; +- group_name = basename(iommu_group_path); ++ group_path[len] = 0; + ++ group_name = basename(group_path); + if (sscanf(group_name, "%d", &groupid) != 1) { +- error_report("vfio: error reading %s: %m", path); ++ error_report("vfio: error reading %s: %m", group_path); + return -errno; + } + +@@ -3926,21 +3905,18 @@ static int vfio_initfn(PCIDevice *pdev) + return -ENOENT; + } + +- snprintf(path, sizeof(path), "%04x:%02x:%02x.%01x", +- vdev->host.domain, vdev->host.bus, vdev->host.slot, +- vdev->host.function); +- + QLIST_FOREACH(vbasedev_iter, &group->device_list, next) { + if (strcmp(vbasedev_iter->name, vdev->vbasedev.name) == 0) { +- error_report("vfio: error: device %s is already attached", path); ++ error_report("vfio: error: device %s is already attached", ++ vdev->vbasedev.name); + vfio_put_group(group); + return -EBUSY; + } + } + +- ret = vfio_get_device(group, path, vdev); ++ ret = vfio_get_device(group, vdev->vbasedev.name, vdev); + if (ret) { +- error_report("vfio: failed to get device %s", path); ++ error_report("vfio: failed to get device %s", vdev->vbasedev.name); + vfio_put_group(group); + return ret; + } +@@ -4086,6 +4062,7 @@ post_reset: + + static Property vfio_pci_dev_properties[] = { + DEFINE_PROP_PCI_HOST_DEVADDR("host", VFIOPCIDevice, host), ++ DEFINE_PROP_STRING("sysfsdev", VFIOPCIDevice, vbasedev.sysfsdev), + DEFINE_PROP_UINT32("x-intx-mmap-timeout-ms", VFIOPCIDevice, + intx.mmap_timeout, 1100), + DEFINE_PROP_BIT("x-vga", VFIOPCIDevice, features, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vfio-Enable-sparse-mmap-capability.patch b/SOURCES/kvm-vfio-Enable-sparse-mmap-capability.patch new file mode 100644 index 0000000..bdfffe5 --- /dev/null +++ b/SOURCES/kvm-vfio-Enable-sparse-mmap-capability.patch @@ -0,0 +1,223 @@ +From bbd8cc516329f84b70d38a75820f36f2ecd0abda Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Fri, 29 Sep 2017 21:46:14 +0200 +Subject: [PATCH 15/27] vfio: Enable sparse mmap capability + +RH-Author: Alex Williamson +Message-id: <20170929214614.16765.48627.stgit@gimli.home> +Patchwork-id: 76773 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 15/16] vfio: Enable sparse mmap capability +Bugzilla: 1494181 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Auger Eric +RH-Acked-by: Miroslav Rezanina + +Upstream: b53b0f696b10828f6393155f44a352c019e673fd +RHEL: Roll in required linux-headers update + +The sparse mmap capability in a vfio region info allows vfio to tell +us which sub-areas of a region may be mmap'd. Thus rather than +assuming a single mmap covers the entire region and later frobbing it +ourselves for things like the PCI MSI-X vector table, we can read that +directly from vfio. + +Signed-off-by: Alex Williamson +Reviewed-by: Gerd Hoffmann +Tested-by: Gerd Hoffmann +Signed-off-by: Miroslav Rezanina +--- + hw/misc/vfio.c | 67 +++++++++++++++++++++++++++++++++++++++++++--- + linux-headers/linux/vfio.h | 53 +++++++++++++++++++++++++++++++++++- + trace-events | 2 ++ + 3 files changed, 117 insertions(+), 5 deletions(-) + +diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c +index d634531..a27698b 100644 +--- a/hw/misc/vfio.c ++++ b/hw/misc/vfio.c +@@ -2602,6 +2602,54 @@ static void vfio_unmap_bar(VFIOPCIDevice *vdev, int nr) + vfio_region_finalize(&bar->region); + } + ++static struct vfio_info_cap_header * ++vfio_get_region_info_cap(struct vfio_region_info *info, uint16_t id) ++{ ++ struct vfio_info_cap_header *hdr; ++ void *ptr = info; ++ ++ if (!(info->flags & VFIO_REGION_INFO_FLAG_CAPS)) { ++ return NULL; ++ } ++ ++ for (hdr = ptr + info->cap_offset; hdr != ptr; hdr = ptr + hdr->next) { ++ if (hdr->id == id) { ++ return hdr; ++ } ++ } ++ ++ return NULL; ++} ++ ++static void vfio_setup_region_sparse_mmaps(VFIORegion *region, ++ struct vfio_region_info *info) ++{ ++ struct vfio_info_cap_header *hdr; ++ struct vfio_region_info_cap_sparse_mmap *sparse; ++ int i; ++ ++ hdr = vfio_get_region_info_cap(info, VFIO_REGION_INFO_CAP_SPARSE_MMAP); ++ if (!hdr) { ++ return; ++ } ++ ++ sparse = container_of(hdr, struct vfio_region_info_cap_sparse_mmap, header); ++ ++ trace_vfio_region_sparse_mmap_header(region->vbasedev->name, ++ region->nr, sparse->nr_areas); ++ ++ region->nr_mmaps = sparse->nr_areas; ++ region->mmaps = g_new0(VFIOMmap, region->nr_mmaps); ++ ++ for (i = 0; i < region->nr_mmaps; i++) { ++ region->mmaps[i].offset = sparse->areas[i].offset; ++ region->mmaps[i].size = sparse->areas[i].size; ++ trace_vfio_region_sparse_mmap_entry(i, region->mmaps[i].offset, ++ region->mmaps[i].offset + ++ region->mmaps[i].size); ++ } ++} ++ + static int vfio_region_setup(Object *obj, VFIODevice *vbasedev, + VFIORegion *region, int index, const char *name) + { +@@ -2628,11 +2676,14 @@ static int vfio_region_setup(Object *obj, VFIODevice *vbasedev, + region->flags & VFIO_REGION_INFO_FLAG_MMAP && + !(region->size & ~TARGET_PAGE_MASK)) { + +- region->nr_mmaps = 1; +- region->mmaps = g_new0(VFIOMmap, region->nr_mmaps); ++ vfio_setup_region_sparse_mmaps(region, info); + +- region->mmaps[0].offset = 0; +- region->mmaps[0].size = region->size; ++ if (!region->nr_mmaps) { ++ region->nr_mmaps = 1; ++ region->mmaps = g_new0(VFIOMmap, region->nr_mmaps); ++ region->mmaps[0].offset = 0; ++ region->mmaps[0].size = region->size; ++ } + } + } + +@@ -3796,6 +3847,7 @@ static int vfio_get_region_info(VFIODevice *vbasedev, int index, + *info = g_malloc0(argsz); + + (*info)->index = index; ++retry: + (*info)->argsz = argsz; + + if (ioctl(vbasedev->fd, VFIO_DEVICE_GET_REGION_INFO, *info)) { +@@ -3803,6 +3855,13 @@ static int vfio_get_region_info(VFIODevice *vbasedev, int index, + return -errno; + } + ++ if ((*info)->argsz > argsz) { ++ argsz = (*info)->argsz; ++ *info = g_realloc(*info, argsz); ++ ++ goto retry; ++ } ++ + return 0; + } + +diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h +index d197fd4..8995a34 100644 +--- a/linux-headers/linux/vfio.h ++++ b/linux-headers/linux/vfio.h +@@ -38,6 +38,33 @@ + #define VFIO_TYPE (';') + #define VFIO_BASE 100 + ++/* ++ * For extension of INFO ioctls, VFIO makes use of a capability chain ++ * designed after PCI/e capabilities. A flag bit indicates whether ++ * this capability chain is supported and a field defined in the fixed ++ * structure defines the offset of the first capability in the chain. ++ * This field is only valid when the corresponding bit in the flags ++ * bitmap is set. This offset field is relative to the start of the ++ * INFO buffer, as is the next field within each capability header. ++ * The id within the header is a shared address space per INFO ioctl, ++ * while the version field is specific to the capability id. The ++ * contents following the header are specific to the capability id. ++ */ ++struct vfio_info_cap_header { ++ __u16 id; /* Identifies capability */ ++ __u16 version; /* Version specific to the capability ID */ ++ __u32 next; /* Offset of next capability */ ++}; ++ ++/* ++ * Callers of INFO ioctls passing insufficiently sized buffers will see ++ * the capability chain flag bit set, a zero value for the first capability ++ * offset (if available within the provided argsz), and argsz will be ++ * updated to report the necessary buffer size. For compatibility, the ++ * INFO ioctl will not report error in this case, but the capability chain ++ * will not be available. ++ */ ++ + /* -------- IOCTLs for VFIO file descriptor (/dev/vfio/vfio) -------- */ + + /** +@@ -171,13 +198,37 @@ struct vfio_region_info { + #define VFIO_REGION_INFO_FLAG_READ (1 << 0) /* Region supports read */ + #define VFIO_REGION_INFO_FLAG_WRITE (1 << 1) /* Region supports write */ + #define VFIO_REGION_INFO_FLAG_MMAP (1 << 2) /* Region supports mmap */ ++#define VFIO_REGION_INFO_FLAG_CAPS (1 << 3) /* Info supports caps */ + __u32 index; /* Region index */ +- __u32 resv; /* Reserved for alignment */ ++ __u32 cap_offset; /* Offset within info struct of first cap */ + __u64 size; /* Region size (bytes) */ + __u64 offset; /* Region offset from start of device fd */ + }; + #define VFIO_DEVICE_GET_REGION_INFO _IO(VFIO_TYPE, VFIO_BASE + 8) + ++/* ++ * The sparse mmap capability allows finer granularity of specifying areas ++ * within a region with mmap support. When specified, the user should only ++ * mmap the offset ranges specified by the areas array. mmaps outside of the ++ * areas specified may fail (such as the range covering a PCI MSI-X table) or ++ * may result in improper device behavior. ++ * ++ * The structures below define version 1 of this capability. ++ */ ++#define VFIO_REGION_INFO_CAP_SPARSE_MMAP 1 ++ ++struct vfio_region_sparse_mmap_area { ++ __u64 offset; /* Offset of mmap'able area within region */ ++ __u64 size; /* Size of mmap'able area */ ++}; ++ ++struct vfio_region_info_cap_sparse_mmap { ++ struct vfio_info_cap_header header; ++ __u32 nr_areas; ++ __u32 reserved; ++ struct vfio_region_sparse_mmap_area areas[]; ++}; ++ + /** + * VFIO_DEVICE_GET_IRQ_INFO - _IOWR(VFIO_TYPE, VFIO_BASE + 9, + * struct vfio_irq_info) +diff --git a/trace-events b/trace-events +index cc62b0b..fa2618d 100644 +--- a/trace-events ++++ b/trace-events +@@ -1164,3 +1164,5 @@ vfio_region_mmap(const char *name, unsigned long offset, unsigned long end) "Reg + vfio_region_exit(const char *name, int index) "Device %s, region %d" + vfio_region_finalize(const char *name, int index) "Device %s, region %d" + vfio_region_mmaps_set_enabled(const char *name, bool enabled) "Region %s mmaps enabled: %d" ++vfio_region_sparse_mmap_header(const char *name, int index, int nr_areas) "Device %s region %d: %d sparse mmap entries" ++vfio_region_sparse_mmap_entry(int i, unsigned long start, unsigned long end) "sparse entry %d [0x%lx - 0x%lx]" +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vfio-Generalize-region-support.patch b/SOURCES/kvm-vfio-Generalize-region-support.patch new file mode 100644 index 0000000..c0018c8 --- /dev/null +++ b/SOURCES/kvm-vfio-Generalize-region-support.patch @@ -0,0 +1,591 @@ +From a33e922436f708fe4881da4b6f363c49db5af581 Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Fri, 29 Sep 2017 21:46:02 +0200 +Subject: [PATCH 14/27] vfio: Generalize region support + +RH-Author: Alex Williamson +Message-id: <20170929214601.16765.68107.stgit@gimli.home> +Patchwork-id: 76772 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 14/16] vfio: Generalize region support +Bugzilla: 1494181 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Auger Eric +RH-Acked-by: Miroslav Rezanina + +Upstream: db0da029a1853d46c90a6c0790ce6ca77fd46ea3 +RHEL: MemoryRegions still destroyed from exitfn, so finalize is called + immediately after exit with memory_region_destroy(). + +Both platform and PCI vfio drivers create a "slow", I/O memory region +with one or more mmap memory regions overlayed when supported by the +device. Generalize this to a set of common helpers in the core that +pulls the region info from vfio, fills the region data, configures +slow mapping, and adds helpers for comleting the mmap, enable/disable, +and teardown. This can be immediately used by the PCI MSI-X code, +which needs to mmap around the MSI-X vector table. + +This also changes VFIORegion.mem to be dynamically allocated because +otherwise we don't know how the caller has allocated VFIORegion and +therefore don't know whether to unreference it to destroy the +MemoryRegion or not. + +Signed-off-by: Alex Williamson +Signed-off-by: Miroslav Rezanina +--- + hw/misc/vfio.c | 360 +++++++++++++++++++++++++++++++++++++++------------------ + trace-events | 9 ++ + 2 files changed, 258 insertions(+), 111 deletions(-) + +diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c +index 57a0065..d634531 100644 +--- a/hw/misc/vfio.c ++++ b/hw/misc/vfio.c +@@ -39,6 +39,7 @@ + #include "qemu/range.h" + #include "sysemu/kvm.h" + #include "sysemu/sysemu.h" ++#include "trace.h" + + /* #define DEBUG_VFIO */ + #ifdef DEBUG_VFIO +@@ -84,14 +85,21 @@ typedef struct VFIOQuirk { + } data; + } VFIOQuirk; + ++typedef struct VFIOMmap { ++ MemoryRegion mem; ++ void *mmap; ++ off_t offset; ++ size_t size; ++} VFIOMmap; ++ + typedef struct VFIORegion { + struct VFIODevice *vbasedev; + off_t fd_offset; /* offset of region within device fd */ +- MemoryRegion mem; /* slow, read/write access */ +- MemoryRegion mmap_mem; /* direct mapped access */ +- void *mmap; ++ MemoryRegion *mem; /* slow, read/write access */ + size_t size; + uint32_t flags; /* VFIO region flags (rd/wr/mmap) */ ++ uint32_t nr_mmaps; ++ VFIOMmap *mmaps; + uint8_t nr; /* cache the region number for debug */ + } VFIORegion; + +@@ -294,6 +302,9 @@ static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr, + static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled); + static int vfio_get_region_info(VFIODevice *vbasedev, int index, + struct vfio_region_info **info); ++static void vfio_region_mmaps_set_enabled(VFIORegion *region, bool enabled); ++static void vfio_region_exit(VFIORegion *region); ++static void vfio_region_finalize(VFIORegion *region); + + /* + * Common VFIO interrupt disable +@@ -1681,7 +1692,7 @@ static void vfio_probe_ati_bar4_window_quirk(VFIOPCIDevice *vdev, int nr) + memory_region_init_io(&quirk->mem, + &vfio_generic_window_quirk, quirk, + "vfio-ati-bar4-window-quirk", 8); +- memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, ++ memory_region_add_subregion_overlap(vdev->bars[nr].region.mem, + quirk->data.base_offset, &quirk->mem, 1); + + QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); +@@ -1714,7 +1725,7 @@ static void vfio_probe_ati_bar2_4000_quirk(VFIOPCIDevice *vdev, int nr) + memory_region_init_io(&quirk->mem, &vfio_generic_quirk, quirk, + "vfio-ati-bar2-4000-quirk", + TARGET_PAGE_ALIGN(quirk->data.address_mask + 1)); +- memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, ++ memory_region_add_subregion_overlap(vdev->bars[nr].region.mem, + quirk->data.address_match & TARGET_PAGE_MASK, + &quirk->mem, 1); + +@@ -1939,7 +1950,7 @@ static void vfio_probe_nvidia_bar5_window_quirk(VFIOPCIDevice *vdev, int nr) + memory_region_init_io(&quirk->mem, + &vfio_nvidia_bar5_window_quirk, quirk, + "vfio-nvidia-bar5-window-quirk", 16); +- memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, ++ memory_region_add_subregion_overlap(vdev->bars[nr].region.mem, + 0, &quirk->mem, 1); + + QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); +@@ -1977,7 +1988,7 @@ static void vfio_probe_nvidia_bar0_88000_quirk(VFIOPCIDevice *vdev, int nr) + memory_region_init_io(&quirk->mem, &vfio_generic_quirk, + quirk, "vfio-nvidia-bar0-88000-quirk", + TARGET_PAGE_ALIGN(quirk->data.address_mask + 1)); +- memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, ++ memory_region_add_subregion_overlap(vdev->bars[nr].region.mem, + quirk->data.address_match & TARGET_PAGE_MASK, + &quirk->mem, 1); + +@@ -2015,7 +2026,7 @@ static void vfio_probe_nvidia_bar0_1800_quirk(VFIOPCIDevice *vdev, int nr) + memory_region_init_io(&quirk->mem, &vfio_generic_quirk, quirk, + "vfio-nvidia-bar0-1800-quirk", + TARGET_PAGE_ALIGN(quirk->data.address_mask + 1)); +- memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, ++ memory_region_add_subregion_overlap(vdev->bars[nr].region.mem, + quirk->data.address_match & TARGET_PAGE_MASK, + &quirk->mem, 1); + +@@ -2070,7 +2081,7 @@ static void vfio_bar_quirk_teardown(VFIOPCIDevice *vdev, int nr) + + while (!QLIST_EMPTY(&bar->quirks)) { + VFIOQuirk *quirk = QLIST_FIRST(&bar->quirks); +- memory_region_del_subregion(&bar->region.mem, &quirk->mem); ++ memory_region_del_subregion(bar->region.mem, &quirk->mem); + memory_region_destroy(&quirk->mem); + QLIST_REMOVE(quirk, next); + g_free(quirk); +@@ -2384,6 +2395,74 @@ static int vfio_setup_msi(VFIOPCIDevice *vdev, int pos) + return 0; + } + ++static void vfio_pci_fixup_msix_region(VFIOPCIDevice *vdev) ++{ ++ off_t start, end; ++ VFIORegion *region = &vdev->bars[vdev->msix->table_bar].region; ++ ++ /* ++ * We expect to find a single mmap covering the whole BAR, anything else ++ * means it's either unsupported or already setup. ++ */ ++ if (region->nr_mmaps != 1 || region->mmaps[0].offset || ++ region->size != region->mmaps[0].size) { ++ return; ++ } ++ ++ /* MSI-X table start and end aligned to host page size */ ++ start = vdev->msix->table_offset & TARGET_PAGE_MASK; ++ end = TARGET_PAGE_ALIGN((uint64_t)vdev->msix->table_offset + ++ (vdev->msix->entries * PCI_MSIX_ENTRY_SIZE)); ++ ++ /* ++ * Does the MSI-X table cover the beginning of the BAR? The whole BAR? ++ * NB - Host page size is necessarily a power of two and so is the PCI ++ * BAR (not counting EA yet), therefore if we have host page aligned ++ * @start and @end, then any remainder of the BAR before or after those ++ * must be at least host page sized and therefore mmap'able. ++ */ ++ if (!start) { ++ if (end >= region->size) { ++ region->nr_mmaps = 0; ++ g_free(region->mmaps); ++ region->mmaps = NULL; ++ trace_vfio_msix_fixup(vdev->vbasedev.name, ++ vdev->msix->table_bar, 0, 0); ++ } else { ++ region->mmaps[0].offset = end; ++ region->mmaps[0].size = region->size - end; ++ trace_vfio_msix_fixup(vdev->vbasedev.name, ++ vdev->msix->table_bar, region->mmaps[0].offset, ++ region->mmaps[0].offset + region->mmaps[0].size); ++ } ++ ++ /* Maybe it's aligned at the end of the BAR */ ++ } else if (end >= region->size) { ++ region->mmaps[0].size = start; ++ trace_vfio_msix_fixup(vdev->vbasedev.name, ++ vdev->msix->table_bar, region->mmaps[0].offset, ++ region->mmaps[0].offset + region->mmaps[0].size); ++ ++ /* Otherwise it must split the BAR */ ++ } else { ++ region->nr_mmaps = 2; ++ region->mmaps = g_renew(VFIOMmap, region->mmaps, 2); ++ ++ memcpy(®ion->mmaps[1], ®ion->mmaps[0], sizeof(VFIOMmap)); ++ ++ region->mmaps[0].size = start; ++ trace_vfio_msix_fixup(vdev->vbasedev.name, ++ vdev->msix->table_bar, region->mmaps[0].offset, ++ region->mmaps[0].offset + region->mmaps[0].size); ++ ++ region->mmaps[1].offset = end; ++ region->mmaps[1].size = region->size - end; ++ trace_vfio_msix_fixup(vdev->vbasedev.name, ++ vdev->msix->table_bar, region->mmaps[1].offset, ++ region->mmaps[1].offset + region->mmaps[1].size); ++ } ++} ++ + /* + * We don't have any control over how pci_add_capability() inserts + * capabilities into the chain. In order to setup MSI-X we need a +@@ -2461,6 +2540,8 @@ static int vfio_early_setup_msix(VFIOPCIDevice *vdev) + } + } + ++ vfio_pci_fixup_msix_region(vdev); ++ + return 0; + } + +@@ -2469,9 +2550,9 @@ static int vfio_setup_msix(VFIOPCIDevice *vdev, int pos) + int ret; + + ret = msix_init(&vdev->pdev, vdev->msix->entries, +- &vdev->bars[vdev->msix->table_bar].region.mem, ++ vdev->bars[vdev->msix->table_bar].region.mem, + vdev->msix->table_bar, vdev->msix->table_offset, +- &vdev->bars[vdev->msix->pba_bar].region.mem, ++ vdev->bars[vdev->msix->pba_bar].region.mem, + vdev->msix->pba_bar, vdev->msix->pba_offset, pos); + if (ret < 0) { + if (ret == -ENOTSUP) { +@@ -2490,8 +2571,8 @@ static void vfio_teardown_msi(VFIOPCIDevice *vdev) + + if (vdev->msix) { + msix_uninit(&vdev->pdev, +- &vdev->bars[vdev->msix->table_bar].region.mem, +- &vdev->bars[vdev->msix->pba_bar].region.mem); ++ vdev->bars[vdev->msix->table_bar].region.mem, ++ vdev->bars[vdev->msix->pba_bar].region.mem); + } + } + +@@ -2503,16 +2584,7 @@ static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled) + int i; + + for (i = 0; i < PCI_ROM_SLOT; i++) { +- VFIOBAR *bar = &vdev->bars[i]; +- +- if (!bar->region.size) { +- continue; +- } +- +- memory_region_set_enabled(&bar->region.mmap_mem, enabled); +- if (vdev->msix && vdev->msix->table_bar == i) { +- memory_region_set_enabled(&vdev->msix->mmap_mem, enabled); +- } ++ vfio_region_mmaps_set_enabled(&vdev->bars[i].region, enabled); + } + } + +@@ -2526,65 +2598,171 @@ static void vfio_unmap_bar(VFIOPCIDevice *vdev, int nr) + + vfio_bar_quirk_teardown(vdev, nr); + +- memory_region_del_subregion(&bar->region.mem, &bar->region.mmap_mem); +- munmap(bar->region.mmap, memory_region_size(&bar->region.mmap_mem)); +- memory_region_destroy(&bar->region.mmap_mem); ++ vfio_region_exit(&bar->region); ++ vfio_region_finalize(&bar->region); ++} ++ ++static int vfio_region_setup(Object *obj, VFIODevice *vbasedev, ++ VFIORegion *region, int index, const char *name) ++{ ++ struct vfio_region_info *info; ++ int ret; ++ ++ ret = vfio_get_region_info(vbasedev, index, &info); ++ if (ret) { ++ return ret; ++ } ++ ++ region->vbasedev = vbasedev; ++ region->flags = info->flags; ++ region->size = info->size; ++ region->fd_offset = info->offset; ++ region->nr = index; + +- if (vdev->msix && vdev->msix->table_bar == nr) { +- memory_region_del_subregion(&bar->region.mem, &vdev->msix->mmap_mem); +- munmap(vdev->msix->mmap, memory_region_size(&vdev->msix->mmap_mem)); +- memory_region_destroy(&vdev->msix->mmap_mem); ++ if (region->size) { ++ region->mem = g_new0(MemoryRegion, 1); ++ memory_region_init_io(region->mem, &vfio_region_ops, ++ region, name, region->size); ++ ++ if (VFIO_ALLOW_MMAP && ++ region->flags & VFIO_REGION_INFO_FLAG_MMAP && ++ !(region->size & ~TARGET_PAGE_MASK)) { ++ ++ region->nr_mmaps = 1; ++ region->mmaps = g_new0(VFIOMmap, region->nr_mmaps); ++ ++ region->mmaps[0].offset = 0; ++ region->mmaps[0].size = region->size; ++ } + } + +- memory_region_destroy(&bar->region.mem); ++ g_free(info); ++ ++ trace_vfio_region_setup(vbasedev->name, index, name, ++ region->flags, region->fd_offset, region->size); ++ return 0; + } + +-static int vfio_mmap_region(Object *obj, VFIORegion *region, +- MemoryRegion *mem, MemoryRegion *submem, +- void **map, size_t size, off_t offset, +- const char *name) ++static int vfio_region_mmap(VFIORegion *region) + { +- int ret = 0; +- VFIODevice *vbasedev = region->vbasedev; ++ int i, prot = 0; ++ char *name; ++ ++ if (!region->mem) { ++ return 0; ++ } ++ ++ prot |= region->flags & VFIO_REGION_INFO_FLAG_READ ? PROT_READ : 0; ++ prot |= region->flags & VFIO_REGION_INFO_FLAG_WRITE ? PROT_WRITE : 0; ++ ++ for (i = 0; i < region->nr_mmaps; i++) { ++ region->mmaps[i].mmap = mmap(NULL, region->mmaps[i].size, prot, ++ MAP_SHARED, region->vbasedev->fd, ++ region->fd_offset + ++ region->mmaps[i].offset); ++ if (region->mmaps[i].mmap == MAP_FAILED) { ++ int ret = -errno; + +- if (VFIO_ALLOW_MMAP && size && region->flags & +- VFIO_REGION_INFO_FLAG_MMAP) { +- int prot = 0; ++ trace_vfio_region_mmap_fault(memory_region_name(region->mem), i, ++ region->fd_offset + ++ region->mmaps[i].offset, ++ region->fd_offset + ++ region->mmaps[i].offset + ++ region->mmaps[i].size - 1, ret); + +- if (region->flags & VFIO_REGION_INFO_FLAG_READ) { +- prot |= PROT_READ; ++ region->mmaps[i].mmap = NULL; ++ ++ for (i--; i >= 0; i--) { ++ memory_region_del_subregion(region->mem, ®ion->mmaps[i].mem); ++ munmap(region->mmaps[i].mmap, region->mmaps[i].size); ++ memory_region_destroy(®ion->mmaps[i].mem); ++ region->mmaps[i].mmap = NULL; ++ } ++ ++ return ret; + } + +- if (region->flags & VFIO_REGION_INFO_FLAG_WRITE) { +- prot |= PROT_WRITE; ++ name = g_strdup_printf("%s mmaps[%d]", ++ memory_region_name(region->mem), i); ++ memory_region_init_ram_ptr(®ion->mmaps[i].mem, ++ name, region->mmaps[i].size, ++ region->mmaps[i].mmap); ++ g_free(name); ++ memory_region_set_skip_dump(®ion->mmaps[i].mem); ++ memory_region_add_subregion(region->mem, region->mmaps[i].offset, ++ ®ion->mmaps[i].mem); ++ ++ trace_vfio_region_mmap(memory_region_name(®ion->mmaps[i].mem), ++ region->mmaps[i].offset, ++ region->mmaps[i].offset + ++ region->mmaps[i].size - 1); ++ } ++ ++ return 0; ++} ++ ++static void vfio_region_exit(VFIORegion *region) ++{ ++ int i; ++ ++ if (!region->mem) { ++ return; ++ } ++ ++ for (i = 0; i < region->nr_mmaps; i++) { ++ if (region->mmaps[i].mmap) { ++ memory_region_del_subregion(region->mem, ®ion->mmaps[i].mem); + } ++ } ++ ++ trace_vfio_region_exit(region->vbasedev->name, region->nr); ++} ++ ++static void vfio_region_finalize(VFIORegion *region) ++{ ++ int i; ++ ++ if (!region->mem) { ++ return; ++ } + +- *map = mmap(NULL, size, prot, MAP_SHARED, +- vbasedev->fd, region->fd_offset + offset); +- if (*map == MAP_FAILED) { +- *map = NULL; +- ret = -errno; +- goto empty_region; ++ for (i = 0; i < region->nr_mmaps; i++) { ++ if (region->mmaps[i].mmap) { ++ munmap(region->mmaps[i].mmap, region->mmaps[i].size); ++ memory_region_destroy(®ion->mmaps[i].mem); + } ++ } + +- memory_region_init_ram_ptr(submem, name, size, *map); +- memory_region_set_skip_dump(submem); +- } else { +-empty_region: +- /* Create a zero sized sub-region to make cleanup easy. */ +- memory_region_init(submem, name, 0); ++ memory_region_destroy(region->mem); ++ ++ g_free(region->mem); ++ g_free(region->mmaps); ++ ++ trace_vfio_region_finalize(region->vbasedev->name, region->nr); ++} ++ ++static void vfio_region_mmaps_set_enabled(VFIORegion *region, bool enabled) ++{ ++ int i; ++ ++ if (!region->mem) { ++ return; + } + +- memory_region_add_subregion(mem, offset, submem); ++ for (i = 0; i < region->nr_mmaps; i++) { ++ if (region->mmaps[i].mmap) { ++ memory_region_set_enabled(®ion->mmaps[i].mem, enabled); ++ } ++ } + +- return ret; ++ trace_vfio_region_mmaps_set_enabled(memory_region_name(region->mem), ++ enabled); + } + + static void vfio_map_bar(VFIOPCIDevice *vdev, int nr) + { + VFIOBAR *bar = &vdev->bars[nr]; + uint64_t size = bar->region.size; +- char name[64]; + uint32_t pci_bar; + uint8_t type; + int ret; +@@ -2594,8 +2772,6 @@ static void vfio_map_bar(VFIOPCIDevice *vdev, int nr) + return; + } + +- snprintf(name, sizeof(name), "VFIO %s BAR %d", vdev->vbasedev.name, nr); +- + /* Determine what type of BAR this is for registration */ + ret = pread(vdev->vbasedev.fd, &pci_bar, sizeof(pci_bar), + vdev->config_offset + PCI_BASE_ADDRESS_0 + (4 * nr)); +@@ -2610,40 +2786,11 @@ static void vfio_map_bar(VFIOPCIDevice *vdev, int nr) + type = pci_bar & (bar->ioport ? ~PCI_BASE_ADDRESS_IO_MASK : + ~PCI_BASE_ADDRESS_MEM_MASK); + +- /* A "slow" read/write mapping underlies all BARs */ +- memory_region_init_io(&bar->region.mem, &vfio_region_ops, +- bar, name, size); +- pci_register_bar(&vdev->pdev, nr, type, &bar->region.mem); +- +- /* +- * We can't mmap areas overlapping the MSIX vector table, so we +- * potentially insert a direct-mapped subregion before and after it. +- */ +- if (vdev->msix && vdev->msix->table_bar == nr) { +- size = vdev->msix->table_offset & TARGET_PAGE_MASK; +- } +- +- strncat(name, " mmap", sizeof(name) - strlen(name) - 1); +- if (vfio_mmap_region(OBJECT(vdev), &bar->region, &bar->region.mem, +- &bar->region.mmap_mem, &bar->region.mmap, +- size, 0, name)) { +- error_report("%s unsupported. Performance may be slow", name); +- } +- +- if (vdev->msix && vdev->msix->table_bar == nr) { +- uint64_t start; ++ pci_register_bar(&vdev->pdev, nr, type, bar->region.mem); + +- start = TARGET_PAGE_ALIGN((uint64_t)vdev->msix->table_offset + +- (vdev->msix->entries * PCI_MSIX_ENTRY_SIZE)); +- +- size = start < bar->region.size ? bar->region.size - start : 0; +- strncat(name, " msix-hi", sizeof(name) - strlen(name) - 1); +- /* VFIOMSIXInfo contains another MemoryRegion for this mapping */ +- if (vfio_mmap_region(OBJECT(vdev), &bar->region, &bar->region.mem, +- &vdev->msix->mmap_mem, +- &vdev->msix->mmap, size, start, name)) { +- error_report("%s unsupported. Performance may be slow", name); +- } ++ if (vfio_region_mmap(&bar->region)) { ++ error_report("Failed to mmap %s BAR %d. Performance may be slow", ++ vdev->vbasedev.name, nr); + } + + vfio_bar_quirk_setup(vdev, nr); +@@ -3531,25 +3678,18 @@ static int vfio_get_device(VFIOGroup *group, const char *name, + } + + for (i = VFIO_PCI_BAR0_REGION_INDEX; i < VFIO_PCI_ROM_REGION_INDEX; i++) { +- ret = vfio_get_region_info(&vdev->vbasedev, i, ®_info); ++ char *name = g_strdup_printf("%s BAR %d", vdev->vbasedev.name, i); ++ ++ ret = vfio_region_setup(OBJECT(vdev), &vdev->vbasedev, ++ &vdev->bars[i].region, i, name); ++ g_free(name); ++ + if (ret) { + error_report("vfio: Error getting region %d info: %m", i); + goto error; + } + +- DPRINTF("Device %s region %d:\n", name, i); +- DPRINTF(" size: 0x%lx, offset: 0x%lx, flags: 0x%lx\n", +- (unsigned long)reg_info->size, (unsigned long)reg_info->offset, +- (unsigned long)reg_info->flags); +- +- vdev->bars[i].region.vbasedev = &vdev->vbasedev; +- vdev->bars[i].region.flags = reg_info->flags; +- vdev->bars[i].region.size = reg_info->size; +- vdev->bars[i].region.fd_offset = reg_info->offset; +- vdev->bars[i].region.nr = i; + QLIST_INIT(&vdev->bars[i].quirks); +- +- g_free(reg_info); + } + + ret = vfio_get_region_info(&vdev->vbasedev, +@@ -3644,10 +3784,8 @@ static void vfio_put_device(VFIOPCIDevice *vdev) + DPRINTF("vfio_put_device: close vdev->vbasedev.fd\n"); + close(vdev->vbasedev.fd); + g_free(vdev->vbasedev.name); +- if (vdev->msix) { +- g_free(vdev->msix); +- vdev->msix = NULL; +- } ++ g_free(vdev->msix); ++ + } + + static int vfio_get_region_info(VFIODevice *vbasedev, int index, +diff --git a/trace-events b/trace-events +index 6cd46e9..cc62b0b 100644 +--- a/trace-events ++++ b/trace-events +@@ -1155,3 +1155,12 @@ kvm_run_exit(int cpu_index, uint32_t reason) "cpu_index %d, reason %d" + # qom/object.c + object_dynamic_cast_assert(const char *type, const char *target, const char *file, int line, const char *func) "%s->%s (%s:%d:%s)" + object_class_dynamic_cast_assert(const char *type, const char *target, const char *file, int line, const char *func) "%s->%s (%s:%d:%s)" ++ ++# hw/misc/vfio.c ++vfio_msix_fixup(const char *name, int bar, uint64_t start, uint64_t end) " (%s) MSI-X region %d mmap fixup [0x%"PRIx64" - 0x%"PRIx64"]" ++vfio_region_setup(const char *dev, int index, const char *name, unsigned long flags, unsigned long offset, unsigned long size) "Device %s, region %d \"%s\", flags: %lx, offset: %lx, size: %lx" ++vfio_region_mmap_fault(const char *name, int index, unsigned long offset, unsigned long size, int fault) "Region %s mmaps[%d], [%lx - %lx], fault: %d" ++vfio_region_mmap(const char *name, unsigned long offset, unsigned long end) "Region %s [%lx - %lx]" ++vfio_region_exit(const char *name, int index) "Device %s, region %d" ++vfio_region_finalize(const char *name, int index) "Device %s, region %d" ++vfio_region_mmaps_set_enabled(const char *name, bool enabled) "Region %s mmaps enabled: %d" +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vfio-Handle-zero-length-sparse-mmap-ranges.patch b/SOURCES/kvm-vfio-Handle-zero-length-sparse-mmap-ranges.patch new file mode 100644 index 0000000..6f40b9a --- /dev/null +++ b/SOURCES/kvm-vfio-Handle-zero-length-sparse-mmap-ranges.patch @@ -0,0 +1,110 @@ +From 9291ea1d33e70d9c01558da25ac6744ff2ef77ec Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Fri, 29 Sep 2017 21:46:24 +0200 +Subject: [PATCH 16/27] vfio: Handle zero-length sparse mmap ranges + +RH-Author: Alex Williamson +Message-id: <20170929214624.16765.84023.stgit@gimli.home> +Patchwork-id: 76774 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 16/16] vfio: Handle zero-length sparse mmap ranges +Bugzilla: 1494181 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Auger Eric +RH-Acked-by: Miroslav Rezanina + +Upstream: 24acf72b9a291cebfd05f2ecdf3a982ac01e6291 + +As reported in the link below, user has a PCI device with a 4KB BAR +which contains the MSI-X table. This seems to hit a corner case in +the kernel where the region reports being mmap capable, but the sparse +mmap information reports a zero sized range. It's not entirely clear +that the kernel is incorrect in doing this, but regardless, we need +to handle it. To do this, fill our mmap array only with non-zero +sized sparse mmap entries and add an error return from the function +so we can tell the difference between nr_mmaps being zero based on +sparse mmap info vs lack of sparse mmap info. + +NB, this doesn't actually change the behavior of the device, it only +removes the scary "Failed to mmap ... Performance may be slow" error +message. We cannot currently create an mmap over the MSI-X table. + +Link: http://lists.nongnu.org/archive/html/qemu-discuss/2016-10/msg00009.html +Signed-off-by: Alex Williamson +Signed-off-by: Miroslav Rezanina +--- + hw/misc/vfio.c | 36 ++++++++++++++++++++++-------------- + 1 file changed, 22 insertions(+), 14 deletions(-) + +diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c +index a27698b..68ff949 100644 +--- a/hw/misc/vfio.c ++++ b/hw/misc/vfio.c +@@ -2621,16 +2621,16 @@ vfio_get_region_info_cap(struct vfio_region_info *info, uint16_t id) + return NULL; + } + +-static void vfio_setup_region_sparse_mmaps(VFIORegion *region, +- struct vfio_region_info *info) ++static int vfio_setup_region_sparse_mmaps(VFIORegion *region, ++ struct vfio_region_info *info) + { + struct vfio_info_cap_header *hdr; + struct vfio_region_info_cap_sparse_mmap *sparse; +- int i; ++ int i, j; + + hdr = vfio_get_region_info_cap(info, VFIO_REGION_INFO_CAP_SPARSE_MMAP); + if (!hdr) { +- return; ++ return -ENODEV; + } + + sparse = container_of(hdr, struct vfio_region_info_cap_sparse_mmap, header); +@@ -2638,16 +2638,24 @@ static void vfio_setup_region_sparse_mmaps(VFIORegion *region, + trace_vfio_region_sparse_mmap_header(region->vbasedev->name, + region->nr, sparse->nr_areas); + +- region->nr_mmaps = sparse->nr_areas; +- region->mmaps = g_new0(VFIOMmap, region->nr_mmaps); ++ region->mmaps = g_new0(VFIOMmap, sparse->nr_areas); + +- for (i = 0; i < region->nr_mmaps; i++) { +- region->mmaps[i].offset = sparse->areas[i].offset; +- region->mmaps[i].size = sparse->areas[i].size; +- trace_vfio_region_sparse_mmap_entry(i, region->mmaps[i].offset, +- region->mmaps[i].offset + +- region->mmaps[i].size); ++ for (i = 0, j = 0; i < sparse->nr_areas; i++) { ++ trace_vfio_region_sparse_mmap_entry(i, sparse->areas[i].offset, ++ sparse->areas[i].offset + ++ sparse->areas[i].size); ++ ++ if (sparse->areas[i].size) { ++ region->mmaps[j].offset = sparse->areas[i].offset; ++ region->mmaps[j].size = sparse->areas[i].size; ++ j++; ++ } + } ++ ++ region->nr_mmaps = j; ++ region->mmaps = g_realloc(region->mmaps, j * sizeof(VFIOMmap)); ++ ++ return 0; + } + + static int vfio_region_setup(Object *obj, VFIODevice *vbasedev, +@@ -2676,9 +2684,9 @@ static int vfio_region_setup(Object *obj, VFIODevice *vbasedev, + region->flags & VFIO_REGION_INFO_FLAG_MMAP && + !(region->size & ~TARGET_PAGE_MASK)) { + +- vfio_setup_region_sparse_mmaps(region, info); ++ ret = vfio_setup_region_sparse_mmaps(region, info); + +- if (!region->nr_mmaps) { ++ if (ret) { + region->nr_mmaps = 1; + region->mmaps = g_new0(VFIOMmap, region->nr_mmaps); + region->mmaps[0].offset = 0; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vfio-Wrap-VFIO_DEVICE_GET_REGION_INFO.patch b/SOURCES/kvm-vfio-Wrap-VFIO_DEVICE_GET_REGION_INFO.patch new file mode 100644 index 0000000..bf4d416 --- /dev/null +++ b/SOURCES/kvm-vfio-Wrap-VFIO_DEVICE_GET_REGION_INFO.patch @@ -0,0 +1,213 @@ +From 474ecfa2ca12dee5c07c974a166c27652b9c9a93 Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Fri, 29 Sep 2017 21:45:50 +0200 +Subject: [PATCH 13/27] vfio: Wrap VFIO_DEVICE_GET_REGION_INFO + +RH-Author: Alex Williamson +Message-id: <20170929214550.16765.34651.stgit@gimli.home> +Patchwork-id: 76771 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 13/16] vfio: Wrap VFIO_DEVICE_GET_REGION_INFO +Bugzilla: 1494181 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Auger Eric +RH-Acked-by: Miroslav Rezanina + +Upstream: 469002263a295ec471c1498c3b456ccd9f85a841 + +In preparation for supporting capability chains on regions, wrap +ioctl(VFIO_DEVICE_GET_REGION_INFO) so we don't duplicate the code for +each caller. + +Signed-off-by: Alex Williamson +Signed-off-by: Miroslav Rezanina +--- + hw/misc/vfio.c | 95 +++++++++++++++++++++++++++++++++++----------------------- + 1 file changed, 58 insertions(+), 37 deletions(-) + +diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c +index e2dc3f5..57a0065 100644 +--- a/hw/misc/vfio.c ++++ b/hw/misc/vfio.c +@@ -292,6 +292,8 @@ static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len); + static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr, + uint32_t val, int len); + static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled); ++static int vfio_get_region_info(VFIODevice *vbasedev, int index, ++ struct vfio_region_info **info); + + /* + * Common VFIO interrupt disable +@@ -1176,26 +1178,26 @@ static const MemoryRegionOps vfio_region_ops = { + + static void vfio_pci_load_rom(VFIOPCIDevice *vdev) + { +- struct vfio_region_info reg_info = { +- .argsz = sizeof(reg_info), +- .index = VFIO_PCI_ROM_REGION_INDEX +- }; ++ struct vfio_region_info *reg_info; + uint64_t size; + off_t off = 0; + size_t bytes; + +- if (ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_REGION_INFO, ®_info)) { ++ if (vfio_get_region_info(&vdev->vbasedev, ++ VFIO_PCI_ROM_REGION_INDEX, ®_info)) { + error_report("vfio: Error getting ROM info: %m"); + return; + } + + DPRINTF("Device %s ROM:\n", vdev->vbasedev.name); + DPRINTF(" size: 0x%lx, offset: 0x%lx, flags: 0x%lx\n", +- (unsigned long)reg_info.size, (unsigned long)reg_info.offset, +- (unsigned long)reg_info.flags); ++ (unsigned long)reg_info->size, (unsigned long)reg_info->offset, ++ (unsigned long)reg_info->flags); ++ ++ vdev->rom_size = size = reg_info->size; ++ vdev->rom_offset = reg_info->offset; + +- vdev->rom_size = size = reg_info.size; +- vdev->rom_offset = reg_info.offset; ++ g_free(reg_info); + + if (!vdev->rom_size) { + vdev->rom_read_failed = true; +@@ -3483,7 +3485,7 @@ static int vfio_get_device(VFIOGroup *group, const char *name, + VFIOPCIDevice *vdev) + { + struct vfio_device_info dev_info = { .argsz = sizeof(dev_info) }; +- struct vfio_region_info reg_info = { .argsz = sizeof(reg_info) }; ++ struct vfio_region_info *reg_info; + struct vfio_irq_info irq_info = { .argsz = sizeof(irq_info) }; + int ret, i; + +@@ -3529,9 +3531,7 @@ static int vfio_get_device(VFIOGroup *group, const char *name, + } + + for (i = VFIO_PCI_BAR0_REGION_INDEX; i < VFIO_PCI_ROM_REGION_INDEX; i++) { +- reg_info.index = i; +- +- ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_REGION_INFO, ®_info); ++ ret = vfio_get_region_info(&vdev->vbasedev, i, ®_info); + if (ret) { + error_report("vfio: Error getting region %d info: %m", i); + goto error; +@@ -3539,20 +3539,21 @@ static int vfio_get_device(VFIOGroup *group, const char *name, + + DPRINTF("Device %s region %d:\n", name, i); + DPRINTF(" size: 0x%lx, offset: 0x%lx, flags: 0x%lx\n", +- (unsigned long)reg_info.size, (unsigned long)reg_info.offset, +- (unsigned long)reg_info.flags); ++ (unsigned long)reg_info->size, (unsigned long)reg_info->offset, ++ (unsigned long)reg_info->flags); + + vdev->bars[i].region.vbasedev = &vdev->vbasedev; +- vdev->bars[i].region.flags = reg_info.flags; +- vdev->bars[i].region.size = reg_info.size; +- vdev->bars[i].region.fd_offset = reg_info.offset; ++ vdev->bars[i].region.flags = reg_info->flags; ++ vdev->bars[i].region.size = reg_info->size; ++ vdev->bars[i].region.fd_offset = reg_info->offset; + vdev->bars[i].region.nr = i; + QLIST_INIT(&vdev->bars[i].quirks); +- } + +- reg_info.index = VFIO_PCI_CONFIG_REGION_INDEX; ++ g_free(reg_info); ++ } + +- ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_REGION_INFO, ®_info); ++ ret = vfio_get_region_info(&vdev->vbasedev, ++ VFIO_PCI_CONFIG_REGION_INDEX, ®_info); + if (ret) { + error_report("vfio: Error getting config info: %m"); + goto error; +@@ -3560,41 +3561,43 @@ static int vfio_get_device(VFIOGroup *group, const char *name, + + DPRINTF("Device %s config:\n", name); + DPRINTF(" size: 0x%lx, offset: 0x%lx, flags: 0x%lx\n", +- (unsigned long)reg_info.size, (unsigned long)reg_info.offset, +- (unsigned long)reg_info.flags); ++ (unsigned long)reg_info->size, (unsigned long)reg_info->offset, ++ (unsigned long)reg_info->flags); + +- vdev->config_size = reg_info.size; ++ vdev->config_size = reg_info->size; + if (vdev->config_size == PCI_CONFIG_SPACE_SIZE) { + vdev->pdev.cap_present &= ~QEMU_PCI_CAP_EXPRESS; + } +- vdev->config_offset = reg_info.offset; ++ vdev->config_offset = reg_info->offset; ++ ++ g_free(reg_info); + + if ((vdev->features & VFIO_FEATURE_ENABLE_VGA) && + dev_info.num_regions > VFIO_PCI_VGA_REGION_INDEX) { +- struct vfio_region_info vga_info = { +- .argsz = sizeof(vga_info), +- .index = VFIO_PCI_VGA_REGION_INDEX, +- }; +- +- ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_REGION_INFO, &vga_info); ++ ret = vfio_get_region_info(&vdev->vbasedev, ++ VFIO_PCI_VGA_REGION_INDEX, ®_info); + if (ret) { + error_report( + "vfio: Device does not support requested feature x-vga"); + goto error; + } + +- if (!(vga_info.flags & VFIO_REGION_INFO_FLAG_READ) || +- !(vga_info.flags & VFIO_REGION_INFO_FLAG_WRITE) || +- vga_info.size < 0xbffff + 1) { ++ if (!(reg_info->flags & VFIO_REGION_INFO_FLAG_READ) || ++ !(reg_info->flags & VFIO_REGION_INFO_FLAG_WRITE) || ++ reg_info->size < 0xbffff + 1) { + error_report("vfio: Unexpected VGA info, flags 0x%lx, size 0x%lx", +- (unsigned long)vga_info.flags, +- (unsigned long)vga_info.size); ++ (unsigned long)reg_info->flags, ++ (unsigned long)reg_info->size); ++ g_free(reg_info); ++ ret = -1; + goto error; + } + +- vdev->vga.fd_offset = vga_info.offset; ++ vdev->vga.fd_offset = reg_info->offset; + vdev->vga.fd = vdev->vbasedev.fd; + ++ g_free(reg_info); ++ + vdev->vga.region[QEMU_PCI_VGA_MEM].offset = QEMU_PCI_VGA_MEM_BASE; + vdev->vga.region[QEMU_PCI_VGA_MEM].nr = QEMU_PCI_VGA_MEM; + QLIST_INIT(&vdev->vga.region[QEMU_PCI_VGA_MEM].quirks); +@@ -3647,6 +3650,24 @@ static void vfio_put_device(VFIOPCIDevice *vdev) + } + } + ++static int vfio_get_region_info(VFIODevice *vbasedev, int index, ++ struct vfio_region_info **info) ++{ ++ size_t argsz = sizeof(struct vfio_region_info); ++ ++ *info = g_malloc0(argsz); ++ ++ (*info)->index = index; ++ (*info)->argsz = argsz; ++ ++ if (ioctl(vbasedev->fd, VFIO_DEVICE_GET_REGION_INFO, *info)) { ++ g_free(*info); ++ return -errno; ++ } ++ ++ return 0; ++} ++ + static void vfio_err_notifier_handler(void *opaque) + { + VFIOPCIDevice *vdev = opaque; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vfio-pass-device-to-vfio_mmap_bar-and-use-it-to-set-.patch b/SOURCES/kvm-vfio-pass-device-to-vfio_mmap_bar-and-use-it-to-set-.patch new file mode 100644 index 0000000..cc4c86e --- /dev/null +++ b/SOURCES/kvm-vfio-pass-device-to-vfio_mmap_bar-and-use-it-to-set-.patch @@ -0,0 +1,63 @@ +From 4adaef467772d0131b96e6dc2533b13afd8254a9 Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Fri, 29 Sep 2017 21:44:01 +0200 +Subject: [PATCH 01/27] vfio: pass device to vfio_mmap_bar and use it to set + owner + +RH-Author: Alex Williamson +Message-id: <20170929214401.16765.56856.stgit@gimli.home> +Patchwork-id: 76759 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 01/16] vfio: pass device to vfio_mmap_bar and use it to set owner +Bugzilla: 1494181 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Auger Eric +RH-Acked-by: Miroslav Rezanina + +From: Paolo Bonzini + +Upstream: 5cb022a1bfaa0c15a13d3266bc6d683cc1f44d7f +RHEL: Update vfio_mmap_bar() parameters, but RHEL memory API doesn't + support an owner, this makes later patches apply more cleanly. + +Cc: Alex Williamson +Signed-off-by: Paolo Bonzini +Signed-off-by: Miroslav Rezanina +--- + hw/misc/vfio.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c +index 4fdc09a..363c646 100644 +--- a/hw/misc/vfio.c ++++ b/hw/misc/vfio.c +@@ -2570,7 +2570,8 @@ static void vfio_unmap_bar(VFIODevice *vdev, int nr) + memory_region_destroy(&bar->mem); + } + +-static int vfio_mmap_bar(VFIOBAR *bar, MemoryRegion *mem, MemoryRegion *submem, ++static int vfio_mmap_bar(VFIODevice *vdev, VFIOBAR *bar, ++ MemoryRegion *mem, MemoryRegion *submem, + void **map, size_t size, off_t offset, + const char *name) + { +@@ -2654,7 +2655,7 @@ static void vfio_map_bar(VFIODevice *vdev, int nr) + } + + strncat(name, " mmap", sizeof(name) - strlen(name) - 1); +- if (vfio_mmap_bar(bar, &bar->mem, ++ if (vfio_mmap_bar(vdev, bar, &bar->mem, + &bar->mmap_mem, &bar->mmap, size, 0, name)) { + error_report("%s unsupported. Performance may be slow", name); + } +@@ -2668,7 +2669,7 @@ static void vfio_map_bar(VFIODevice *vdev, int nr) + size = start < bar->size ? bar->size - start : 0; + strncat(name, " msix-hi", sizeof(name) - strlen(name) - 1); + /* VFIOMSIXInfo contains another MemoryRegion for this mapping */ +- if (vfio_mmap_bar(bar, &bar->mem, &vdev->msix->mmap_mem, ++ if (vfio_mmap_bar(vdev, bar, &bar->mem, &vdev->msix->mmap_mem, + &vdev->msix->mmap, size, start, name)) { + error_report("%s unsupported. Performance may be slow", name); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vfio-pci-Fix-incorrect-error-message.patch b/SOURCES/kvm-vfio-pci-Fix-incorrect-error-message.patch new file mode 100644 index 0000000..bdb7ba7 --- /dev/null +++ b/SOURCES/kvm-vfio-pci-Fix-incorrect-error-message.patch @@ -0,0 +1,50 @@ +From 0dadf0b76c9236d048c203fb5b9baaf3fe6fac15 Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Fri, 29 Sep 2017 21:45:44 +0200 +Subject: [PATCH 12/27] vfio/pci: Fix incorrect error message + +RH-Author: Alex Williamson +Message-id: <20170929214544.16765.85472.stgit@gimli.home> +Patchwork-id: 76770 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 12/16] vfio/pci: Fix incorrect error message +Bugzilla: 1494181 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Auger Eric +RH-Acked-by: Miroslav Rezanina + +From: Dong Jia Shi + +Upstream: 6e4e6f0d403b1fb25f9dfdbe17754c643997753d + +When the "No host device provided" error occurs, the hint message +that starts with "Use -vfio-pci," makes no sense, since "-vfio-pci" +is not a valid command line parameter. + +Correct this by replacing "-vfio-pci" with "-device vfio-pci". + +Signed-off-by: Dong Jia Shi +Reviewed-by: Eric Auger +Signed-off-by: Alex Williamson +Signed-off-by: Miroslav Rezanina +--- + hw/misc/vfio.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c +index a95bbaf..e2dc3f5 100644 +--- a/hw/misc/vfio.c ++++ b/hw/misc/vfio.c +@@ -3867,8 +3867,8 @@ static int vfio_initfn(PCIDevice *pdev) + if (!(~vdev->host.domain || ~vdev->host.bus || + ~vdev->host.slot || ~vdev->host.function)) { + error_report("No provided host device - " +- "Use -vfio-pci,host=DDDD:BB:DD.F " +- "or -vfio-pci,sysfsdev=PATH_TO_DEVICE"); ++ "Use -device vfio-pci,host=DDDD:BB:DD.F " ++ "or -device vfio-pci,sysfsdev=PATH_TO_DEVICE"); + return -EINVAL; + } + vdev->vbasedev.sysfsdev = +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vfio-pci-Handle-host-oversight.patch b/SOURCES/kvm-vfio-pci-Handle-host-oversight.patch new file mode 100644 index 0000000..85b2469 --- /dev/null +++ b/SOURCES/kvm-vfio-pci-Handle-host-oversight.patch @@ -0,0 +1,64 @@ +From 9f8e26c9d8485647072b2cbe7848b8d0054597c6 Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Fri, 29 Sep 2017 21:45:31 +0200 +Subject: [PATCH 11/27] vfio/pci: Handle host oversight + +RH-Author: Alex Williamson +Message-id: <20170929214531.16765.45212.stgit@gimli.home> +Patchwork-id: 76769 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 11/16] vfio/pci: Handle host oversight +Bugzilla: 1494181 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Auger Eric +RH-Acked-by: Miroslav Rezanina + +From: Eric Auger + +Upstream: 4a946268504e72fe0c547b9dda97adbe277a585f + +In case the end-user calls qemu with -vfio-pci option without passing +either sysfsdev or host property value, the device is interpreted as +0000:00:00.0. Let's create a specific error message to guide the end-user. + +Signed-off-by: Eric Auger +Reviewed-by: Markus Armbruster +Signed-off-by: Alex Williamson +Signed-off-by: Miroslav Rezanina +--- + hw/misc/vfio.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c +index 0af8613..a95bbaf 100644 +--- a/hw/misc/vfio.c ++++ b/hw/misc/vfio.c +@@ -3864,6 +3864,13 @@ static int vfio_initfn(PCIDevice *pdev) + } + + if (!vdev->vbasedev.sysfsdev) { ++ if (!(~vdev->host.domain || ~vdev->host.bus || ++ ~vdev->host.slot || ~vdev->host.function)) { ++ error_report("No provided host device - " ++ "Use -vfio-pci,host=DDDD:BB:DD.F " ++ "or -vfio-pci,sysfsdev=PATH_TO_DEVICE"); ++ return -EINVAL; ++ } + vdev->vbasedev.sysfsdev = + g_strdup_printf("/sys/bus/pci/devices/%04x:%02x:%02x.%01x", + vdev->host.domain, vdev->host.bus, +@@ -4062,6 +4069,12 @@ post_reset: + + static void vfio_instance_init(Object *obj) + { ++ VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, PCI_DEVICE(obj)); ++ ++ vdev->host.domain = ~0U; ++ vdev->host.bus = ~0U; ++ vdev->host.slot = ~0U; ++ vdev->host.function = ~0U; + } + + static Property vfio_pci_dev_properties[] = { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vfio-pci-Only-mmap-TARGET_PAGE_SIZE-regions.patch b/SOURCES/kvm-vfio-pci-Only-mmap-TARGET_PAGE_SIZE-regions.patch deleted file mode 100644 index 8b84636..0000000 --- a/SOURCES/kvm-vfio-pci-Only-mmap-TARGET_PAGE_SIZE-regions.patch +++ /dev/null @@ -1,61 +0,0 @@ -From daa0c48addc50413b79612d9e7251a9cbf35af48 Mon Sep 17 00:00:00 2001 -From: Alex Williamson -Date: Mon, 20 Nov 2017 16:21:44 +0100 -Subject: [PATCH] vfio/pci: Only mmap >= TARGET_PAGE_SIZE regions - -RH-Author: Alex Williamson -Message-id: <20171120162044.30263.60064.stgit@gimli.home> -Patchwork-id: 77755 -O-Subject: [RHEL-7.4.z qemu-kvm PATCH] vfio/pci: Only mmap >= TARGET_PAGE_SIZE regions -Bugzilla: 1515110 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Thomas Huth -RH-Acked-by: Auger Eric - -Upstream Status: RHEL-only (very small subset of db0da029a185) -Tested: Teradici USB assignment - -Upstream kernel commit 05f0c03fbac1 ('vfio-pci: Allow to mmap sub-page -MMIO BARs if the mmio page is exclusive') [RHEL-7.4 390f15a45024] allows -vfio-pci to expose the VFIO_REGION_INFO_FLAG_MMAP flag, indicating the -region can be mmap'd, for sub-page PCI BARs iff the BAR is page aligned -and the remainder of the page can be reserved to ensure that it's not -used for other purposes. Unfortunately QEMU versions prior to v2.6.0 -blindly accept the MMAP flag with no special handling of these sub-page -mmaps. This went unnoticed upstream, but was inadvertently fixed by -commit db0da029a185 ('vfio: Generalize region support') which ensures -that the region size is a multiple of page size. This returns us to -the previous behavior where sub-page regions are not mmap'd, even though -the kernel now allows it. This QEMU commit has since been picked up in -qemu-kvm with the backport of the above as a33e922436f7. qemu-kvm-rhev -has had this support since RHEL-7.3. Furthermore, upstream commit -95251725e335 ('vfio: Add support for mmapping sub-page MMIO BARs') -allows QEMU to fully make use of these sub-page mmaps. qemu-kvm-rhev -acquired this capability in the RHEL-7.4 rebase. - -Here we extract only the portion of db0da029a185 which excludes sub-page -regions from being mmap'd. - -Signed-off-by: Alex Williamson -Signed-off-by: Miroslav Rezanina ---- - hw/misc/vfio.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c -index 4fdc09a..adfefec 100644 ---- a/hw/misc/vfio.c -+++ b/hw/misc/vfio.c -@@ -2576,7 +2576,8 @@ static int vfio_mmap_bar(VFIOBAR *bar, MemoryRegion *mem, MemoryRegion *submem, - { - int ret = 0; - -- if (VFIO_ALLOW_MMAP && size && bar->flags & VFIO_REGION_INFO_FLAG_MMAP) { -+ if (VFIO_ALLOW_MMAP && size && bar->flags & VFIO_REGION_INFO_FLAG_MMAP && -+ !(size & ~TARGET_PAGE_MASK)) { - int prot = 0; - - if (bar->flags & VFIO_REGION_INFO_FLAG_READ) { --- -1.8.3.1 - diff --git a/SOURCES/kvm-vfio-remove-bootindex-property-from-qdev-to-qom.patch b/SOURCES/kvm-vfio-remove-bootindex-property-from-qdev-to-qom.patch new file mode 100644 index 0000000..e95987b --- /dev/null +++ b/SOURCES/kvm-vfio-remove-bootindex-property-from-qdev-to-qom.patch @@ -0,0 +1,58 @@ +From 394cb4371862245164782e8a98910bc78f90c629 Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Fri, 29 Sep 2017 21:45:24 +0200 +Subject: [PATCH 10/27] vfio: remove bootindex property from qdev to qom + +RH-Author: Alex Williamson +Message-id: <20170929214524.16765.24180.stgit@gimli.home> +Patchwork-id: 76767 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 10/16] vfio: remove bootindex property from qdev to qom +Bugzilla: 1494181 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Auger Eric +RH-Acked-by: Miroslav Rezanina + +From: Gonglei + +Upstream: abc5b3bfe1c77ad622188341d1ee4d49de308ae3 +RHEL: Only taking the instance_init infrastructure, bootindex not + moved and vars removed to allow clean build, re-added later. + +Remove bootindex form qdev property to qom, things will +continue to work just fine, and we can use qom features +which are not supported by qdev property. + +Signed-off-by: Gonglei +Reviewed-by: Gerd Hoffmann +Signed-off-by: Gerd Hoffmann +Signed-off-by: Miroslav Rezanina +--- + hw/misc/vfio.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c +index 64d4dc7..0af8613 100644 +--- a/hw/misc/vfio.c ++++ b/hw/misc/vfio.c +@@ -4060,6 +4060,10 @@ post_reset: + vfio_pci_post_reset(vdev); + } + ++static void vfio_instance_init(Object *obj) ++{ ++} ++ + static Property vfio_pci_dev_properties[] = { + DEFINE_PROP_PCI_HOST_DEVADDR("host", VFIOPCIDevice, host), + DEFINE_PROP_STRING("sysfsdev", VFIOPCIDevice, vbasedev.sysfsdev), +@@ -4105,6 +4109,7 @@ static const TypeInfo vfio_pci_dev_info = { + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(VFIOPCIDevice), + .class_init = vfio_pci_dev_class_init, ++ .instance_init = vfio_instance_init, + }; + + static void register_vfio_pci_dev_type(void) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vga-Add-mechanism-to-force-the-use-of-a-shadow-surfa.patch b/SOURCES/kvm-vga-Add-mechanism-to-force-the-use-of-a-shadow-surfa.patch index 144892b..92e7f61 100644 --- a/SOURCES/kvm-vga-Add-mechanism-to-force-the-use-of-a-shadow-surfa.patch +++ b/SOURCES/kvm-vga-Add-mechanism-to-force-the-use-of-a-shadow-surfa.patch @@ -1,13 +1,13 @@ -From c7b591dff2d72eb1571f05d7f328471954980966 Mon Sep 17 00:00:00 2001 +From 3067d5947bd28c5c05ba8dc7c87b70edc6157a27 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 20 Oct 2017 11:06:17 +0200 -Subject: [PATCH 09/11] vga: Add mechanism to force the use of a shadow surface +Subject: [PATCH 2/7] vga: Add mechanism to force the use of a shadow surface RH-Author: Gerd Hoffmann Message-id: <20171020110619.2541-10-kraxel@redhat.com> Patchwork-id: 77409 O-Subject: [RHEL-7.5 qemu-kvm PATCH 09/11] vga: Add mechanism to force the use of a shadow surface -Bugzilla: 1501294 +Bugzilla: 1501295 RH-Acked-by: Stefan Hajnoczi RH-Acked-by: Dr. David Alan Gilbert RH-Acked-by: Miroslav Rezanina diff --git a/SOURCES/kvm-vga-Remove-remainder-of-old-conversion-cruft.patch b/SOURCES/kvm-vga-Remove-remainder-of-old-conversion-cruft.patch index 189ccca..a3121ab 100644 --- a/SOURCES/kvm-vga-Remove-remainder-of-old-conversion-cruft.patch +++ b/SOURCES/kvm-vga-Remove-remainder-of-old-conversion-cruft.patch @@ -1,13 +1,13 @@ -From 83143be104bdf9d750078d4331c53c66581f7b26 Mon Sep 17 00:00:00 2001 +From d177da08e3ad6ff44abdc0887fd513a0c8222d48 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 5 Oct 2017 14:51:16 +0200 -Subject: [PATCH 04/11] vga: Remove remainder of old conversion cruft +Subject: [PATCH 20/27] vga: Remove remainder of old conversion cruft RH-Author: Gerd Hoffmann Message-id: <20171005145119.15277-5-kraxel@redhat.com> Patchwork-id: 76826 O-Subject: [RHEL-7.5 qemu-kvm PATCH 4/7] vga: Remove remainder of old conversion cruft -Bugzilla: 1501294 +Bugzilla: 1486642 RH-Acked-by: Dr. David Alan Gilbert RH-Acked-by: Thomas Huth RH-Acked-by: Miroslav Rezanina diff --git a/SOURCES/kvm-vga-Rename-vga_template.h-to-vga-helpers.h.patch b/SOURCES/kvm-vga-Rename-vga_template.h-to-vga-helpers.h.patch index a028674..fe4de16 100644 --- a/SOURCES/kvm-vga-Rename-vga_template.h-to-vga-helpers.h.patch +++ b/SOURCES/kvm-vga-Rename-vga_template.h-to-vga-helpers.h.patch @@ -1,13 +1,13 @@ -From d5e0842eca8498600dac7114a0e0a617df7f4ea4 Mon Sep 17 00:00:00 2001 +From b97bdaf62f567d661feaf69662cb176e43ceba60 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 5 Oct 2017 14:51:18 +0200 -Subject: [PATCH 06/11] vga: Rename vga_template.h to vga-helpers.h +Subject: [PATCH 22/27] vga: Rename vga_template.h to vga-helpers.h RH-Author: Gerd Hoffmann Message-id: <20171005145119.15277-7-kraxel@redhat.com> Patchwork-id: 76822 O-Subject: [RHEL-7.5 qemu-kvm PATCH 6/7] vga: Rename vga_template.h to vga-helpers.h -Bugzilla: 1501294 +Bugzilla: 1486642 RH-Acked-by: Dr. David Alan Gilbert RH-Acked-by: Thomas Huth RH-Acked-by: Miroslav Rezanina diff --git a/SOURCES/kvm-vga-Separate-LE-and-BE-conversion-functions.patch b/SOURCES/kvm-vga-Separate-LE-and-BE-conversion-functions.patch index 36b14a4..4bb351b 100644 --- a/SOURCES/kvm-vga-Separate-LE-and-BE-conversion-functions.patch +++ b/SOURCES/kvm-vga-Separate-LE-and-BE-conversion-functions.patch @@ -1,13 +1,13 @@ -From 6b22d494d91773be44318574e14cc59491c8f77f Mon Sep 17 00:00:00 2001 +From 83678480936d5e15ffb30321a6f61e443bc1012f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 5 Oct 2017 14:51:17 +0200 -Subject: [PATCH 05/11] vga: Separate LE and BE conversion functions +Subject: [PATCH 21/27] vga: Separate LE and BE conversion functions RH-Author: Gerd Hoffmann Message-id: <20171005145119.15277-6-kraxel@redhat.com> Patchwork-id: 76824 O-Subject: [RHEL-7.5 qemu-kvm PATCH 5/7] vga: Separate LE and BE conversion functions -Bugzilla: 1501294 +Bugzilla: 1486642 RH-Acked-by: Dr. David Alan Gilbert RH-Acked-by: Thomas Huth RH-Acked-by: Miroslav Rezanina diff --git a/SOURCES/kvm-vga-Start-cutting-out-non-32bpp-conversion-support.patch b/SOURCES/kvm-vga-Start-cutting-out-non-32bpp-conversion-support.patch index 521c307..222b708 100644 --- a/SOURCES/kvm-vga-Start-cutting-out-non-32bpp-conversion-support.patch +++ b/SOURCES/kvm-vga-Start-cutting-out-non-32bpp-conversion-support.patch @@ -1,13 +1,13 @@ -From 7839b693640dc53bd97279b99b1a2747883ada2a Mon Sep 17 00:00:00 2001 +From 08caae6c10ff9769921e408b0faa41f8c952f653 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 5 Oct 2017 14:51:15 +0200 -Subject: [PATCH 03/11] vga: Start cutting out non-32bpp conversion support +Subject: [PATCH 19/27] vga: Start cutting out non-32bpp conversion support RH-Author: Gerd Hoffmann Message-id: <20171005145119.15277-4-kraxel@redhat.com> Patchwork-id: 76825 O-Subject: [RHEL-7.5 qemu-kvm PATCH 3/7] vga: Start cutting out non-32bpp conversion support -Bugzilla: 1501294 +Bugzilla: 1486642 RH-Acked-by: Dr. David Alan Gilbert RH-Acked-by: Thomas Huth RH-Acked-by: Miroslav Rezanina diff --git a/SOURCES/kvm-vga-check-the-validation-of-memory-addr-when-draw-te.patch b/SOURCES/kvm-vga-check-the-validation-of-memory-addr-when-draw-te.patch new file mode 100644 index 0000000..4280086 --- /dev/null +++ b/SOURCES/kvm-vga-check-the-validation-of-memory-addr-when-draw-te.patch @@ -0,0 +1,69 @@ +From 5c99bd7a9de1f1a64d948776482ae7103091fac2 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 26 Jan 2018 07:30:05 +0100 +Subject: [PATCH 2/4] vga: check the validation of memory addr when draw text + +RH-Author: Gerd Hoffmann +Message-id: <20180126073005.15344-2-kraxel@redhat.com> +Patchwork-id: 78710 +O-Subject: [RHEL-7.5 qemu-kvm PATCH 1/1] vga: check the validation of memory addr when draw text +Bugzilla: 1534691 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Miroslav Rezanina + +From: linzhecheng + +Start a vm with qemu-kvm -enable-kvm -vnc :66 -smp 1 -m 1024 -hda +redhat_5.11.qcow2 -device pcnet -vga cirrus, +then use VNC client to connect to VM, and excute the code below in guest +OS will lead to qemu crash: + +int main() + { + iopl(3); + srand(time(NULL)); + int a,b; + while(1){ + a = rand()%0x100; + b = 0x3c0 + (rand()%0x20); + outb(a,b); + } + return 0; +} + +The above code is writing the registers of VGA randomly. +We can write VGA CRT controller registers index 0x0C or 0x0D +(which is the start address register) to modify the +the display memory address of the upper left pixel +or character of the screen. The address may be out of the +range of vga ram. So we should check the validation of memory address +when reading or writing it to avoid segfault. + +Signed-off-by: linzhecheng +Message-id: 20180111132724.13744-1-linzhecheng@huawei.com +Fixes: CVE-2018-5683 +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 191f59dc17396bb5a8da50f8c59b6e0a430711a4) +Signed-off-by: Miroslav Rezanina +--- + hw/display/vga.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/hw/display/vga.c b/hw/display/vga.c +index c40744f..017e951 100644 +--- a/hw/display/vga.c ++++ b/hw/display/vga.c +@@ -1328,6 +1328,9 @@ static void vga_draw_text(VGACommonState *s, int full_update) + cx_min = width; + cx_max = -1; + for(cx = 0; cx < width; cx++) { ++ if (src + sizeof(uint16_t) > s->vram_ptr + s->vram_size) { ++ break; ++ } + ch_attr = *(uint16_t *)src; + if (full_update || ch_attr != *ch_attr_ptr || src == cursor_ptr) { + if (cx < cx_min) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vga-drop-line_offset-variable.patch b/SOURCES/kvm-vga-drop-line_offset-variable.patch index eeea0de..fbbb2b8 100644 --- a/SOURCES/kvm-vga-drop-line_offset-variable.patch +++ b/SOURCES/kvm-vga-drop-line_offset-variable.patch @@ -1,13 +1,13 @@ -From 68dd20867cb9103d0d51ba0223d677e74b7cc51a Mon Sep 17 00:00:00 2001 +From 52c3ce4ea3447ae11bd18184b7659c130ec676df Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 20 Oct 2017 11:06:16 +0200 -Subject: [PATCH 08/11] vga: drop line_offset variable +Subject: [PATCH 1/7] vga: drop line_offset variable RH-Author: Gerd Hoffmann Message-id: <20171020110619.2541-9-kraxel@redhat.com> Patchwork-id: 77399 O-Subject: [RHEL-7.5 qemu-kvm PATCH 08/11] vga: drop line_offset variable -Bugzilla: 1501294 +Bugzilla: 1501295 RH-Acked-by: Stefan Hajnoczi RH-Acked-by: Dr. David Alan Gilbert RH-Acked-by: Miroslav Rezanina diff --git a/SOURCES/kvm-vga-handle-cirrus-vbe-mode-wraparounds.patch b/SOURCES/kvm-vga-handle-cirrus-vbe-mode-wraparounds.patch index 38c14d2..e2ea070 100644 --- a/SOURCES/kvm-vga-handle-cirrus-vbe-mode-wraparounds.patch +++ b/SOURCES/kvm-vga-handle-cirrus-vbe-mode-wraparounds.patch @@ -1,13 +1,13 @@ -From d120e85aeaaeb925ef3fb63a5f962ef64ae26815 Mon Sep 17 00:00:00 2001 +From 90ded2892509c6c62140b907c7d036964cf312d5 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 20 Oct 2017 11:06:18 +0200 -Subject: [PATCH 10/11] vga: handle cirrus vbe mode wraparounds. +Subject: [PATCH 3/7] vga: handle cirrus vbe mode wraparounds. RH-Author: Gerd Hoffmann Message-id: <20171020110619.2541-11-kraxel@redhat.com> Patchwork-id: 77404 O-Subject: [RHEL-7.5 qemu-kvm PATCH 10/11] vga: handle cirrus vbe mode wraparounds. -Bugzilla: 1501294 +Bugzilla: 1501295 RH-Acked-by: Stefan Hajnoczi RH-Acked-by: Dr. David Alan Gilbert RH-Acked-by: Miroslav Rezanina diff --git a/SOURCES/kvm-vga-stop-passing-pointers-to-vga_draw_line-functions.patch b/SOURCES/kvm-vga-stop-passing-pointers-to-vga_draw_line-functions.patch index 412e986..c21ef03 100644 --- a/SOURCES/kvm-vga-stop-passing-pointers-to-vga_draw_line-functions.patch +++ b/SOURCES/kvm-vga-stop-passing-pointers-to-vga_draw_line-functions.patch @@ -1,13 +1,13 @@ -From 1ac530769380bb6e481e97502925b656efdfa8fc Mon Sep 17 00:00:00 2001 +From e56700784b7585dddff0713ea52b2b00b8531b7f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 5 Oct 2017 14:51:19 +0200 -Subject: [PATCH 07/11] vga: stop passing pointers to vga_draw_line* functions +Subject: [PATCH 23/27] vga: stop passing pointers to vga_draw_line* functions RH-Author: Gerd Hoffmann Message-id: <20171005145119.15277-8-kraxel@redhat.com> Patchwork-id: 76828 O-Subject: [RHEL-7.5 qemu-kvm PATCH 7/7] vga: stop passing pointers to vga_draw_line* functions -Bugzilla: 1501294 +Bugzilla: 1486642 RH-Acked-by: Dr. David Alan Gilbert RH-Acked-by: Thomas Huth RH-Acked-by: Miroslav Rezanina diff --git a/SOURCES/kvm-virtio-net-dynamic-network-offloads-configuration.patch b/SOURCES/kvm-virtio-net-dynamic-network-offloads-configuration.patch index 7cd2cc1..65e26dd 100644 --- a/SOURCES/kvm-virtio-net-dynamic-network-offloads-configuration.patch +++ b/SOURCES/kvm-virtio-net-dynamic-network-offloads-configuration.patch @@ -1,13 +1,13 @@ -From 4fcf18be2584d1e2071b55f0987169a715890cca Mon Sep 17 00:00:00 2001 +From bb34da88524f313681005435f8fd6d905ca81b6a Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 17 Aug 2017 09:45:35 +0200 -Subject: [PATCH 1/2] virtio-net: dynamic network offloads configuration +Subject: [PATCH 2/4] virtio-net: dynamic network offloads configuration RH-Author: Dr. David Alan Gilbert Message-id: <20170817094536.12740-2-dgilbert@redhat.com> Patchwork-id: 76021 O-Subject: [RHEL-7.5/7.4.z/7.3.z/7.2.z qemu-kvm PATCH v2 1/2] virtio-net: dynamic network offloads configuration -Bugzilla: 1482468 +Bugzilla: 1480428 RH-Acked-by: Eduardo Habkost RH-Acked-by: Michael S. Tsirkin RH-Acked-by: Thomas Huth diff --git a/SOURCES/kvm-virtio-net-validate-backend-queue-numbers-against-bu.patch b/SOURCES/kvm-virtio-net-validate-backend-queue-numbers-against-bu.patch new file mode 100644 index 0000000..0d85a2a --- /dev/null +++ b/SOURCES/kvm-virtio-net-validate-backend-queue-numbers-against-bu.patch @@ -0,0 +1,67 @@ +From 30860f89b8dc79b24906e8f7d6d6aa0788616bd1 Mon Sep 17 00:00:00 2001 +From: Xiao Wang +Date: Thu, 18 Jan 2018 08:16:16 +0100 +Subject: [PATCH 1/3] virtio-net: validate backend queue numbers against bus + limitation + +RH-Author: Xiao Wang +Message-id: <1516263376-6261-1-git-send-email-jasowang@redhat.com> +Patchwork-id: 78662 +O-Subject: [RHEL7.5 qemu-kvm PATCH] virtio-net: validate backend queue numbers against bus limitation +Bugzilla: 1460872 +RH-Acked-by: wexu@redhat.com +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +Notes: conflict since RHEL7 lacks: +- 575a1c0e4228 ("net: move queue number into NICPeers") +- e6f746b380ad ("virtio-net: Convert to QOM realize") + +We don't validate the backend queue numbers against bus limitation, +this will easily crash qemu if it exceeds the limitation which will +hit the abort() in virtio_del_queue(). An example is trying to +starting a virtio-net device with 256 queues. E.g: + +./qemu-system-x86_64 -netdev tap,id=hn0,queues=256 -device +virtio-net-pci,netdev=hn0 + +Fixing this by doing the validation and fail early. + +Cc: Michael S. Tsirkin +Cc: qemu-stable +Signed-off-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Stefan Hajnoczi +(cherry picked from commit 7e0e736ecdfeac6d3517513d3a702304e4f6cf59) +Signed-off-by: Jason Wang +Signed-off-by: Miroslav Rezanina + +Conflicts: + hw/net/virtio-net.c +--- + hw/net/virtio-net.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index eb2feaf..3e41acc 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -1535,6 +1535,14 @@ static int virtio_net_device_init(VirtIODevice *vdev) + n->config_size); + + n->max_queues = MAX(n->nic_conf.queues, 1); ++ if (n->max_queues * 2 + 1 > VIRTIO_PCI_QUEUE_MAX) { ++ error_report("Invalid number of queues (= %" PRIu32 "), " ++ "must be a postive integer less than %d.", ++ n->max_queues, (VIRTIO_PCI_QUEUE_MAX - 1) / 2); ++ virtio_cleanup(vdev); ++ return -EINVAL; ++ } ++ + n->vqs = g_malloc0(sizeof(VirtIONetQueue) * n->max_queues); + n->vqs[0].rx_vq = virtio_add_queue(vdev, 256, virtio_net_handle_rx); + n->curr_queues = 1; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vmcoreinfo-put-it-in-the-misc-device-category.patch b/SOURCES/kvm-vmcoreinfo-put-it-in-the-misc-device-category.patch new file mode 100644 index 0000000..44cc754 --- /dev/null +++ b/SOURCES/kvm-vmcoreinfo-put-it-in-the-misc-device-category.patch @@ -0,0 +1,43 @@ +From b616fce364cb20904fb53ac9744abba20180c322 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 13 Dec 2017 13:38:44 +0100 +Subject: [PATCH 13/41] vmcoreinfo: put it in the 'misc' device category +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20171213133912.26176-14-marcandre.lureau@redhat.com> +Patchwork-id: 78363 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 13/41] vmcoreinfo: put it in the 'misc' device category +Bugzilla: 1411490 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Miroslav Rezanina + +Signed-off-by: Marc-André Lureau +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin + +(cherry picked from commit b948bb55dac527ae6b0c5e6dc69d00866a3a6fee) +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + hw/misc/vmcoreinfo.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/misc/vmcoreinfo.c b/hw/misc/vmcoreinfo.c +index 1bf6735..fa5f610 100644 +--- a/hw/misc/vmcoreinfo.c ++++ b/hw/misc/vmcoreinfo.c +@@ -79,6 +79,7 @@ static void vmcoreinfo_device_class_init(ObjectClass *klass, void *data) + + dc->vmsd = &vmstate_vmcoreinfo; + dc->realize = vmcoreinfo_realize; ++ set_bit(DEVICE_CATEGORY_MISC, dc->categories); + } + + static const TypeInfo vmcoreinfo_device_info = { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vnc-Fix-qemu-crashed-when-vnc-client-disconnect-sudd.patch b/SOURCES/kvm-vnc-Fix-qemu-crashed-when-vnc-client-disconnect-sudd.patch new file mode 100644 index 0000000..985a389 --- /dev/null +++ b/SOURCES/kvm-vnc-Fix-qemu-crashed-when-vnc-client-disconnect-sudd.patch @@ -0,0 +1,70 @@ +From 74eb4b3e1fcc6d36de0116c2fbbaa308191a1ab7 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:15 +0100 +Subject: [PATCH 01/27] vnc: Fix qemu crashed when vnc client disconnect + suddenly + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-2-berrange@redhat.com> +Patchwork-id: 78947 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 01/27] vnc: Fix qemu crashed when vnc client disconnect suddenly +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +From: "Gonglei (Arei)" + +Hi, + +When I use RealVNC viewer client (http://www.realvnc.com/) to connect vnc server, +the client disconnect suddenly, and I click reconnect button immediately, then the Qemu crashed. + +In the function vnc_worker_thread_loop, will call vnc_async_encoding_start +to set the local vs->output buffer by global queue's buffer. Then send rectangles to +the vnc client call function vnc_send_framebuffer_update. Finally, Under normal circumstances, +call vnc_async_encoding_end to set the global queue'buffer by the local vs->output conversely. + +When the vnc client disconnect, the job->vs->csock will be set to -1. And the current prcoess +logic will goto disconnected partion without call function vnc_async_encoding_end. +But, the function vnc_send_framebuffer_update will call buffer_reserve, which +maybe call g_realloc reset the local vs's buffer, meaning the global queue's buffer is modified also. +If anyone use the original global queue's buffer memory will cause corruption and then crash qemu. + +This patch assure the function vnc_async_encoding_end being called +even though the vnc client disconnect suddenly. + +Signed-off-by: Gonglei +Signed-off-by: Gerd Hoffmann +(cherry picked from commit e3c1adf16e38714ebd761dd02517dd07760ba6d2) +Signed-off-by: Miroslav Rezanina +--- + ui/vnc-jobs.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c +index 2d3fce8..a141f40 100644 +--- a/ui/vnc-jobs.c ++++ b/ui/vnc-jobs.c +@@ -252,6 +252,8 @@ static int vnc_worker_thread_loop(VncJobQueue *queue) + + if (job->vs->csock == -1) { + vnc_unlock_display(job->vs->vd); ++ /* Copy persistent encoding data */ ++ vnc_async_encoding_end(job->vs, &vs); + goto disconnected; + } + +@@ -278,6 +280,9 @@ static int vnc_worker_thread_loop(VncJobQueue *queue) + vnc_async_encoding_end(job->vs, &vs); + + qemu_bh_schedule(job->vs->bh); ++ } else { ++ /* Copy persistent encoding data */ ++ vnc_async_encoding_end(job->vs, &vs); + } + vnc_unlock_output(job->vs); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vnc-add-vnc_width-vnc_height-helpers.patch b/SOURCES/kvm-vnc-add-vnc_width-vnc_height-helpers.patch new file mode 100644 index 0000000..0ca2313 --- /dev/null +++ b/SOURCES/kvm-vnc-add-vnc_width-vnc_height-helpers.patch @@ -0,0 +1,63 @@ +From 2f0eb4848baaa020132d5848a5d05e9db55fb15c Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:24 +0100 +Subject: [PATCH 10/27] vnc: add vnc_width+vnc_height helpers + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-11-berrange@redhat.com> +Patchwork-id: 78943 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 10/27] vnc: add vnc_width+vnc_height helpers +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +From: Gerd Hoffmann + +Signed-off-by: Gerd Hoffmann +Reviewed-by: Peter Lieven +Reviewed-by: Daniel P. Berrange +Message-id: 1446203414-4013-12-git-send-email-kraxel@redhat.com +(cherry picked from commit d05959c2e111858bb83c40ae5d8b8c10964b7bb0) +Signed-off-by: Miroslav Rezanina +--- + ui/vnc.c | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +diff --git a/ui/vnc.c b/ui/vnc.c +index 9923d24..c3f29df 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -426,6 +426,17 @@ static void framebuffer_update_request(VncState *vs, int incremental, + static void vnc_refresh(DisplayChangeListener *dcl); + static int vnc_refresh_server_surface(VncDisplay *vd); + ++static int vnc_width(VncDisplay *vd) ++{ ++ return MIN(VNC_MAX_WIDTH, ROUND_UP(surface_width(vd->ds), ++ VNC_DIRTY_PIXELS_PER_BIT)); ++} ++ ++static int vnc_height(VncDisplay *vd) ++{ ++ return MIN(VNC_MAX_HEIGHT, surface_height(vd->ds)); ++} ++ + static void vnc_set_area_dirty(DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT], + VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT), + int width, int height, +@@ -614,9 +625,8 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl, + /* server surface */ + qemu_pixman_image_unref(vd->server); + vd->ds = surface; +- width = MIN(VNC_MAX_WIDTH, ROUND_UP(surface_width(vd->ds), +- VNC_DIRTY_PIXELS_PER_BIT)); +- height = MIN(VNC_MAX_HEIGHT, surface_height(vd->ds)); ++ width = vnc_width(vd); ++ height = vnc_height(vd); + vd->server = pixman_image_create_bits(VNC_SERVER_FB_FORMAT, + width, height, NULL, 0); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vnc-allow-to-connect-with-add_client-when-vnc-none.patch b/SOURCES/kvm-vnc-allow-to-connect-with-add_client-when-vnc-none.patch new file mode 100644 index 0000000..15c6a89 --- /dev/null +++ b/SOURCES/kvm-vnc-allow-to-connect-with-add_client-when-vnc-none.patch @@ -0,0 +1,55 @@ +From d8e67658b944a2b0f235c4384909c2efce4671bd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Fri, 9 Jun 2017 14:23:37 +0200 +Subject: [PATCH 1/4] vnc: allow to connect with add_client when -vnc none +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20170609142337.10457-1-marcandre.lureau@redhat.com> +Patchwork-id: 75568 +O-Subject: [RHEL-7.4 qemu-kvm PATCH] vnc: allow to connect with add_client when -vnc none +Bugzilla: 1435352 +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Laurent Vivier +RH-Acked-by: Laszlo Ersek + +Do not skip VNC initialization, in particular of auth method when vnc is +configured without sockets, since we should still allow connections +through QMP add_client. + +Upstream-status: similar to commit fa03cb7fd212. However, the upstream +code changed significantly, so the patch is different. + +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + ui/vnc.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/ui/vnc.c b/ui/vnc.c +index 1834db0..29b216c 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -2993,8 +2993,6 @@ void vnc_display_open(DisplayState *ds, const char *display, Error **errp) + return; + } + vnc_display_close(ds); +- if (strcmp(display, "none") == 0) +- return; + + vs->display = g_strdup(display); + vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE; +@@ -3219,7 +3217,7 @@ void vnc_display_open(DisplayState *ds, const char *display, Error **errp) + goto fail; + } + vnc_connect(vs, csock, 0, 0); +- } else { ++ } else if (strcmp(display, "none")) { + /* listen for connects */ + char *dpy; + dpy = g_malloc(256); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vnc-factor-out-vnc_update_server_surface.patch b/SOURCES/kvm-vnc-factor-out-vnc_update_server_surface.patch new file mode 100644 index 0000000..5f1f35a --- /dev/null +++ b/SOURCES/kvm-vnc-factor-out-vnc_update_server_surface.patch @@ -0,0 +1,75 @@ +From cf12dd3eb8a9c18fbccbe01cfcf8290d483becee Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:25 +0100 +Subject: [PATCH 11/27] vnc: factor out vnc_update_server_surface + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-12-berrange@redhat.com> +Patchwork-id: 78952 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 11/27] vnc: factor out vnc_update_server_surface +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +From: Gerd Hoffmann + +Signed-off-by: Gerd Hoffmann +Reviewed-by: Peter Lieven +Reviewed-by: Daniel P. Berrange +Message-id: 1446203414-4013-13-git-send-email-kraxel@redhat.com +(cherry picked from commit 453f842bc4cab49f10c267cff9ad3cf657265d49) +Signed-off-by: Miroslav Rezanina +--- + ui/vnc.c | 21 +++++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +diff --git a/ui/vnc.c b/ui/vnc.c +index c3f29df..38e0f1a 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -613,6 +613,17 @@ void *vnc_server_fb_ptr(VncDisplay *vd, int x, int y) + return ptr; + } + ++static void vnc_update_server_surface(VncDisplay *vd) ++{ ++ qemu_pixman_image_unref(vd->server); ++ vd->server = NULL; ++ ++ vd->server = pixman_image_create_bits(VNC_SERVER_FB_FORMAT, ++ vnc_width(vd), ++ vnc_height(vd), ++ NULL, 0); ++} ++ + static void vnc_dpy_switch(DisplayChangeListener *dcl, + DisplaySurface *surface) + { +@@ -621,19 +632,17 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl, + int width, height; + + vnc_abort_display_jobs(vd); ++ vd->ds = surface; + + /* server surface */ +- qemu_pixman_image_unref(vd->server); +- vd->ds = surface; +- width = vnc_width(vd); +- height = vnc_height(vd); +- vd->server = pixman_image_create_bits(VNC_SERVER_FB_FORMAT, +- width, height, NULL, 0); ++ vnc_update_server_surface(vd); + + /* guest surface */ + qemu_pixman_image_unref(vd->guest.fb); + vd->guest.fb = pixman_image_ref(surface->image); + vd->guest.format = surface->format; ++ width = vnc_width(vd); ++ height = vnc_height(vd); + memset(vd->guest.dirty, 0x00, sizeof(vd->guest.dirty)); + vnc_set_area_dirty(vd->guest.dirty, width, height, 0, 0, + width, height); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vnc-jobs-move-buffer-reset-use-new-buffer-move.patch b/SOURCES/kvm-vnc-jobs-move-buffer-reset-use-new-buffer-move.patch new file mode 100644 index 0000000..f67e2f2 --- /dev/null +++ b/SOURCES/kvm-vnc-jobs-move-buffer-reset-use-new-buffer-move.patch @@ -0,0 +1,114 @@ +From 22f72cfdac645ac7a47289dbada48a116d19d42d Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:22 +0100 +Subject: [PATCH 08/27] vnc-jobs: move buffer reset, use new buffer move + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-9-berrange@redhat.com> +Patchwork-id: 78938 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 08/27] vnc-jobs: move buffer reset, use new buffer move +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +From: Gerd Hoffmann + +Signed-off-by: Gerd Hoffmann +Reviewed-by: Peter Lieven +Reviewed-by: Daniel P. Berrange +Message-id: 1446203414-4013-10-git-send-email-kraxel@redhat.com +(cherry picked from commit d90340115a3569caa72063775ff927f4dc353551) + + Conflicts: + ui/vnc-jobs.c - context differences + ui/vnc.{c.h} - make buffer_empty non-static since we don't + have util/buffer.{c,h} yet + +Signed-off-by: Miroslav Rezanina +--- + ui/vnc-jobs.c | 15 ++++++++------- + ui/vnc.c | 2 +- + ui/vnc.h | 1 + + 3 files changed, 10 insertions(+), 8 deletions(-) + +diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c +index a6dfdf6..e553bd9 100644 +--- a/ui/vnc-jobs.c ++++ b/ui/vnc-jobs.c +@@ -29,6 +29,7 @@ + #include "vnc.h" + #include "vnc-jobs.h" + #include "qemu/sockets.h" ++#include "qemu/main-loop.h" + + /* + * Locking: +@@ -164,8 +165,11 @@ void vnc_jobs_consume_buffer(VncState *vs) + + vnc_lock_output(vs); + if (vs->jobs_buffer.offset) { +- vnc_write(vs, vs->jobs_buffer.buffer, vs->jobs_buffer.offset); +- buffer_reset(&vs->jobs_buffer); ++ if (vs->csock != -1 && buffer_empty(&vs->output)) { ++ qemu_set_fd_handler(vs->csock, vnc_client_read, ++ vnc_client_write, vs); ++ } ++ buffer_move(&vs->output, &vs->jobs_buffer); + } + flush = vs->csock != -1 && vs->abort != true; + vnc_unlock_output(vs); +@@ -192,8 +196,6 @@ static void vnc_async_encoding_start(VncState *orig, VncState *local) + local->hextile = orig->hextile; + local->zrle = orig->zrle; + local->csock = -1; /* Don't do any network work on this thread */ +- +- buffer_reset(&local->output); + } + + static void vnc_async_encoding_end(VncState *orig, VncState *local) +@@ -269,14 +271,13 @@ static int vnc_worker_thread_loop(VncJobQueue *queue) + + vnc_lock_output(job->vs); + if (job->vs->csock != -1) { +- buffer_reserve(&job->vs->jobs_buffer, vs.output.offset); +- buffer_append(&job->vs->jobs_buffer, vs.output.buffer, +- vs.output.offset); ++ buffer_move(&job->vs->jobs_buffer, &vs.output); + /* Copy persistent encoding data */ + vnc_async_encoding_end(job->vs, &vs); + + qemu_bh_schedule(job->vs->bh); + } else { ++ buffer_reset(&vs.output); + /* Copy persistent encoding data */ + vnc_async_encoding_end(job->vs, &vs); + } +diff --git a/ui/vnc.c b/ui/vnc.c +index 95457ad..ebb6484 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -480,7 +480,7 @@ void buffer_reserve(Buffer *buffer, size_t len) + } + } + +-static int buffer_empty(Buffer *buffer) ++int buffer_empty(Buffer *buffer) + { + return buffer->offset == 0; + } +diff --git a/ui/vnc.h b/ui/vnc.h +index 703fef9..d8465ba 100644 +--- a/ui/vnc.h ++++ b/ui/vnc.h +@@ -547,6 +547,7 @@ void buffer_reset(Buffer *buffer); + void buffer_free(Buffer *buffer); + void buffer_append(Buffer *buffer, const void *data, size_t len); + void buffer_advance(Buffer *buf, size_t len); ++int buffer_empty(Buffer *buffer); + uint8_t *buffer_end(Buffer *buffer); + void buffer_move_empty(Buffer *to, Buffer *from); + void buffer_move(Buffer *to, Buffer *from); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vnc-kill-jobs-queue-buffer.patch b/SOURCES/kvm-vnc-kill-jobs-queue-buffer.patch new file mode 100644 index 0000000..32b1cd3 --- /dev/null +++ b/SOURCES/kvm-vnc-kill-jobs-queue-buffer.patch @@ -0,0 +1,71 @@ +From 56d3fe342a9c8c8e832e59fc093515e99aa8f677 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:21 +0100 +Subject: [PATCH 07/27] vnc: kill jobs queue buffer + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-8-berrange@redhat.com> +Patchwork-id: 78939 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 07/27] vnc: kill jobs queue buffer +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +From: Gerd Hoffmann + +RHEL-7 note: the vnc_queue_init() hunk is missing from the downstream +patch because the buffer_init() call that the hunk removes only appeared +with upstream commit 543b95801f98 ("vnc: attach names to buffers", +2015-11-05), as part of v2.5.0. + +Signed-off-by: Gerd Hoffmann +Reviewed-by: Peter Lieven +Reviewed-by: Daniel P. Berrange +Message-id: 1446203414-4013-9-git-send-email-kraxel@redhat.com +(cherry picked from commit 8305f917c1bc86b1ead0fa9197b5443a4bd611f3) +Signed-off-by: Miroslav Rezanina +--- + ui/vnc-jobs.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c +index a141f40..a6dfdf6 100644 +--- a/ui/vnc-jobs.c ++++ b/ui/vnc-jobs.c +@@ -53,7 +53,6 @@ struct VncJobQueue { + QemuCond cond; + QemuMutex mutex; + QemuThread thread; +- Buffer buffer; + bool exit; + QTAILQ_HEAD(, VncJob) jobs; + }; +@@ -192,7 +191,6 @@ static void vnc_async_encoding_start(VncState *orig, VncState *local) + local->zlib = orig->zlib; + local->hextile = orig->hextile; + local->zrle = orig->zrle; +- local->output = queue->buffer; + local->csock = -1; /* Don't do any network work on this thread */ + + buffer_reset(&local->output); +@@ -205,8 +203,6 @@ static void vnc_async_encoding_end(VncState *orig, VncState *local) + orig->hextile = local->hextile; + orig->zrle = local->zrle; + orig->lossy_rect = local->lossy_rect; +- +- queue->buffer = local->output; + } + + static int vnc_worker_thread_loop(VncJobQueue *queue) +@@ -309,7 +305,6 @@ static void vnc_queue_clear(VncJobQueue *q) + { + qemu_cond_destroy(&queue->cond); + qemu_mutex_destroy(&queue->mutex); +- buffer_free(&queue->buffer); + g_free(q); + queue = NULL; /* Unset global queue */ + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vnc-only-alloc-server-surface-with-clients-connected.patch b/SOURCES/kvm-vnc-only-alloc-server-surface-with-clients-connected.patch new file mode 100644 index 0000000..84f98eb --- /dev/null +++ b/SOURCES/kvm-vnc-only-alloc-server-surface-with-clients-connected.patch @@ -0,0 +1,86 @@ +From e7fa743d920c9c201bcf1e42e2c0058249a5c1e5 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:27 +0100 +Subject: [PATCH 13/27] vnc: only alloc server surface with clients connected + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-14-berrange@redhat.com> +Patchwork-id: 78956 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 13/27] vnc: only alloc server surface with clients connected +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +From: Gerd Hoffmann + +RHEL-7 note: (a) the "graphic_hw_update(NULL)" call is different in the +upstream context due to commit 1d0d59fe2919 ("vnc: allow binding servers +to qemu consoles", 2015-01-22). That commit talks about "multiseat" and +is part of v2.3.0, so out of scope for this backport. (b) The +QTAILQ_INSERT_HEAD() macro invocation is QTAILQ_INSERT_TAIL() in the +upstream context, due to commit e5f34cdd2da5 ("vnc: track & +limit connections", 2015-01-22), part of v2.3.0. That commit is also +irrelevant for this backport. + +Signed-off-by: Gerd Hoffmann +Reviewed-by: Peter Lieven +Reviewed-by: Daniel P. Berrange +Message-id: 1446203414-4013-15-git-send-email-kraxel@redhat.com +(cherry picked from commit c7628bff4138ce906a3620d12e0820c1cf6c140d) + + Conflicts: + ui/vnc.c - context differences + +Signed-off-by: Miroslav Rezanina +--- + ui/vnc.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/ui/vnc.c b/ui/vnc.c +index df081a5..dc09089 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -620,6 +620,10 @@ static void vnc_update_server_surface(VncDisplay *vd) + qemu_pixman_image_unref(vd->server); + vd->server = NULL; + ++ if (QTAILQ_EMPTY(&vd->clients)) { ++ return; ++ } ++ + vd->server = pixman_image_create_bits(VNC_SERVER_FB_FORMAT, + vnc_width(vd), + vnc_height(vd), +@@ -1019,6 +1023,10 @@ void vnc_disconnect_finish(VncState *vs) + if (vs->initialized) { + QTAILQ_REMOVE(&vs->vd->clients, vs, next); + qemu_remove_mouse_mode_change_notifier(&vs->mouse_mode_notifier); ++ if (QTAILQ_EMPTY(&vs->vd->clients)) { ++ /* last client gone */ ++ vnc_update_server_surface(vs->vd); ++ } + } + + if (vs->vd->lock_key_sync) +@@ -2819,6 +2827,7 @@ void vnc_init_state(VncState *vs) + { + vs->initialized = true; + VncDisplay *vd = vs->vd; ++ bool first_client = QTAILQ_EMPTY(&vd->clients); + + vs->last_x = -1; + vs->last_y = -1; +@@ -2832,6 +2841,9 @@ void vnc_init_state(VncState *vs) + vs->bh = qemu_bh_new(vnc_jobs_bh, vs); + + QTAILQ_INSERT_HEAD(&vd->clients, vs, next); ++ if (first_client) { ++ vnc_update_server_surface(vd); ++ } + + graphic_hw_update(NULL); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vnc-return-directly-if-no-vnc-client-connected.patch b/SOURCES/kvm-vnc-return-directly-if-no-vnc-client-connected.patch new file mode 100644 index 0000000..9fa1a00 --- /dev/null +++ b/SOURCES/kvm-vnc-return-directly-if-no-vnc-client-connected.patch @@ -0,0 +1,61 @@ +From 59bdfd752c491ce0e7253d78e379b0bd8c5cd00e Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:18 +0100 +Subject: [PATCH 04/27] vnc: return directly if no vnc client connected + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-5-berrange@redhat.com> +Patchwork-id: 78950 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 04/27] vnc: return directly if no vnc client connected +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +From: ChenLiang + +graphic_hw_update and vnc_refresh_server_surface aren't +need to do when no vnc client connected. It can reduce +lock contention, because vnc_refresh will hold global big +lock two millisecond every three seconds. + +Signed-off-by: ChenLiang +Signed-off-by: Gonglei +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 9d6b20704734fe1ab789400806ebd54f579d50a2) +Signed-off-by: Miroslav Rezanina +--- + ui/vnc.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/ui/vnc.c b/ui/vnc.c +index 42070b4..9047862 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -2677,6 +2677,11 @@ static void vnc_refresh(DisplayChangeListener *dcl) + VncState *vs, *vn; + int has_dirty, rects = 0; + ++ if (QTAILQ_EMPTY(&vd->clients)) { ++ update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_MAX); ++ return; ++ } ++ + graphic_hw_update(NULL); + + if (vnc_trylock_display(vd)) { +@@ -2692,11 +2697,6 @@ static void vnc_refresh(DisplayChangeListener *dcl) + /* vs might be free()ed here */ + } + +- if (QTAILQ_EMPTY(&vd->clients)) { +- update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_MAX); +- return; +- } +- + if (has_dirty && rects) { + vd->dcl.update_interval /= 2; + if (vd->dcl.update_interval < VNC_REFRESH_INTERVAL_BASE) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vnc-update-fix.patch b/SOURCES/kvm-vnc-update-fix.patch new file mode 100644 index 0000000..0f6eff6 --- /dev/null +++ b/SOURCES/kvm-vnc-update-fix.patch @@ -0,0 +1,75 @@ +From 67517d9d08977cf80a2528502b9de5351c17c990 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:17 +0100 +Subject: [PATCH 03/27] vnc update fix + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-4-berrange@redhat.com> +Patchwork-id: 78942 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 03/27] vnc update fix +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +From: Gerd Hoffmann + +We need to remember has_updates for each vnc client. Otherwise it might +happen that vnc_update_client(has_dirty=1) takes the first exit due to +output buffers not being flushed yet and subsequent calls with +has_dirty=0 take the second exit, wrongly assuming there is nothing to +do because the work defered in the first call is ignored. + +Signed-off-by: Gerd Hoffmann +Reviewed-by: Peter Lieven +(cherry picked from commit 6365828003c8e88bff67d351af4b66c406568a26) +Signed-off-by: Miroslav Rezanina +--- + ui/vnc.c | 4 +++- + ui/vnc.h | 1 + + 2 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/ui/vnc.c b/ui/vnc.c +index 5226295..42070b4 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -794,6 +794,7 @@ static int find_and_clear_dirty_height(struct VncState *vs, + + static int vnc_update_client(VncState *vs, int has_dirty) + { ++ vs->has_dirty += has_dirty; + if (vs->need_update && vs->csock != -1) { + VncDisplay *vd = vs->vd; + VncJob *job; +@@ -805,7 +806,7 @@ static int vnc_update_client(VncState *vs, int has_dirty) + /* kernel send buffers are full -> drop frames to throttle */ + return 0; + +- if (!has_dirty && !vs->audio_cap && !vs->force_update) ++ if (!vs->has_dirty && !vs->audio_cap && !vs->force_update) + return 0; + + /* +@@ -845,6 +846,7 @@ static int vnc_update_client(VncState *vs, int has_dirty) + + vnc_job_push(job); + vs->force_update = 0; ++ vs->has_dirty = 0; + return n; + } + +diff --git a/ui/vnc.h b/ui/vnc.h +index 8d534b6..d1badbb 100644 +--- a/ui/vnc.h ++++ b/ui/vnc.h +@@ -263,6 +263,7 @@ struct VncState + VncDisplay *vd; + int need_update; + int force_update; ++ int has_dirty; + uint32_t features; + int absolute; + int last_x; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vnc-use-vnc_-width-height-in-vnc_set_area_dirty.patch b/SOURCES/kvm-vnc-use-vnc_-width-height-in-vnc_set_area_dirty.patch new file mode 100644 index 0000000..6b57457 --- /dev/null +++ b/SOURCES/kvm-vnc-use-vnc_-width-height-in-vnc_set_area_dirty.patch @@ -0,0 +1,99 @@ +From 38debd5362a680a90db572263f7b49ecbde24ac1 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:26 +0100 +Subject: [PATCH 12/27] vnc: use vnc_{width, height} in vnc_set_area_dirty + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-13-berrange@redhat.com> +Patchwork-id: 78945 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 12/27] vnc: use vnc_{width, height} in vnc_set_area_dirty +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +From: Gerd Hoffmann + +vnc: use vnc_{width,height} in vnc_set_area_dirty + +Signed-off-by: Gerd Hoffmann +Reviewed-by: Peter Lieven +Reviewed-by: Daniel P. Berrange +Message-id: 1446203414-4013-14-git-send-email-kraxel@redhat.com +(cherry picked from commit f7b3d68c95bc4f8915a3d084360aa07c7f4e4717) +Signed-off-by: Miroslav Rezanina +--- + ui/vnc.c | 21 ++++++++++----------- + 1 file changed, 10 insertions(+), 11 deletions(-) + +diff --git a/ui/vnc.c b/ui/vnc.c +index 38e0f1a..df081a5 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -439,8 +439,12 @@ static int vnc_height(VncDisplay *vd) + + static void vnc_set_area_dirty(DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT], + VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT), +- int width, int height, +- int x, int y, int w, int h) { ++ VncDisplay *vd, ++ int x, int y, int w, int h) ++{ ++ int width = vnc_width(vd); ++ int height = vnc_height(vd); ++ + /* this is needed this to ensure we updated all affected + * blocks if x % VNC_DIRTY_PIXELS_PER_BIT != 0 */ + w += (x % VNC_DIRTY_PIXELS_PER_BIT); +@@ -462,10 +466,8 @@ static void vnc_dpy_update(DisplayChangeListener *dcl, + { + VncDisplay *vd = container_of(dcl, VncDisplay, dcl); + struct VncSurface *s = &vd->guest; +- int width = pixman_image_get_width(vd->server); +- int height = pixman_image_get_height(vd->server); + +- vnc_set_area_dirty(s->dirty, width, height, x, y, w, h); ++ vnc_set_area_dirty(s->dirty, vd, x, y, w, h); + } + + void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h, +@@ -644,7 +646,7 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl, + width = vnc_width(vd); + height = vnc_height(vd); + memset(vd->guest.dirty, 0x00, sizeof(vd->guest.dirty)); +- vnc_set_area_dirty(vd->guest.dirty, width, height, 0, 0, ++ vnc_set_area_dirty(vd->guest.dirty, vd, 0, 0, + width, height); + + QTAILQ_FOREACH(vs, &vd->clients, next) { +@@ -654,7 +656,7 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl, + vnc_cursor_define(vs); + } + memset(vs->dirty, 0x00, sizeof(vs->dirty)); +- vnc_set_area_dirty(vs->dirty, width, height, 0, 0, ++ vnc_set_area_dirty(vs->dirty, vd, 0, 0, + width, height); + } + } +@@ -1816,9 +1818,6 @@ static void ext_key_event(VncState *vs, int down, + static void framebuffer_update_request(VncState *vs, int incremental, + int x, int y, int w, int h) + { +- int width = pixman_image_get_width(vs->vd->server); +- int height = pixman_image_get_height(vs->vd->server); +- + vs->need_update = 1; + + if (incremental) { +@@ -1826,7 +1825,7 @@ static void framebuffer_update_request(VncState *vs, int incremental, + } + + vs->force_update = 1; +- vnc_set_area_dirty(vs->dirty, width, height, x, y, w, h); ++ vnc_set_area_dirty(vs->dirty, vs->vd, x, y, w, h); + } + + static void send_ext_key_event_ack(VncState *vs) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vnc-zap-dead-code.patch b/SOURCES/kvm-vnc-zap-dead-code.patch new file mode 100644 index 0000000..07f3236 --- /dev/null +++ b/SOURCES/kvm-vnc-zap-dead-code.patch @@ -0,0 +1,44 @@ +From 94da5567a7962a25fdc268ed284c15d20637c348 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Thu, 8 Feb 2018 17:50:23 +0100 +Subject: [PATCH 09/27] vnc: zap dead code + +RH-Author: Daniel P. Berrange +Message-id: <20180208175041.5634-10-berrange@redhat.com> +Patchwork-id: 78940 +O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 09/27] vnc: zap dead code +Bugzilla: 1527405 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Miroslav Rezanina + +From: Gerd Hoffmann + +Signed-off-by: Gerd Hoffmann +Reviewed-by: Peter Lieven +Reviewed-by: Daniel P. Berrange +Message-id: 1446203414-4013-11-git-send-email-kraxel@redhat.com +(cherry picked from commit e081aae5ae01f5ff695ba9fee4e622053d8e4bfe) +Signed-off-by: Miroslav Rezanina +--- + ui/vnc.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/ui/vnc.c b/ui/vnc.c +index ebb6484..9923d24 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -621,10 +621,6 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl, + width, height, NULL, 0); + + /* guest surface */ +-#if 0 /* FIXME */ +- if (ds_get_bytes_per_pixel(ds) != vd->guest.ds->pf.bytes_per_pixel) +- console_color_init(ds); +-#endif + qemu_pixman_image_unref(vd->guest.fb); + vd->guest.fb = pixman_image_ref(surface->image); + vd->guest.format = surface->format; +-- +1.8.3.1 + diff --git a/SPECS/qemu-kvm.spec b/SPECS/qemu-kvm.spec index b81495f..11271e0 100644 --- a/SPECS/qemu-kvm.spec +++ b/SPECS/qemu-kvm.spec @@ -76,13 +76,13 @@ Obsoletes: %1 < %{obsoletes_version} \ Summary: QEMU is a machine emulator and virtualizer Name: %{pkgname}%{?pkgsuffix} Version: 1.5.3 -Release: 141%{?dist}.5 +Release: 156%{?dist} # Epoch because we pushed a qemu-1.0 package. AIUI this can't ever be dropped Epoch: 10 License: GPLv2+ and LGPLv2+ and BSD Group: Development/Tools URL: http://www.qemu.org/ -ExclusiveArch: x86_64 %{power64} aarch64 s390x +ExclusiveArch: x86_64 Requires: seabios-bin >= 1.7.2.2-5 Requires: sgabios-bin Requires: seavgabios-bin @@ -3594,38 +3594,277 @@ Patch1768: kvm-serial-reinstate-watch-after-migration.patch Patch1769: kvm-nbd-Fully-initialize-client-in-case-of-failed-negoti.patch # For bz#1451614 - CVE-2017-9524 qemu-kvm: segment fault when private user nmap qemu-nbd server [rhel-7.4] Patch1770: kvm-nbd-Fix-regression-on-resiliency-to-port-scan.patch -# For bz#1468107 - CVE-2017-10664 qemu-kvm: Qemu: qemu-nbd: server breaks with SIGPIPE upon client abort [rhel-7.4.z] -Patch1771: kvm-qemu-nbd-Ignore-SIGPIPE.patch -# For bz#1482468 - KVM: windows guest migration from EL6 to EL7 fails. [rhel-7.4.z] +# For bz#1435352 - qemu started with "-vnc none,..." doesn't support any VNC authentication +Patch1771: kvm-vnc-allow-to-connect-with-add_client-when-vnc-none.patch +# For bz#1480428 - KVM: windows guest migration from EL6 to EL7 fails. Patch1772: kvm-virtio-net-dynamic-network-offloads-configuration.patch -# For bz#1482468 - KVM: windows guest migration from EL6 to EL7 fails. [rhel-7.4.z] +# For bz#1480428 - KVM: windows guest migration from EL6 to EL7 fails. Patch1773: kvm-Workaround-rhel6-ctrl_guest_offloads-machine-type-mi.patch -# For bz#1501294 - CVE-2017-15289 qemu-kvm: Qemu: cirrus: OOB access issue in mode4and5 write functions [rhel-7.4.z] -Patch1774: kvm-bswap.h-Remove-cpu_to_32wu.patch -# For bz#1501294 - CVE-2017-15289 qemu-kvm: Qemu: cirrus: OOB access issue in mode4and5 write functions [rhel-7.4.z] -Patch1775: kvm-hw-use-ld_p-st_p-instead-of-ld_raw-st_raw.patch -# For bz#1501294 - CVE-2017-15289 qemu-kvm: Qemu: cirrus: OOB access issue in mode4and5 write functions [rhel-7.4.z] -Patch1776: kvm-vga-Start-cutting-out-non-32bpp-conversion-support.patch -# For bz#1501294 - CVE-2017-15289 qemu-kvm: Qemu: cirrus: OOB access issue in mode4and5 write functions [rhel-7.4.z] -Patch1777: kvm-vga-Remove-remainder-of-old-conversion-cruft.patch -# For bz#1501294 - CVE-2017-15289 qemu-kvm: Qemu: cirrus: OOB access issue in mode4and5 write functions [rhel-7.4.z] -Patch1778: kvm-vga-Separate-LE-and-BE-conversion-functions.patch -# For bz#1501294 - CVE-2017-15289 qemu-kvm: Qemu: cirrus: OOB access issue in mode4and5 write functions [rhel-7.4.z] -Patch1779: kvm-vga-Rename-vga_template.h-to-vga-helpers.h.patch -# For bz#1501294 - CVE-2017-15289 qemu-kvm: Qemu: cirrus: OOB access issue in mode4and5 write functions [rhel-7.4.z] -Patch1780: kvm-vga-stop-passing-pointers-to-vga_draw_line-functions.patch -# For bz#1501294 - CVE-2017-15289 qemu-kvm: Qemu: cirrus: OOB access issue in mode4and5 write functions [rhel-7.4.z] -Patch1781: kvm-vga-drop-line_offset-variable.patch -# For bz#1501294 - CVE-2017-15289 qemu-kvm: Qemu: cirrus: OOB access issue in mode4and5 write functions [rhel-7.4.z] -Patch1782: kvm-vga-Add-mechanism-to-force-the-use-of-a-shadow-surfa.patch -# For bz#1501294 - CVE-2017-15289 qemu-kvm: Qemu: cirrus: OOB access issue in mode4and5 write functions [rhel-7.4.z] -Patch1783: kvm-vga-handle-cirrus-vbe-mode-wraparounds.patch -# For bz#1501294 - CVE-2017-15289 qemu-kvm: Qemu: cirrus: OOB access issue in mode4and5 write functions [rhel-7.4.z] -Patch1784: kvm-cirrus-fix-oob-access-in-mode4and5-write-functions.patch -# For bz#1501120 - CVE-2017-14167 qemu-kvm: Qemu: i386: multiboot OOB access while loading kernel image [rhel-7.4.z] -Patch1785: kvm-multiboot-validate-multiboot-header-address-values.patch -# For bz#1515110 - Regression in QEMU handling for sub-page MMIO BARs for vfio-pci devices [rhel-7.4.z] -Patch1786: kvm-vfio-pci-Only-mmap-TARGET_PAGE_SIZE-regions.patch +# For bz#1387648 - [Intel 7.5 FEAT] Memory Protection Keys for qemu-kvm +Patch1774: kvm-target-i386-Add-PKU-and-and-OSPKE-support.patch +# For bz#1492559 - virtio-blk mutiwrite merge causes too big IO +Patch1775: kvm-block-Limit-multiwrite-merge-downstream-only.patch +# For bz#1466463 - CVE-2017-10664 qemu-kvm: Qemu: qemu-nbd: server breaks with SIGPIPE upon client abort [rhel-7.5] +Patch1776: kvm-qemu-nbd-Ignore-SIGPIPE.patch +# For bz#1476641 - ui/vnc_keysym.h is very out of date and does not correctly support many Eastern European keyboards +Patch1777: kvm-qemu-char-add-Czech-characters-to-VNC-keysyms.patch +# For bz#1476641 - ui/vnc_keysym.h is very out of date and does not correctly support many Eastern European keyboards +Patch1778: kvm-qemu-char-add-missing-characters-used-in-keymaps.patch +# For bz#1476641 - ui/vnc_keysym.h is very out of date and does not correctly support many Eastern European keyboards +Patch1779: kvm-qemu-char-add-cyrillic-characters-numerosign-to-VNC-.patch +# For bz#1461672 - qemu-img core dumped when create external snapshot through ssh protocol without specifying image size +Patch1780: kvm-block-ssh-Use-QemuOpts-for-runtime-options.patch +# For bz#1494181 - Backport vGPU support to qemu-kvm +Patch1781: kvm-vfio-pass-device-to-vfio_mmap_bar-and-use-it-to-set-.patch +# For bz#1494181 - Backport vGPU support to qemu-kvm +Patch1782: kvm-hw-vfio-pci-Rename-VFIODevice-into-VFIOPCIDevice.patch +# For bz#1494181 - Backport vGPU support to qemu-kvm +Patch1783: kvm-hw-vfio-pci-generalize-mask-unmask-to-any-IRQ-index.patch +# For bz#1494181 - Backport vGPU support to qemu-kvm +Patch1784: kvm-hw-vfio-pci-introduce-minimalist-VFIODevice-with-fd.patch +# For bz#1494181 - Backport vGPU support to qemu-kvm +Patch1785: kvm-hw-vfio-pci-add-type-name-and-group-fields-in-VFIODe.patch +# For bz#1494181 - Backport vGPU support to qemu-kvm +Patch1786: kvm-hw-vfio-pci-handle-reset-at-VFIODevice.patch +# For bz#1494181 - Backport vGPU support to qemu-kvm +Patch1787: kvm-hw-vfio-pci-Introduce-VFIORegion.patch +# For bz#1494181 - Backport vGPU support to qemu-kvm +Patch1788: kvm-hw-vfio-pci-use-name-field-in-format-strings.patch +# For bz#1494181 - Backport vGPU support to qemu-kvm +Patch1789: kvm-vfio-Add-sysfsdev-property-for-pci-platform.patch +# For bz#1494181 - Backport vGPU support to qemu-kvm +Patch1790: kvm-vfio-remove-bootindex-property-from-qdev-to-qom.patch +# For bz#1494181 - Backport vGPU support to qemu-kvm +Patch1791: kvm-vfio-pci-Handle-host-oversight.patch +# For bz#1494181 - Backport vGPU support to qemu-kvm +Patch1792: kvm-vfio-pci-Fix-incorrect-error-message.patch +# For bz#1494181 - Backport vGPU support to qemu-kvm +Patch1793: kvm-vfio-Wrap-VFIO_DEVICE_GET_REGION_INFO.patch +# For bz#1494181 - Backport vGPU support to qemu-kvm +Patch1794: kvm-vfio-Generalize-region-support.patch +# For bz#1494181 - Backport vGPU support to qemu-kvm +Patch1795: kvm-vfio-Enable-sparse-mmap-capability.patch +# For bz#1494181 - Backport vGPU support to qemu-kvm +Patch1796: kvm-vfio-Handle-zero-length-sparse-mmap-ranges.patch +# For bz#1486642 - CVE-2017-13672 qemu-kvm: Qemu: vga: OOB read access during display update [rhel-7.5] +Patch1797: kvm-bswap.h-Remove-cpu_to_32wu.patch +# For bz#1486642 - CVE-2017-13672 qemu-kvm: Qemu: vga: OOB read access during display update [rhel-7.5] +Patch1798: kvm-hw-use-ld_p-st_p-instead-of-ld_raw-st_raw.patch +# For bz#1486642 - CVE-2017-13672 qemu-kvm: Qemu: vga: OOB read access during display update [rhel-7.5] +Patch1799: kvm-vga-Start-cutting-out-non-32bpp-conversion-support.patch +# For bz#1486642 - CVE-2017-13672 qemu-kvm: Qemu: vga: OOB read access during display update [rhel-7.5] +Patch1800: kvm-vga-Remove-remainder-of-old-conversion-cruft.patch +# For bz#1486642 - CVE-2017-13672 qemu-kvm: Qemu: vga: OOB read access during display update [rhel-7.5] +Patch1801: kvm-vga-Separate-LE-and-BE-conversion-functions.patch +# For bz#1486642 - CVE-2017-13672 qemu-kvm: Qemu: vga: OOB read access during display update [rhel-7.5] +Patch1802: kvm-vga-Rename-vga_template.h-to-vga-helpers.h.patch +# For bz#1486642 - CVE-2017-13672 qemu-kvm: Qemu: vga: OOB read access during display update [rhel-7.5] +Patch1803: kvm-vga-stop-passing-pointers-to-vga_draw_line-functions.patch +# For bz#1450396 - Add support for AMD EPYC processors +Patch1804: kvm-target-i386-Add-Intel-SHA_NI-instruction-support.patch +# For bz#1450396 - Add support for AMD EPYC processors +Patch1805: kvm-target-i386-cpu-Add-new-EPYC-CPU-model.patch +# For bz#1501510 - Add Skylake-Server CPU model (qemu-kvm) +Patch1806: kvm-target-i386-Enable-clflushopt-clwb-pcommit-instructi.patch +# For bz#1501510 - Add Skylake-Server CPU model (qemu-kvm) +Patch1807: kvm-i386-add-Skylake-Server-cpu-model.patch +# For bz#1501295 - CVE-2017-15289 qemu-kvm: Qemu: cirrus: OOB access issue in mode4and5 write functions [rhel-7.5] +Patch1808: kvm-vga-drop-line_offset-variable.patch +# For bz#1501295 - CVE-2017-15289 qemu-kvm: Qemu: cirrus: OOB access issue in mode4and5 write functions [rhel-7.5] +Patch1809: kvm-vga-Add-mechanism-to-force-the-use-of-a-shadow-surfa.patch +# For bz#1501295 - CVE-2017-15289 qemu-kvm: Qemu: cirrus: OOB access issue in mode4and5 write functions [rhel-7.5] +Patch1810: kvm-vga-handle-cirrus-vbe-mode-wraparounds.patch +# For bz#1501295 - CVE-2017-15289 qemu-kvm: Qemu: cirrus: OOB access issue in mode4and5 write functions [rhel-7.5] +Patch1811: kvm-cirrus-fix-oob-access-in-mode4and5-write-functions.patch +# For bz#1470244 - reboot leads to shutoff of qemu-kvm-vm if i6300esb-watchdog set to poweroff +Patch1812: kvm-i6300esb-Fix-signed-integer-overflow.patch +# For bz#1470244 - reboot leads to shutoff of qemu-kvm-vm if i6300esb-watchdog set to poweroff +Patch1813: kvm-i6300esb-fix-timer-overflow.patch +# For bz#1470244 - reboot leads to shutoff of qemu-kvm-vm if i6300esb-watchdog set to poweroff +Patch1814: kvm-i6300esb-remove-muldiv64.patch +# For bz#1501121 - CVE-2017-14167 qemu-kvm: Qemu: i386: multiboot OOB access while loading kernel image [rhel-7.5] +Patch1815: kvm-multiboot-validate-multiboot-header-address-values.patch +# For bz#1417864 - Qemu-kvm starts with unspecified port +Patch1816: kvm-qemu-option-reject-empty-number-value.patch +# For bz#1491434 - KVM leaks file descriptors when attaching and detaching virtio-scsi block devices +Patch1817: kvm-block-linux-aio-fix-memory-and-fd-leak.patch +# For bz#1491434 - KVM leaks file descriptors when attaching and detaching virtio-scsi block devices +Patch1818: kvm-linux-aio-Fix-laio-resource-leak.patch +# For bz#1508745 - CVE-2017-13711 qemu-kvm: Qemu: Slirp: use-after-free when sending response [rhel-7.5] +Patch1819: kvm-slirp-cleanup-leftovers-from-misc.h.patch +# For bz#1508745 - CVE-2017-13711 qemu-kvm: Qemu: Slirp: use-after-free when sending response [rhel-7.5] +Patch1820: kvm-Avoid-embedding-struct-mbuf-in-other-structures.patch +# For bz#1508745 - CVE-2017-13711 qemu-kvm: Qemu: Slirp: use-after-free when sending response [rhel-7.5] +Patch1821: kvm-slirp-Fix-access-to-freed-memory.patch +# For bz#1508745 - CVE-2017-13711 qemu-kvm: Qemu: Slirp: use-after-free when sending response [rhel-7.5] +Patch1822: kvm-slirp-fix-clearing-ifq_so-from-pending-packets.patch +# For bz#1459714 - Throw error if qemu-img rebasing backing file is too long or provide way to fix a "too long" backing file. +Patch1823: kvm-qcow2-Prevent-backing-file-names-longer-than-1023.patch +# For bz#1459725 - Prevent qemu-img resize from causing "Active L1 table too large" +Patch1824: kvm-qemu-img-Use-strerror-for-generic-resize-error.patch +# For bz#1459725 - Prevent qemu-img resize from causing "Active L1 table too large" +Patch1825: kvm-qcow2-Avoid-making-the-L1-table-too-big.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1826: kvm-fw_cfg-remove-support-for-guest-side-data-writes.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1827: kvm-fw_cfg-prevent-selector-key-conflict.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1828: kvm-fw_cfg-prohibit-insertion-of-duplicate-fw_cfg-file-n.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1829: kvm-fw_cfg-factor-out-initialization-of-FW_CFG_ID-rev.-n.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1830: kvm-Implement-fw_cfg-DMA-interface.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1831: kvm-fw_cfg-avoid-calculating-invalid-current-entry-point.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1832: kvm-fw-cfg-support-writeable-blobs.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1833: kvm-Enable-fw_cfg-DMA-interface-for-x86.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1834: kvm-fw_cfg-unbreak-migration-compatibility.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1835: kvm-i386-expose-fw_cfg-QEMU0002-in-SSDT.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1836: kvm-fw_cfg-add-write-callback.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1837: kvm-hw-misc-add-vmcoreinfo-device.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1838: kvm-vmcoreinfo-put-it-in-the-misc-device-category.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1839: kvm-fw_cfg-enable-DMA-if-device-vmcoreinfo.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1840: kvm-build-sys-restrict-vmcoreinfo-to-fw_cfg-dma-capable-.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1841: kvm-dump-Make-DumpState-and-endian-conversion-routines-a.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1842: kvm-dump.c-Fix-memory-leak-issue-in-cleanup-processing-f.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1843: kvm-dump-Propagate-errors-into-qmp_dump_guest_memory.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1844: kvm-dump-Turn-some-functions-to-void-to-make-code-cleane.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1845: kvm-dump-Fix-dump-guest-memory-termination-and-use-after.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1846: kvm-dump-allow-target-to-set-the-page-size.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1847: kvm-dump-allow-target-to-set-the-physical-base.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1848: kvm-dump-guest-memory-cleanup-removing-dump_-error-clean.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1849: kvm-dump-guest-memory-using-static-DumpState-add-DumpSta.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1850: kvm-dump-guest-memory-add-dump_in_progress-helper-functi.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1851: kvm-dump-guest-memory-introduce-dump_process-helper-func.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1852: kvm-dump-guest-memory-disable-dump-when-in-INMIGRATE-sta.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1853: kvm-DumpState-adding-total_size-and-written_size-fields.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1854: kvm-dump-do-not-dump-non-existent-guest-memory.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1855: kvm-dump-add-guest-ELF-note.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1856: kvm-dump-update-phys_base-header-field-based-on-VMCOREIN.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1857: kvm-kdump-set-vmcoreinfo-location.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1858: kvm-scripts-dump-guest-memory.py-Move-constants-to-the-t.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1859: kvm-scripts-dump-guest-memory.py-Make-methods-functions.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1860: kvm-scripts-dump-guest-memory.py-Improve-python-3-compat.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1861: kvm-scripts-dump-guest-memory.py-Cleanup-functions.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1862: kvm-scripts-dump-guest-memory.py-Introduce-multi-arch-su.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1863: kvm-Fix-typo-in-variable-name-found-and-fixed-by-codespe.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1864: kvm-scripts-dump-guest-memory.py-add-vmcoreinfo.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1865: kvm-dump-guest-memory.py-fix-No-symbol-vmcoreinfo_find.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1866: kvm-dump-guest-memory.py-fix-You-can-t-do-that-without-a.patch +# For bz#CVE-2017-5715 +Patch1867: kvm-target-i386-cpu-add-new-CPUID-bits-for-indirect-bran.patch +# For bz#CVE-2017-5715 +Patch1868: kvm-target-i386-add-support-for-SPEC_CTRL-MSR.patch +# For bz#CVE-2017-5715 +Patch1869: kvm-target-i386-cpu-add-new-CPU-models-for-indirect-bran.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1870: kvm-i386-update-ssdt-misc.hex.generated.patch +# For bz#1435432 - Emulated ISA serial port hangs randomly when sending lots of data from guest -> host +# For bz#1473536 - Hangs in serial console under qemu +Patch1871: kvm-main-loop-Acquire-main_context-lock-around-os_host_m.patch +# For bz#1460872 - Aborted(core dumped) when booting guest with "-netdev tap....vhost=on,queues=32" +Patch1872: kvm-virtio-net-validate-backend-queue-numbers-against-bu.patch +# For bz#1411490 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm) +Patch1873: kvm-dump-guest-memory.py-fix-python-2-support.patch +# For bz#1536883 - [abrt] [faf] qemu-kvm: unknown function(): /usr/libexec/qemu-kvm killed by 6 +Patch1874: kvm-qxl-add-migration-blocker-to-avoid-pre-save-assert.patch +# For bz#1538866 - qemu will coredump after executing info qtree +Patch1875: kvm-qdev-Fix-assert-in-PCI-address-property-when-used-by.patch +# For bz#1534691 - CVE-2018-5683 qemu-kvm: Qemu: Out-of-bounds read in vga_draw_text routine [rhel-7.5] +Patch1876: kvm-vga-check-the-validation-of-memory-addr-when-draw-te.patch +# For bz#1536883 - [abrt] [faf] qemu-kvm: unknown function(): /usr/libexec/qemu-kvm killed by 6 +Patch1877: kvm-savevm-Improve-error-message-for-blocked-migration.patch +# For bz#1536883 - [abrt] [faf] qemu-kvm: unknown function(): /usr/libexec/qemu-kvm killed by 6 +Patch1878: kvm-savevm-fail-if-migration-blockers-are-present.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1879: kvm-vnc-Fix-qemu-crashed-when-vnc-client-disconnect-sudd.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1880: kvm-fix-full-frame-updates-for-VNC-clients.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1881: kvm-vnc-update-fix.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1882: kvm-vnc-return-directly-if-no-vnc-client-connected.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1883: kvm-buffer-add-buffer_move_empty.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1884: kvm-buffer-add-buffer_move.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1885: kvm-vnc-kill-jobs-queue-buffer.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1886: kvm-vnc-jobs-move-buffer-reset-use-new-buffer-move.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1887: kvm-vnc-zap-dead-code.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1888: kvm-vnc-add-vnc_width-vnc_height-helpers.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1889: kvm-vnc-factor-out-vnc_update_server_surface.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1890: kvm-vnc-use-vnc_-width-height-in-vnc_set_area_dirty.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1891: kvm-vnc-only-alloc-server-surface-with-clients-connected.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1892: kvm-ui-fix-refresh-of-VNC-server-surface.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1893: kvm-ui-move-disconnecting-check-to-start-of-vnc_update_c.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1894: kvm-ui-remove-redundant-indentation-in-vnc_client_update.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1895: kvm-ui-avoid-pointless-VNC-updates-if-framebuffer-isn-t-.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1896: kvm-ui-track-how-much-decoded-data-we-consumed-when-doin.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1897: kvm-ui-introduce-enum-to-track-VNC-client-framebuffer-up.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1898: kvm-ui-correctly-reset-framebuffer-update-state-after-pr.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1899: kvm-ui-refactor-code-for-determining-if-an-update-should.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1900: kvm-ui-fix-VNC-client-throttling-when-audio-capture-is-a.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1901: kvm-ui-fix-VNC-client-throttling-when-forced-update-is-r.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1902: kvm-ui-place-a-hard-cap-on-VNC-server-output-buffer-size.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1903: kvm-ui-avoid-sign-extension-using-client-width-height.patch +# For bz#1527405 - CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] +Patch1904: kvm-ui-correctly-advance-output-buffer-when-writing-SASL.patch +# For bz#1518711 - CVE-2017-15268 qemu-kvm: Qemu: I/O: potential memory exhaustion via websock connection to VNC [rhel-7.5] +Patch1905: kvm-io-skip-updates-to-client-if-websocket-output-buffer.patch BuildRequires: zlib-devel @@ -5590,6 +5829,125 @@ tar -xf %{SOURCE21} %patch1784 -p1 %patch1785 -p1 %patch1786 -p1 +%patch1787 -p1 +%patch1788 -p1 +%patch1789 -p1 +%patch1790 -p1 +%patch1791 -p1 +%patch1792 -p1 +%patch1793 -p1 +%patch1794 -p1 +%patch1795 -p1 +%patch1796 -p1 +%patch1797 -p1 +%patch1798 -p1 +%patch1799 -p1 +%patch1800 -p1 +%patch1801 -p1 +%patch1802 -p1 +%patch1803 -p1 +%patch1804 -p1 +%patch1805 -p1 +%patch1806 -p1 +%patch1807 -p1 +%patch1808 -p1 +%patch1809 -p1 +%patch1810 -p1 +%patch1811 -p1 +%patch1812 -p1 +%patch1813 -p1 +%patch1814 -p1 +%patch1815 -p1 +%patch1816 -p1 +%patch1817 -p1 +%patch1818 -p1 +%patch1819 -p1 +%patch1820 -p1 +%patch1821 -p1 +%patch1822 -p1 +%patch1823 -p1 +%patch1824 -p1 +%patch1825 -p1 +%patch1826 -p1 +%patch1827 -p1 +%patch1828 -p1 +%patch1829 -p1 +%patch1830 -p1 +%patch1831 -p1 +%patch1832 -p1 +%patch1833 -p1 +%patch1834 -p1 +%patch1835 -p1 +%patch1836 -p1 +%patch1837 -p1 +%patch1838 -p1 +%patch1839 -p1 +%patch1840 -p1 +%patch1841 -p1 +%patch1842 -p1 +%patch1843 -p1 +%patch1844 -p1 +%patch1845 -p1 +%patch1846 -p1 +%patch1847 -p1 +%patch1848 -p1 +%patch1849 -p1 +%patch1850 -p1 +%patch1851 -p1 +%patch1852 -p1 +%patch1853 -p1 +%patch1854 -p1 +%patch1855 -p1 +%patch1856 -p1 +%patch1857 -p1 +%patch1858 -p1 +%patch1859 -p1 +%patch1860 -p1 +%patch1861 -p1 +%patch1862 -p1 +%patch1863 -p1 +%patch1864 -p1 +%patch1865 -p1 +%patch1866 -p1 +%patch1867 -p1 +%patch1868 -p1 +%patch1869 -p1 +%patch1870 -p1 +%patch1871 -p1 +%patch1872 -p1 +%patch1873 -p1 +%patch1874 -p1 +%patch1875 -p1 +%patch1876 -p1 +%patch1877 -p1 +%patch1878 -p1 +%patch1879 -p1 +%patch1880 -p1 +%patch1881 -p1 +%patch1882 -p1 +%patch1883 -p1 +%patch1884 -p1 +%patch1885 -p1 +%patch1886 -p1 +%patch1887 -p1 +%patch1888 -p1 +%patch1889 -p1 +%patch1890 -p1 +%patch1891 -p1 +%patch1892 -p1 +%patch1893 -p1 +%patch1894 -p1 +%patch1895 -p1 +%patch1896 -p1 +%patch1897 -p1 +%patch1898 -p1 +%patch1899 -p1 +%patch1900 -p1 +%patch1901 -p1 +%patch1902 -p1 +%patch1903 -p1 +%patch1904 -p1 +%patch1905 -p1 %build buildarch="%{kvm_target}-softmmu" @@ -6035,41 +6393,235 @@ sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : %{_mandir}/man8/qemu-nbd.8* %changelog -* Wed Nov 29 2017 Miroslav Rezanina - 1.5.3-141.el7_4.5 -- kvm-vfio-pci-Only-mmap-TARGET_PAGE_SIZE-regions.patch [bz#1515110] -- Resolves: bz#1515110 - (Regression in QEMU handling for sub-page MMIO BARs for vfio-pci devices [rhel-7.4.z]) - -* Fri Nov 10 2017 Miroslav Rezanina - 1.5.3-141.el7_4.4 -- kvm-multiboot-validate-multiboot-header-address-values.patch [bz#1501120] -- Resolves: bz#1501120 - (CVE-2017-14167 qemu-kvm: Qemu: i386: multiboot OOB access while loading kernel image [rhel-7.4.z]) - -* Tue Nov 07 2017 Miroslav Rezanina - 1.5.3-141.el7_4.3 -- kvm-bswap.h-Remove-cpu_to_32wu.patch [bz#1501294] -- kvm-hw-use-ld_p-st_p-instead-of-ld_raw-st_raw.patch [bz#1501294] -- kvm-vga-Start-cutting-out-non-32bpp-conversion-support.patch [bz#1501294] -- kvm-vga-Remove-remainder-of-old-conversion-cruft.patch [bz#1501294] -- kvm-vga-Separate-LE-and-BE-conversion-functions.patch [bz#1501294] -- kvm-vga-Rename-vga_template.h-to-vga-helpers.h.patch [bz#1501294] -- kvm-vga-stop-passing-pointers-to-vga_draw_line-functions.patch [bz#1501294] -- kvm-vga-drop-line_offset-variable.patch [bz#1501294] -- kvm-vga-Add-mechanism-to-force-the-use-of-a-shadow-surfa.patch [bz#1501294] -- kvm-vga-handle-cirrus-vbe-mode-wraparounds.patch [bz#1501294] -- kvm-cirrus-fix-oob-access-in-mode4and5-write-functions.patch [bz#1501294] -- Resolves: bz#1501294 - (CVE-2017-15289 qemu-kvm: Qemu: cirrus: OOB access issue in mode4and5 write functions [rhel-7.4.z]) - -* Mon Aug 21 2017 Miroslav Rezanina - 1.5.3-141.el7_4.2 -- kvm-virtio-net-dynamic-network-offloads-configuration.patch [bz#1482468] -- kvm-Workaround-rhel6-ctrl_guest_offloads-machine-type-mi.patch [bz#1482468] -- Resolves: bz#1482468 - (KVM: windows guest migration from EL6 to EL7 fails. [rhel-7.4.z]) - -* Tue Jul 11 2017 Miroslav Rezanina - 1.5.3-141.el7_4.1 -- kvm-qemu-nbd-Ignore-SIGPIPE.patch [bz#1468107] -- Resolves: bz#1468107 - (CVE-2017-10664 qemu-kvm: Qemu: qemu-nbd: server breaks with SIGPIPE upon client abort [rhel-7.4.z]) +* Tue Feb 20 2018 Miroslav Rezanina - 1.5.3-156.el7 +- kvm-vnc-Fix-qemu-crashed-when-vnc-client-disconnect-sudd.patch [bz#1527405] +- kvm-fix-full-frame-updates-for-VNC-clients.patch [bz#1527405] +- kvm-vnc-update-fix.patch [bz#1527405] +- kvm-vnc-return-directly-if-no-vnc-client-connected.patch [bz#1527405] +- kvm-buffer-add-buffer_move_empty.patch [bz#1527405] +- kvm-buffer-add-buffer_move.patch [bz#1527405] +- kvm-vnc-kill-jobs-queue-buffer.patch [bz#1527405] +- kvm-vnc-jobs-move-buffer-reset-use-new-buffer-move.patch [bz#1527405] +- kvm-vnc-zap-dead-code.patch [bz#1527405] +- kvm-vnc-add-vnc_width-vnc_height-helpers.patch [bz#1527405] +- kvm-vnc-factor-out-vnc_update_server_surface.patch [bz#1527405] +- kvm-vnc-use-vnc_-width-height-in-vnc_set_area_dirty.patch [bz#1527405] +- kvm-vnc-only-alloc-server-surface-with-clients-connected.patch [bz#1527405] +- kvm-ui-fix-refresh-of-VNC-server-surface.patch [bz#1527405] +- kvm-ui-move-disconnecting-check-to-start-of-vnc_update_c.patch [bz#1527405] +- kvm-ui-remove-redundant-indentation-in-vnc_client_update.patch [bz#1527405] +- kvm-ui-avoid-pointless-VNC-updates-if-framebuffer-isn-t-.patch [bz#1527405] +- kvm-ui-track-how-much-decoded-data-we-consumed-when-doin.patch [bz#1527405] +- kvm-ui-introduce-enum-to-track-VNC-client-framebuffer-up.patch [bz#1527405] +- kvm-ui-correctly-reset-framebuffer-update-state-after-pr.patch [bz#1527405] +- kvm-ui-refactor-code-for-determining-if-an-update-should.patch [bz#1527405] +- kvm-ui-fix-VNC-client-throttling-when-audio-capture-is-a.patch [bz#1527405] +- kvm-ui-fix-VNC-client-throttling-when-forced-update-is-r.patch [bz#1527405] +- kvm-ui-place-a-hard-cap-on-VNC-server-output-buffer-size.patch [bz#1527405] +- kvm-ui-avoid-sign-extension-using-client-width-height.patch [bz#1527405] +- kvm-ui-correctly-advance-output-buffer-when-writing-SASL.patch [bz#1527405] +- kvm-io-skip-updates-to-client-if-websocket-output-buffer.patch [bz#1518711] +- Resolves: bz#1518711 + (CVE-2017-15268 qemu-kvm: Qemu: I/O: potential memory exhaustion via websock connection to VNC [rhel-7.5]) +- Resolves: bz#1527405 + (CVE-2017-15124 qemu-kvm: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5]) + +* Tue Jan 30 2018 Miroslav Rezanina - 1.5.3-155.el7 +- kvm-qdev-Fix-assert-in-PCI-address-property-when-used-by.patch [bz#1538866] +- kvm-vga-check-the-validation-of-memory-addr-when-draw-te.patch [bz#1534691] +- kvm-savevm-Improve-error-message-for-blocked-migration.patch [bz#1536883] +- kvm-savevm-fail-if-migration-blockers-are-present.patch [bz#1536883] +- Resolves: bz#1534691 + (CVE-2018-5683 qemu-kvm: Qemu: Out-of-bounds read in vga_draw_text routine [rhel-7.5]) +- Resolves: bz#1536883 + ([abrt] [faf] qemu-kvm: unknown function(): /usr/libexec/qemu-kvm killed by 6) +- Resolves: bz#1538866 + (qemu will coredump after executing info qtree) + +* Wed Jan 24 2018 Miroslav Rezanina - 1.5.3-154.el7 +- kvm-virtio-net-validate-backend-queue-numbers-against-bu.patch [bz#1460872] +- kvm-dump-guest-memory.py-fix-python-2-support.patch [bz#1411490] +- kvm-qxl-add-migration-blocker-to-avoid-pre-save-assert.patch [bz#1536883] +- Resolves: bz#1411490 + ([RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm)) +- Resolves: bz#1460872 + (Aborted(core dumped) when booting guest with "-netdev tap....vhost=on,queues=32") +- Resolves: bz#1536883 + ([abrt] [faf] qemu-kvm: unknown function(): /usr/libexec/qemu-kvm killed by 6) + +* Fri Jan 12 2018 Miroslav Rezanina - 1.5.3-153.el7 +- kvm-i386-update-ssdt-misc.hex.generated.patch [bz#1411490] +- kvm-main-loop-Acquire-main_context-lock-around-os_host_m.patch [bz#1435432 bz#1473536] +- Resolves: bz#1411490 + ([RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm)) +- Resolves: bz#1435432 + (Emulated ISA serial port hangs randomly when sending lots of data from guest -> host) +- Resolves: bz#1473536 + (Hangs in serial console under qemu) + +* Thu Jan 04 2018 Miroslav Rezanina - 1.5.3-152.el7 +- kvm-target-i386-cpu-add-new-CPUID-bits-for-indirect-bran.patch [CVE-2017-5715] +- kvm-target-i386-add-support-for-SPEC_CTRL-MSR.patch [CVE-2017-5715] +- kvm-target-i386-cpu-add-new-CPU-models-for-indirect-bran.patch [CVE-2017-5715] + +* Tue Dec 19 2017 Miroslav Rezanina - 1.5.3-151.el7 +- kvm-fw_cfg-remove-support-for-guest-side-data-writes.patch [bz#1411490] +- kvm-fw_cfg-prevent-selector-key-conflict.patch [bz#1411490] +- kvm-fw_cfg-prohibit-insertion-of-duplicate-fw_cfg-file-n.patch [bz#1411490] +- kvm-fw_cfg-factor-out-initialization-of-FW_CFG_ID-rev.-n.patch [bz#1411490] +- kvm-Implement-fw_cfg-DMA-interface.patch [bz#1411490] +- kvm-fw_cfg-avoid-calculating-invalid-current-entry-point.patch [bz#1411490] +- kvm-fw-cfg-support-writeable-blobs.patch [bz#1411490] +- kvm-Enable-fw_cfg-DMA-interface-for-x86.patch [bz#1411490] +- kvm-fw_cfg-unbreak-migration-compatibility.patch [bz#1411490] +- kvm-i386-expose-fw_cfg-QEMU0002-in-SSDT.patch [bz#1411490] +- kvm-fw_cfg-add-write-callback.patch [bz#1411490] +- kvm-hw-misc-add-vmcoreinfo-device.patch [bz#1411490] +- kvm-vmcoreinfo-put-it-in-the-misc-device-category.patch [bz#1411490] +- kvm-fw_cfg-enable-DMA-if-device-vmcoreinfo.patch [bz#1411490] +- kvm-build-sys-restrict-vmcoreinfo-to-fw_cfg-dma-capable-.patch [bz#1411490] +- kvm-dump-Make-DumpState-and-endian-conversion-routines-a.patch [bz#1411490] +- kvm-dump.c-Fix-memory-leak-issue-in-cleanup-processing-f.patch [bz#1411490] +- kvm-dump-Propagate-errors-into-qmp_dump_guest_memory.patch [bz#1411490] +- kvm-dump-Turn-some-functions-to-void-to-make-code-cleane.patch [bz#1411490] +- kvm-dump-Fix-dump-guest-memory-termination-and-use-after.patch [bz#1411490] +- kvm-dump-allow-target-to-set-the-page-size.patch [bz#1411490] +- kvm-dump-allow-target-to-set-the-physical-base.patch [bz#1411490] +- kvm-dump-guest-memory-cleanup-removing-dump_-error-clean.patch [bz#1411490] +- kvm-dump-guest-memory-using-static-DumpState-add-DumpSta.patch [bz#1411490] +- kvm-dump-guest-memory-add-dump_in_progress-helper-functi.patch [bz#1411490] +- kvm-dump-guest-memory-introduce-dump_process-helper-func.patch [bz#1411490] +- kvm-dump-guest-memory-disable-dump-when-in-INMIGRATE-sta.patch [bz#1411490] +- kvm-DumpState-adding-total_size-and-written_size-fields.patch [bz#1411490] +- kvm-dump-do-not-dump-non-existent-guest-memory.patch [bz#1411490] +- kvm-dump-add-guest-ELF-note.patch [bz#1411490] +- kvm-dump-update-phys_base-header-field-based-on-VMCOREIN.patch [bz#1411490] +- kvm-kdump-set-vmcoreinfo-location.patch [bz#1411490] +- kvm-scripts-dump-guest-memory.py-Move-constants-to-the-t.patch [bz#1411490] +- kvm-scripts-dump-guest-memory.py-Make-methods-functions.patch [bz#1411490] +- kvm-scripts-dump-guest-memory.py-Improve-python-3-compat.patch [bz#1411490] +- kvm-scripts-dump-guest-memory.py-Cleanup-functions.patch [bz#1411490] +- kvm-scripts-dump-guest-memory.py-Introduce-multi-arch-su.patch [bz#1411490] +- kvm-Fix-typo-in-variable-name-found-and-fixed-by-codespe.patch [bz#1411490] +- kvm-scripts-dump-guest-memory.py-add-vmcoreinfo.patch [bz#1411490] +- kvm-dump-guest-memory.py-fix-No-symbol-vmcoreinfo_find.patch [bz#1411490] +- kvm-dump-guest-memory.py-fix-You-can-t-do-that-without-a.patch [bz#1411490] +- Resolves: bz#1411490 + ([RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm)) + +* Tue Dec 12 2017 Miroslav Rezanina - 1.5.3-150.el7 +- kvm-Build-only-x86_64-packages.patch [bz#1520793] +- Resolves: bz#1520793 + (Do not build non-x86_64 subpackages) + +* Wed Nov 29 2017 Miroslav Rezanina - 1.5.3-149.el7 +- kvm-block-linux-aio-fix-memory-and-fd-leak.patch [bz#1491434] +- kvm-linux-aio-Fix-laio-resource-leak.patch [bz#1491434] +- kvm-slirp-cleanup-leftovers-from-misc.h.patch [bz#1508745] +- kvm-Avoid-embedding-struct-mbuf-in-other-structures.patch [bz#1508745] +- kvm-slirp-Fix-access-to-freed-memory.patch [bz#1508745] +- kvm-slirp-fix-clearing-ifq_so-from-pending-packets.patch [bz#1508745] +- kvm-qcow2-Prevent-backing-file-names-longer-than-1023.patch [bz#1459714] +- kvm-qemu-img-Use-strerror-for-generic-resize-error.patch [bz#1459725] +- kvm-qcow2-Avoid-making-the-L1-table-too-big.patch [bz#1459725] +- Resolves: bz#1459714 + (Throw error if qemu-img rebasing backing file is too long or provide way to fix a "too long" backing file.) +- Resolves: bz#1459725 + (Prevent qemu-img resize from causing "Active L1 table too large") +- Resolves: bz#1491434 + (KVM leaks file descriptors when attaching and detaching virtio-scsi block devices) +- Resolves: bz#1508745 + (CVE-2017-13711 qemu-kvm: Qemu: Slirp: use-after-free when sending response [rhel-7.5]) + +* Fri Nov 10 2017 Miroslav Rezanina - 1.5.3-148.el7 +- kvm-multiboot-validate-multiboot-header-address-values.patch [bz#1501121] +- kvm-qemu-option-reject-empty-number-value.patch [bz#1417864] +- Resolves: bz#1417864 + (Qemu-kvm starts with unspecified port) +- Resolves: bz#1501121 + (CVE-2017-14167 qemu-kvm: Qemu: i386: multiboot OOB access while loading kernel image [rhel-7.5]) + +* Fri Nov 03 2017 Miroslav Rezanina - 1.5.3-147.el7 +- kvm-vga-drop-line_offset-variable.patch [bz#1501295] +- kvm-vga-Add-mechanism-to-force-the-use-of-a-shadow-surfa.patch [bz#1501295] +- kvm-vga-handle-cirrus-vbe-mode-wraparounds.patch [bz#1501295] +- kvm-cirrus-fix-oob-access-in-mode4and5-write-functions.patch [bz#1501295] +- kvm-i6300esb-Fix-signed-integer-overflow.patch [bz#1470244] +- kvm-i6300esb-fix-timer-overflow.patch [bz#1470244] +- kvm-i6300esb-remove-muldiv64.patch [bz#1470244] +- Resolves: bz#1470244 + (reboot leads to shutoff of qemu-kvm-vm if i6300esb-watchdog set to poweroff) +- Resolves: bz#1501295 + (CVE-2017-15289 qemu-kvm: Qemu: cirrus: OOB access issue in mode4and5 write functions [rhel-7.5]) + +* Tue Oct 24 2017 Miroslav Rezanina - 1.5.3-146.el7 +- kvm-vfio-pass-device-to-vfio_mmap_bar-and-use-it-to-set-.patch [bz#1494181] +- kvm-hw-vfio-pci-Rename-VFIODevice-into-VFIOPCIDevice.patch [bz#1494181] +- kvm-hw-vfio-pci-generalize-mask-unmask-to-any-IRQ-index.patch [bz#1494181] +- kvm-hw-vfio-pci-introduce-minimalist-VFIODevice-with-fd.patch [bz#1494181] +- kvm-hw-vfio-pci-add-type-name-and-group-fields-in-VFIODe.patch [bz#1494181] +- kvm-hw-vfio-pci-handle-reset-at-VFIODevice.patch [bz#1494181] +- kvm-hw-vfio-pci-Introduce-VFIORegion.patch [bz#1494181] +- kvm-hw-vfio-pci-use-name-field-in-format-strings.patch [bz#1494181] +- kvm-vfio-Add-sysfsdev-property-for-pci-platform.patch [bz#1494181] +- kvm-vfio-remove-bootindex-property-from-qdev-to-qom.patch [bz#1494181] +- kvm-vfio-pci-Handle-host-oversight.patch [bz#1494181] +- kvm-vfio-pci-Fix-incorrect-error-message.patch [bz#1494181] +- kvm-vfio-Wrap-VFIO_DEVICE_GET_REGION_INFO.patch [bz#1494181] +- kvm-vfio-Generalize-region-support.patch [bz#1494181] +- kvm-vfio-Enable-sparse-mmap-capability.patch [bz#1494181] +- kvm-vfio-Handle-zero-length-sparse-mmap-ranges.patch [bz#1494181] +- kvm-bswap.h-Remove-cpu_to_32wu.patch [bz#1486642] +- kvm-hw-use-ld_p-st_p-instead-of-ld_raw-st_raw.patch [bz#1486642] +- kvm-vga-Start-cutting-out-non-32bpp-conversion-support.patch [bz#1486642] +- kvm-vga-Remove-remainder-of-old-conversion-cruft.patch [bz#1486642] +- kvm-vga-Separate-LE-and-BE-conversion-functions.patch [bz#1486642] +- kvm-vga-Rename-vga_template.h-to-vga-helpers.h.patch [bz#1486642] +- kvm-vga-stop-passing-pointers-to-vga_draw_line-functions.patch [bz#1486642] +- kvm-target-i386-Add-Intel-SHA_NI-instruction-support.patch [bz#1450396] +- kvm-target-i386-cpu-Add-new-EPYC-CPU-model.patch [bz#1450396] +- kvm-target-i386-Enable-clflushopt-clwb-pcommit-instructi.patch [bz#1501510] +- kvm-i386-add-Skylake-Server-cpu-model.patch [bz#1501510] +- Resolves: bz#1450396 + (Add support for AMD EPYC processors) +- Resolves: bz#1486642 + (CVE-2017-13672 qemu-kvm: Qemu: vga: OOB read access during display update [rhel-7.5]) +- Resolves: bz#1494181 + (Backport vGPU support to qemu-kvm) +- Resolves: bz#1501510 + (Add Skylake-Server CPU model (qemu-kvm)) + +* Fri Oct 06 2017 Miroslav Rezanina - 1.5.3-145.el7 +- kvm-qemu-char-add-Czech-characters-to-VNC-keysyms.patch [bz#1476641] +- kvm-qemu-char-add-missing-characters-used-in-keymaps.patch [bz#1476641] +- kvm-qemu-char-add-cyrillic-characters-numerosign-to-VNC-.patch [bz#1476641] +- kvm-block-ssh-Use-QemuOpts-for-runtime-options.patch [bz#1461672] +- Resolves: bz#1461672 + (qemu-img core dumped when create external snapshot through ssh protocol without specifying image size) +- Resolves: bz#1476641 + (ui/vnc_keysym.h is very out of date and does not correctly support many Eastern European keyboards) + +* Mon Oct 02 2017 Miroslav Rezanina - 1.5.3-144.el7 +- kvm-qemu-nbd-Ignore-SIGPIPE.patch [bz#1466463] +- Resolves: bz#1466463 + (CVE-2017-10664 qemu-kvm: Qemu: qemu-nbd: server breaks with SIGPIPE upon client abort [rhel-7.5]) + +* Thu Sep 28 2017 Wainer dos Santos Moschetta - 1.5.3-143.el7 +- kvm-block-Limit-multiwrite-merge-downstream-only.patch [bz#1492559] +- Resolves: bz#1492559 + (virtio-blk mutiwrite merge causes too big IO) + +* Wed Sep 20 2017 Miroslav Rezanina - 1.5.3-142.el7 +- kvm-vnc-allow-to-connect-with-add_client-when-vnc-none.patch [bz#1435352] +- kvm-virtio-net-dynamic-network-offloads-configuration.patch [bz#1480428] +- kvm-Workaround-rhel6-ctrl_guest_offloads-machine-type-mi.patch [bz#1480428] +- kvm-target-i386-Add-PKU-and-and-OSPKE-support.patch [bz#1387648] +- Resolves: bz#1387648 + ([Intel 7.5 FEAT] Memory Protection Keys for qemu-kvm) +- Resolves: bz#1435352 + (qemu started with "-vnc none,..." doesn't support any VNC authentication) +- Resolves: bz#1480428 + (KVM: windows guest migration from EL6 to EL7 fails.) * Tue Jun 13 2017 Miroslav Rezanina - 1.5.3-141.el7 - kvm-Fix-memory-slot-page-alignment-logic-bug-1455745.patch [bz#1455745]