Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package qemu for openSUSE:Factory checked in at 2023-02-14 20:07:51 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/qemu (Old) and /work/SRC/openSUSE:Factory/.qemu.new.22824 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "qemu" Tue Feb 14 20:07:51 2023 rev:246 rq:1065424 version:7.1.0 Changes: -------- --- /work/SRC/openSUSE:Factory/qemu/qemu.changes 2023-02-12 19:14:05.536956479 +0100 +++ /work/SRC/openSUSE:Factory/.qemu.new.22824/qemu.changes 2023-02-14 20:07:53.952191483 +0100 @@ -1,0 +2,24 @@ +Mon Feb 13 10:28:53 UTC 2023 - Li Zhang <li.zh...@suse.com> + +- Fixes: jsc#PED-1716 Add S390 features from IBM requirements +* Patches added: + dump-Add-architecture-section-and-sectio.patch + dump-Refactor-dump_iterate-and-introduce.patch + dump-Reintroduce-memory_offset-and-secti.patch + dump-Rename-write_elf_loads-to-write_elf.patch + dump-Rename-write_elf-_phdr_note-to-prep.patch + dump-Reorder-struct-DumpState.patch + dump-Replace-opaque-DumpState-pointer-wi.patch + dump-Rework-dump_calculate_size-function.patch + dump-Rework-filter-area-variables.patch + dump-Rework-get_start_block.patch + dump-Split-elf-header-functions-into-pre.patch + dump-Use-a-buffer-for-ELF-section-data-a.patch + dump-Write-ELF-section-headers-right-aft.patch + include-elf.h-add-s390x-note-types.patch + s390x-Add-KVM-PV-dump-interface.patch + s390x-Add-protected-dump-cap.patch + s390x-Introduce-PV-query-interface.patch + s390x-pv-Add-dump-support.patch + +------------------------------------------------------------------- New: ---- dump-Add-architecture-section-and-sectio.patch dump-Refactor-dump_iterate-and-introduce.patch dump-Reintroduce-memory_offset-and-secti.patch dump-Rename-write_elf-_phdr_note-to-prep.patch dump-Rename-write_elf_loads-to-write_elf.patch dump-Reorder-struct-DumpState.patch dump-Replace-opaque-DumpState-pointer-wi.patch dump-Rework-dump_calculate_size-function.patch dump-Rework-filter-area-variables.patch dump-Rework-get_start_block.patch dump-Split-elf-header-functions-into-pre.patch dump-Use-a-buffer-for-ELF-section-data-a.patch dump-Write-ELF-section-headers-right-aft.patch include-elf.h-add-s390x-note-types.patch s390x-Add-KVM-PV-dump-interface.patch s390x-Add-protected-dump-cap.patch s390x-Introduce-PV-query-interface.patch s390x-pv-Add-dump-support.patch ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ qemu.spec ++++++ --- /var/tmp/diff_new_pack.WpykMf/_old 2023-02-14 20:07:55.776201782 +0100 +++ /var/tmp/diff_new_pack.WpykMf/_new 2023-02-14 20:07:55.780201805 +0100 @@ -224,6 +224,24 @@ Patch00058: hw-display-qxl-Avoid-buffer-overrun-in-q.patch Patch00059: ui-vnc-clipboard-fix-integer-underflow-i.patch Patch00060: hw-acpi-erst.c-Fix-memory-handling-issue.patch +Patch00061: dump-Replace-opaque-DumpState-pointer-wi.patch +Patch00062: dump-Rename-write_elf_loads-to-write_elf.patch +Patch00063: dump-Refactor-dump_iterate-and-introduce.patch +Patch00064: dump-Rework-get_start_block.patch +Patch00065: dump-Rework-filter-area-variables.patch +Patch00066: dump-Rework-dump_calculate_size-function.patch +Patch00067: dump-Split-elf-header-functions-into-pre.patch +Patch00068: dump-Rename-write_elf-_phdr_note-to-prep.patch +Patch00069: dump-Use-a-buffer-for-ELF-section-data-a.patch +Patch00070: dump-Write-ELF-section-headers-right-aft.patch +Patch00071: dump-Reorder-struct-DumpState.patch +Patch00072: dump-Reintroduce-memory_offset-and-secti.patch +Patch00073: dump-Add-architecture-section-and-sectio.patch +Patch00074: s390x-Add-protected-dump-cap.patch +Patch00075: s390x-Introduce-PV-query-interface.patch +Patch00076: include-elf.h-add-s390x-note-types.patch +Patch00077: s390x-Add-KVM-PV-dump-interface.patch +Patch00078: s390x-pv-Add-dump-support.patch # Patches applied in roms/seabios/: Patch01000: openSUSE-switch-to-python3-as-needed.patch Patch01001: openSUSE-build-enable-cross-compilation-.patch ++++++ bundles.tar.xz ++++++ Binary files old/621da7789083b80d6f1ff1c0fb499334007b4f51.bundle and new/621da7789083b80d6f1ff1c0fb499334007b4f51.bundle differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/repo new/repo --- old/repo 2023-01-27 12:17:20.000000000 +0100 +++ new/repo 2022-09-20 19:50:47.000000000 +0200 @@ -1 +1 @@ -g...@github.com:openSUSE/qemu.git +https://github.com/openSUSE/qemu.git diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/roms/ipxe/repo new/roms/ipxe/repo --- old/roms/ipxe/repo 2023-01-27 12:17:20.000000000 +0100 +++ new/roms/ipxe/repo 2022-09-20 19:50:47.000000000 +0200 @@ -1 +1 @@ -https://git.qemu.org/git/ipxe.git +https://github.com/openSUSE/qemu-ipxe.git diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/roms/opensbi/repo new/roms/opensbi/repo --- old/roms/opensbi/repo 2023-01-27 12:17:20.000000000 +0100 +++ new/roms/opensbi/repo 2022-09-20 19:50:47.000000000 +0200 @@ -1 +1 @@ -https://git.qemu.org/git/opensbi.git +https://github.com/openSUSE/qemu-opensbi.git diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/roms/qboot/repo new/roms/qboot/repo --- old/roms/qboot/repo 2023-01-27 12:17:20.000000000 +0100 +++ new/roms/qboot/repo 2022-09-20 19:50:47.000000000 +0200 @@ -1 +1 @@ -https://github.com/bonzini/qboot +https://github.com/openSUSE/qemu-qboot.git diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/roms/seabios/repo new/roms/seabios/repo --- old/roms/seabios/repo 2023-01-27 12:17:20.000000000 +0100 +++ new/roms/seabios/repo 2022-09-20 19:50:47.000000000 +0200 @@ -1 +1 @@ -https://git.qemu.org/git/seabios.git/ +https://github.com/openSUSE/qemu-seabios.git diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/roms/sgabios/repo new/roms/sgabios/repo --- old/roms/sgabios/repo 2023-01-27 12:17:20.000000000 +0100 +++ new/roms/sgabios/repo 2022-09-20 19:50:47.000000000 +0200 @@ -1 +1 @@ -https://git.qemu.org/git/sgabios.git +https://github.com/openSUSE/qemu-sgabios.git diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/roms/skiboot/repo new/roms/skiboot/repo --- old/roms/skiboot/repo 2023-01-27 12:17:20.000000000 +0100 +++ new/roms/skiboot/repo 2022-09-20 19:50:47.000000000 +0200 @@ -1 +1 @@ -https://gitlab.com/qemu-project/skiboot.git +https://github.com/openSUSE/qemu-skiboot.git ++++++ dump-Add-architecture-section-and-sectio.patch ++++++ From: Janosch Frank <fran...@linux.ibm.com> Date: Mon, 17 Oct 2022 11:32:10 +0000 Subject: dump: Add architecture section and section string table support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Git-commit: 9b72224f44612ddd5b434a1bccf79346946d11da References: jsc#PED-1716 Add hooks which architectures can use to add arbitrary data to custom sections. Also add a section name string table in order to identify section contents Signed-off-by: Janosch Frank <fran...@linux.ibm.com> Reviewed-by: Marc-André Lureau <marcandre.lur...@redhat.com> Message-Id: <20221017113210.41674-1-fran...@linux.ibm.com> Signed-off-by: Li Zhang <lizh...@suse.de> --- dump/dump.c | 186 +++++++++++++++++++++++++++++++------ include/sysemu/dump-arch.h | 3 + include/sysemu/dump.h | 3 + 3 files changed, 166 insertions(+), 26 deletions(-) diff --git a/dump/dump.c b/dump/dump.c index a19d2420efe9575e97b8ba13d0ca..eb547e3e59e90681cddfc8c4080d 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -103,6 +103,7 @@ static int dump_cleanup(DumpState *s) memory_mapping_list_free(&s->list); close(s->fd); g_free(s->guest_note); + g_array_unref(s->string_table_buf); s->guest_note = NULL; if (s->resume) { if (s->detached) { @@ -152,11 +153,10 @@ static void prepare_elf64_header(DumpState *s, Elf64_Ehdr *elf_header) elf_header->e_phoff = cpu_to_dump64(s, s->phdr_offset); elf_header->e_phentsize = cpu_to_dump16(s, sizeof(Elf64_Phdr)); elf_header->e_phnum = cpu_to_dump16(s, phnum); - if (s->shdr_num) { - elf_header->e_shoff = cpu_to_dump64(s, s->shdr_offset); - elf_header->e_shentsize = cpu_to_dump16(s, sizeof(Elf64_Shdr)); - elf_header->e_shnum = cpu_to_dump16(s, s->shdr_num); - } + elf_header->e_shoff = cpu_to_dump64(s, s->shdr_offset); + elf_header->e_shentsize = cpu_to_dump16(s, sizeof(Elf64_Shdr)); + elf_header->e_shnum = cpu_to_dump16(s, s->shdr_num); + elf_header->e_shstrndx = cpu_to_dump16(s, s->shdr_num - 1); } static void prepare_elf32_header(DumpState *s, Elf32_Ehdr *elf_header) @@ -180,11 +180,10 @@ static void prepare_elf32_header(DumpState *s, Elf32_Ehdr *elf_header) elf_header->e_phoff = cpu_to_dump32(s, s->phdr_offset); elf_header->e_phentsize = cpu_to_dump16(s, sizeof(Elf32_Phdr)); elf_header->e_phnum = cpu_to_dump16(s, phnum); - if (s->shdr_num) { - elf_header->e_shoff = cpu_to_dump32(s, s->shdr_offset); - elf_header->e_shentsize = cpu_to_dump16(s, sizeof(Elf32_Shdr)); - elf_header->e_shnum = cpu_to_dump16(s, s->shdr_num); - } + elf_header->e_shoff = cpu_to_dump32(s, s->shdr_offset); + elf_header->e_shentsize = cpu_to_dump16(s, sizeof(Elf32_Shdr)); + elf_header->e_shnum = cpu_to_dump16(s, s->shdr_num); + elf_header->e_shstrndx = cpu_to_dump16(s, s->shdr_num - 1); } static void write_elf_header(DumpState *s, Error **errp) @@ -195,6 +194,8 @@ static void write_elf_header(DumpState *s, Error **errp) void *header_ptr; int ret; + /* The NULL header and the shstrtab are always defined */ + assert(s->shdr_num >= 2); if (dump_is_64bit(s)) { prepare_elf64_header(s, &elf64_header); header_size = sizeof(elf64_header); @@ -393,17 +394,49 @@ static void prepare_elf_section_hdr_zero(DumpState *s) } } -static void prepare_elf_section_hdrs(DumpState *s) +static void prepare_elf_section_hdr_string(DumpState *s, void *buff) +{ + uint64_t index = s->string_table_buf->len; + const char strtab[] = ".shstrtab"; + Elf32_Shdr shdr32 = {}; + Elf64_Shdr shdr64 = {}; + int shdr_size; + void *shdr; + + g_array_append_vals(s->string_table_buf, strtab, sizeof(strtab)); + if (dump_is_64bit(s)) { + shdr_size = sizeof(Elf64_Shdr); + shdr64.sh_type = SHT_STRTAB; + shdr64.sh_offset = s->section_offset + s->elf_section_data_size; + shdr64.sh_name = index; + shdr64.sh_size = s->string_table_buf->len; + shdr = &shdr64; + } else { + shdr_size = sizeof(Elf32_Shdr); + shdr32.sh_type = SHT_STRTAB; + shdr32.sh_offset = s->section_offset + s->elf_section_data_size; + shdr32.sh_name = index; + shdr32.sh_size = s->string_table_buf->len; + shdr = &shdr32; + } + memcpy(buff, shdr, shdr_size); +} + +static bool prepare_elf_section_hdrs(DumpState *s, Error **errp) { size_t len, sizeof_shdr; + void *buff_hdr; /* * Section ordering: * - HDR zero + * - Arch section hdrs + * - String table hdr */ sizeof_shdr = dump_is_64bit(s) ? sizeof(Elf64_Shdr) : sizeof(Elf32_Shdr); len = sizeof_shdr * s->shdr_num; s->elf_section_hdrs = g_malloc0(len); + buff_hdr = s->elf_section_hdrs; /* * The first section header is ALWAYS a special initial section @@ -419,6 +452,26 @@ static void prepare_elf_section_hdrs(DumpState *s) if (s->phdr_num >= PN_XNUM) { prepare_elf_section_hdr_zero(s); } + buff_hdr += sizeof_shdr; + + /* Add architecture defined section headers */ + if (s->dump_info.arch_sections_write_hdr_fn + && s->shdr_num > 2) { + buff_hdr += s->dump_info.arch_sections_write_hdr_fn(s, buff_hdr); + + if (s->shdr_num >= SHN_LORESERVE) { + error_setg_errno(errp, EINVAL, + "dump: too many architecture defined sections"); + return false; + } + } + + /* + * String table is the last section since strings are added via + * arch_sections_write_hdr(). + */ + prepare_elf_section_hdr_string(s, buff_hdr); + return true; } static void write_elf_section_headers(DumpState *s, Error **errp) @@ -426,7 +479,9 @@ static void write_elf_section_headers(DumpState *s, Error **errp) size_t sizeof_shdr = dump_is_64bit(s) ? sizeof(Elf64_Shdr) : sizeof(Elf32_Shdr); int ret; - prepare_elf_section_hdrs(s); + if (!prepare_elf_section_hdrs(s, errp)) { + return; + } ret = fd_write_vmcore(s->elf_section_hdrs, s->shdr_num * sizeof_shdr, s); if (ret < 0) { @@ -436,6 +491,29 @@ static void write_elf_section_headers(DumpState *s, Error **errp) g_free(s->elf_section_hdrs); } +static void write_elf_sections(DumpState *s, Error **errp) +{ + int ret; + + if (s->elf_section_data_size) { + /* Write architecture section data */ + ret = fd_write_vmcore(s->elf_section_data, + s->elf_section_data_size, s); + if (ret < 0) { + error_setg_errno(errp, -ret, + "dump: failed to write architecture section data"); + return; + } + } + + /* Write string table */ + ret = fd_write_vmcore(s->string_table_buf->data, + s->string_table_buf->len, s); + if (ret < 0) { + error_setg_errno(errp, -ret, "dump: failed to write string table data"); + } +} + static void write_data(DumpState *s, void *buf, int length, Error **errp) { int ret; @@ -692,6 +770,31 @@ static void dump_iterate(DumpState *s, Error **errp) } } +static void dump_end(DumpState *s, Error **errp) +{ + int rc; + ERRP_GUARD(); + + if (s->elf_section_data_size) { + s->elf_section_data = g_malloc0(s->elf_section_data_size); + } + + /* Adds the architecture defined section data to s->elf_section_data */ + if (s->dump_info.arch_sections_write_fn && + s->elf_section_data_size) { + rc = s->dump_info.arch_sections_write_fn(s, s->elf_section_data); + if (rc) { + error_setg_errno(errp, rc, + "dump: failed to get arch section data"); + g_free(s->elf_section_data); + return; + } + } + + /* write sections to vmcore */ + write_elf_sections(s, errp); +} + static void create_vmcore(DumpState *s, Error **errp) { ERRP_GUARD(); @@ -701,7 +804,14 @@ static void create_vmcore(DumpState *s, Error **errp) return; } + /* Iterate over memory and dump it to file */ dump_iterate(s, errp); + if (*errp) { + return; + } + + /* Write the section data */ + dump_end(s, errp); } static int write_start_flat_header(int fd) @@ -1683,6 +1793,14 @@ static void dump_init(DumpState *s, int fd, bool has_format, s->filter_area_begin = begin; s->filter_area_length = length; + /* First index is 0, it's the special null name */ + s->string_table_buf = g_array_new(FALSE, TRUE, 1); + /* + * Allocate the null name, due to the clearing option set to true + * it will be 0. + */ + g_array_set_size(s->string_table_buf, 1); + memory_mapping_list_init(&s->list); guest_phys_blocks_init(&s->guest_phys_blocks); @@ -1819,26 +1937,42 @@ static void dump_init(DumpState *s, int fd, bool has_format, } /* - * calculate phdr_num + * The first section header is always a special one in which most + * fields are 0. The section header string table is also always + * set. + */ + s->shdr_num = 2; + + /* + * Adds the number of architecture sections to shdr_num and sets + * elf_section_data_size so we know the offsets and sizes of all + * parts. + */ + if (s->dump_info.arch_sections_add_fn) { + s->dump_info.arch_sections_add_fn(s); + } + + /* + * calculate shdr_num so we know the offsets and sizes of all + * parts. + * Calculate phdr_num * - * the type of ehdr->e_phnum is uint16_t, so we should avoid overflow + * The absolute maximum amount of phdrs is UINT32_MAX - 1 as + * sh_info is 32 bit. There's special handling once we go over + * UINT16_MAX - 1 but that is handled in the ehdr and section + * code. */ - s->phdr_num = 1; /* PT_NOTE */ - if (s->list.num < UINT16_MAX - 2) { - s->shdr_num = 0; + s->phdr_num = 1; /* Reserve PT_NOTE */ + if (s->list.num <= UINT32_MAX - 1) { s->phdr_num += s->list.num; } else { - /* sh_info of section 0 holds the real number of phdrs */ - s->shdr_num = 1; - - /* the type of shdr->sh_info is uint32_t, so we should avoid overflow */ - if (s->list.num <= UINT32_MAX - 1) { - s->phdr_num += s->list.num; - } else { - s->phdr_num = UINT32_MAX; - } + s->phdr_num = UINT32_MAX; } + /* + * Now that the number of section and program headers is known we + * can calculate the offsets of the headers and data. + */ if (dump_is_64bit(s)) { s->shdr_offset = sizeof(Elf64_Ehdr); s->phdr_offset = s->shdr_offset + sizeof(Elf64_Shdr) * s->shdr_num; diff --git a/include/sysemu/dump-arch.h b/include/sysemu/dump-arch.h index e25b02e99013c75316c8b79da9a3..59bbc9be38c9af0f6181743e2d5c 100644 --- a/include/sysemu/dump-arch.h +++ b/include/sysemu/dump-arch.h @@ -21,6 +21,9 @@ typedef struct ArchDumpInfo { 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. */ + void (*arch_sections_add_fn)(DumpState *s); + uint64_t (*arch_sections_write_hdr_fn)(DumpState *s, uint8_t *buff); + int (*arch_sections_write_fn)(DumpState *s, uint8_t *buff); } ArchDumpInfo; struct GuestPhysBlockList; /* memory_mapping.h */ diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h index 9ed811b31331a4c56b7cb851bd02..38ccac7190a253b6c0da3395ac16 100644 --- a/include/sysemu/dump.h +++ b/include/sysemu/dump.h @@ -180,6 +180,9 @@ typedef struct DumpState { hwaddr note_offset; void *elf_section_hdrs; /* Pointer to section header buffer */ + void *elf_section_data; /* Pointer to section data buffer */ + uint64_t elf_section_data_size; /* Size of section data */ + GArray *string_table_buf; /* String table data buffer */ uint8_t *note_buf; /* buffer for notes */ size_t note_buf_offset; /* the writing place in note_buf */ ++++++ dump-Refactor-dump_iterate-and-introduce.patch ++++++ From: Janosch Frank <fran...@linux.ibm.com> Date: Thu, 11 Aug 2022 12:10:56 +0000 Subject: dump: Refactor dump_iterate and introduce dump_filter_memblock_*() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Git-commit: 1e8113032f5b1efc5da66382470ce4809c76f8f2 References: jsc#PED-1716 The iteration over the memblocks in dump_iterate() is hard to understand so it's about time to clean it up. Instead of manually grabbing the next memblock we can use QTAILQ_FOREACH to iterate over all memblocks. Additionally we move the calculation of the offset and length out by introducing and using the dump_filter_memblock_*() functions. These functions will later be used to cleanup other parts of dump.c. Signed-off-by: Janosch Frank <fran...@linux.ibm.com> Reviewed-by: Janis Schoetterl-Glausch <s...@linux.ibm.com> Reviewed-by: Marc-André Lureau <marcandre.lur...@redhat.com> Message-Id: <20220811121111.9878-4-fran...@linux.ibm.com> Signed-off-by: Li Zhang <lizh...@suse.de> --- dump/dump.c | 74 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/dump/dump.c b/dump/dump.c index 0ed7cf9c7bba191f5a4dee5a796d..340de5a1e7a463573a14a0565682 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -591,31 +591,43 @@ static void dump_begin(DumpState *s, Error **errp) write_elf_notes(s, errp); } -static int get_next_block(DumpState *s, GuestPhysBlock *block) +static int64_t dump_filtered_memblock_size(GuestPhysBlock *block, + int64_t filter_area_start, + int64_t filter_area_length) { - while (1) { - block = QTAILQ_NEXT(block, next); - if (!block) { - /* no more block */ - return 1; - } + int64_t size, left, right; - s->start = 0; - s->next_block = block; - if (s->has_filter) { - if (block->target_start >= s->begin + s->length || - block->target_end <= s->begin) { - /* This block is out of the range */ - continue; - } + /* No filter, return full size */ + if (!filter_area_length) { + return block->target_end - block->target_start; + } - if (s->begin > block->target_start) { - s->start = s->begin - block->target_start; - } + /* calculate the overlapped region. */ + left = MAX(filter_area_start, block->target_start); + right = MIN(filter_area_start + filter_area_length, block->target_end); + size = right - left; + size = size > 0 ? size : 0; + + return size; +} + +static int64_t dump_filtered_memblock_start(GuestPhysBlock *block, + int64_t filter_area_start, + int64_t filter_area_length) +{ + if (filter_area_length) { + /* return -1 if the block is not within filter area */ + if (block->target_start >= filter_area_start + filter_area_length || + block->target_end <= filter_area_start) { + return -1; } - return 0; + if (filter_area_start > block->target_start) { + return filter_area_start - block->target_start; + } } + + return 0; } /* write all memory to vmcore */ @@ -623,24 +635,22 @@ static void dump_iterate(DumpState *s, Error **errp) { ERRP_GUARD(); GuestPhysBlock *block; - int64_t size; - - do { - block = s->next_block; + int64_t memblock_size, memblock_start; - size = block->target_end - block->target_start; - if (s->has_filter) { - size -= s->start; - if (s->begin + s->length < block->target_end) { - size -= block->target_end - (s->begin + s->length); - } + QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) { + memblock_start = dump_filtered_memblock_start(block, s->begin, s->length); + if (memblock_start == -1) { + continue; } - write_memory(s, block, s->start, size, errp); + + memblock_size = dump_filtered_memblock_size(block, s->begin, s->length); + + /* Write the memory to file */ + write_memory(s, block, memblock_start, memblock_size, errp); if (*errp) { return; } - - } while (!get_next_block(s, block)); + } } static void create_vmcore(DumpState *s, Error **errp) ++++++ dump-Reintroduce-memory_offset-and-secti.patch ++++++ From: Janosch Frank <fran...@linux.ibm.com> Date: Mon, 17 Oct 2022 08:38:16 +0000 Subject: dump: Reintroduce memory_offset and section_offset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Git-commit: 13fd417ddc81a1685c6a8f4e1c80bbfe7150f164 References: jsc#PED-1716 section_offset will later be used to store the offset to the section data which will be stored last. For now memory_offset is only needed to make section_offset look nicer. Signed-off-by: Janosch Frank <fran...@linux.ibm.com> Reviewed-by: Marc-André Lureau <marcandre.lur...@redhat.com> Message-Id: <20221017083822.43118-5-fran...@linux.ibm.com> Signed-off-by: Li Zhang <lizh...@suse.de> --- dump/dump.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dump/dump.c b/dump/dump.c index 4a38daf35cf3c4d5dd7c2216677d..a19d2420efe9575e97b8ba13d0ca 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -1848,6 +1848,8 @@ static void dump_init(DumpState *s, int fd, bool has_format, s->phdr_offset = s->shdr_offset + sizeof(Elf32_Shdr) * s->shdr_num; s->note_offset = s->phdr_offset + sizeof(Elf32_Phdr) * s->phdr_num; } + s->memory_offset = s->note_offset + s->note_size; + s->section_offset = s->memory_offset + s->total_size; return; ++++++ dump-Rename-write_elf-_phdr_note-to-prep.patch ++++++ From: Janosch Frank <fran...@linux.ibm.com> Date: Thu, 11 Aug 2022 12:11:01 +0000 Subject: dump: Rename write_elf*_phdr_note to prepare_elf*_phdr_note MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Git-commit: 2341a94d3a0a8a93a5a977e642da1807b8edaab8 References: jsc#PED-1716 The functions in question do not actually write to the file descriptor they set up a buffer which is later written to the fd. Signed-off-by: Janosch Frank <fran...@linux.ibm.com> Reviewed-by: Janis Schoetterl-Glausch <s...@linux.ibm.com> Reviewed-by: Marc-André Lureau <marcandre.lur...@redhat.com> Message-Id: <20220811121111.9878-9-fran...@linux.ibm.com> (cherry picked from commit 2341a94d3a0a8a93a5a977e642da1807b8edaab8) Signed-off-by: Li Zhang <lizh...@suse.de> --- dump/dump.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dump/dump.c b/dump/dump.c index 8a2a97a85eb151d06072fa38fec5..a905316fe52ba59bfb66c94348f6 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -260,7 +260,7 @@ static void write_elf32_load(DumpState *s, MemoryMapping *memory_mapping, } } -static void write_elf64_phdr_note(DumpState *s, Elf64_Phdr *phdr) +static void prepare_elf64_phdr_note(DumpState *s, Elf64_Phdr *phdr) { memset(phdr, 0, sizeof(*phdr)); phdr->p_type = cpu_to_dump32(s, PT_NOTE); @@ -316,7 +316,7 @@ static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s, write_guest_note(f, s, errp); } -static void write_elf32_phdr_note(DumpState *s, Elf32_Phdr *phdr) +static void prepare_elf32_phdr_note(DumpState *s, Elf32_Phdr *phdr) { memset(phdr, 0, sizeof(*phdr)); phdr->p_type = cpu_to_dump32(s, PT_NOTE); @@ -364,11 +364,11 @@ static void write_elf_phdr_note(DumpState *s, Error **errp) int ret; if (dump_is_64bit(s)) { - write_elf64_phdr_note(s, &phdr64); + prepare_elf64_phdr_note(s, &phdr64); size = sizeof(phdr64); phdr = &phdr64; } else { - write_elf32_phdr_note(s, &phdr32); + prepare_elf32_phdr_note(s, &phdr32); size = sizeof(phdr32); phdr = &phdr32; } ++++++ dump-Rename-write_elf_loads-to-write_elf.patch ++++++ From: Janosch Frank <fran...@linux.ibm.com> Date: Thu, 11 Aug 2022 12:10:55 +0000 Subject: dump: Rename write_elf_loads to write_elf_phdr_loads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Git-commit: afae6056ea79e2d89fd90867de3a01732eae724f References: jsc#PED-1716 Let's make it a bit clearer that we write the program headers of the PT_LOAD type. Signed-off-by: Janosch Frank <fran...@linux.ibm.com> Reviewed-by: Marc-André Lureau <marcandre.lur...@redhat.com> Reviewed-by: Janis Schoetterl-Glausch <s...@linux.ibm.com> Reviewed-by: Steffen Eiden <sei...@ibm.linux.com> Message-Id: <20220811121111.9878-3-fran...@linux.ibm.com> Signed-off-by: Li Zhang <lizh...@suse.de> --- dump/dump.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dump/dump.c b/dump/dump.c index 4d9658ffa24f6e9fc8d91e519f02..0ed7cf9c7bba191f5a4dee5a796d 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -490,7 +490,7 @@ static void get_offset_range(hwaddr phys_addr, } } -static void write_elf_loads(DumpState *s, Error **errp) +static void write_elf_phdr_loads(DumpState *s, Error **errp) { ERRP_GUARD(); hwaddr offset, filesz; @@ -573,8 +573,8 @@ static void dump_begin(DumpState *s, Error **errp) return; } - /* write all PT_LOAD to vmcore */ - write_elf_loads(s, errp); + /* write all PT_LOADs to vmcore */ + write_elf_phdr_loads(s, errp); if (*errp) { return; } ++++++ dump-Reorder-struct-DumpState.patch ++++++ From: Janosch Frank <fran...@linux.ibm.com> Date: Mon, 17 Oct 2022 08:38:15 +0000 Subject: dump: Reorder struct DumpState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Git-commit: 8384b73c46fd474847d7e74d121318e344edc3c4 References: jsc#PED-1716 Let's move ELF related members into one block and guest memory related ones into another to improve readability. Signed-off-by: Janosch Frank <fran...@linux.ibm.com> Reviewed-by: Richard Henderson <richard.hender...@linaro.org> Reviewed-by: Marc-André Lureau <marcandre.lur...@redhat.com> Message-Id: <20221017083822.43118-4-fran...@linux.ibm.com> Signed-off-by: Li Zhang <lizh...@suse.de> --- include/sysemu/dump.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h index 9995f65dc8b18420292beb48ee82..9ed811b31331a4c56b7cb851bd02 100644 --- a/include/sysemu/dump.h +++ b/include/sysemu/dump.h @@ -154,15 +154,8 @@ typedef struct DumpState { GuestPhysBlockList guest_phys_blocks; ArchDumpInfo dump_info; MemoryMappingList list; - uint32_t phdr_num; - uint32_t shdr_num; bool resume; bool detached; - ssize_t note_size; - hwaddr shdr_offset; - hwaddr phdr_offset; - hwaddr section_offset; - hwaddr note_offset; hwaddr memory_offset; int fd; @@ -177,6 +170,15 @@ typedef struct DumpState { int64_t filter_area_begin; /* Start address of partial guest memory area */ int64_t filter_area_length; /* Length of partial guest memory area */ + /* Elf dump related data */ + uint32_t phdr_num; + uint32_t shdr_num; + ssize_t note_size; + hwaddr shdr_offset; + hwaddr phdr_offset; + hwaddr section_offset; + hwaddr note_offset; + void *elf_section_hdrs; /* Pointer to section header buffer */ uint8_t *note_buf; /* buffer for notes */ ++++++ dump-Replace-opaque-DumpState-pointer-wi.patch ++++++ From: Janosch Frank <fran...@linux.ibm.com> Date: Thu, 11 Aug 2022 12:10:54 +0000 Subject: dump: Replace opaque DumpState pointer with a typed one MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Git-commit: 1af0006ab959864dfa2f59e9136c5fb93000b61f References: jsc#PED-1716 It's always better to convey the type of a pointer if at all possible. So let's add the DumpState typedef to typedefs.h and move the dump note functions from the opaque pointers to DumpState pointers. Signed-off-by: Janosch Frank <fran...@linux.ibm.com> CC: Peter Maydell <peter.mayd...@linaro.org> CC: Cédric Le Goater <c...@kaod.org> CC: Daniel Henrique Barboza <danielhb...@gmail.com> CC: David Gibson <da...@gibson.dropbear.id.au> CC: Greg Kurz <gr...@kaod.org> CC: Palmer Dabbelt <pal...@dabbelt.com> CC: Alistair Francis <alistair.fran...@wdc.com> CC: Bin Meng <bin.m...@windriver.com> CC: Cornelia Huck <coh...@redhat.com> CC: Thomas Huth <th...@redhat.com> CC: Richard Henderson <richard.hender...@linaro.org> CC: David Hildenbrand <da...@redhat.com> Acked-by: Daniel Henrique Barboza <danielhb...@gmail.com> Reviewed-by: Marc-André Lureau <marcandre.lur...@redhat.com> Message-Id: <20220811121111.9878-2-fran...@linux.ibm.com> Signed-off-by: Li Zhang <lizh...@suse.de> --- include/hw/core/sysemu-cpu-ops.h | 8 ++++---- include/qemu/typedefs.h | 1 + target/arm/arch_dump.c | 6 ++---- target/arm/cpu.h | 4 ++-- target/i386/arch_dump.c | 30 +++++++++++++++--------------- target/i386/cpu.h | 8 ++++---- target/ppc/arch_dump.c | 18 +++++++++--------- target/ppc/cpu.h | 4 ++-- target/riscv/arch_dump.c | 6 ++---- target/riscv/cpu.h | 4 ++-- target/s390x/arch_dump.c | 10 +++++----- target/s390x/s390x-internal.h | 2 +- 12 files changed, 49 insertions(+), 52 deletions(-) diff --git a/include/hw/core/sysemu-cpu-ops.h b/include/hw/core/sysemu-cpu-ops.h index a9ba39e5f258e0cbd95278890b21..ee169b872ca1e36b73c1daea8fb5 100644 --- a/include/hw/core/sysemu-cpu-ops.h +++ b/include/hw/core/sysemu-cpu-ops.h @@ -53,25 +53,25 @@ typedef struct SysemuCPUOps { * 32-bit VM coredump. */ int (*write_elf32_note)(WriteCoreDumpFunction f, CPUState *cpu, - int cpuid, void *opaque); + int cpuid, DumpState *s); /** * @write_elf64_note: Callback for writing a CPU-specific ELF note to a * 64-bit VM coredump. */ int (*write_elf64_note)(WriteCoreDumpFunction f, CPUState *cpu, - int cpuid, void *opaque); + int cpuid, DumpState *s); /** * @write_elf32_qemunote: Callback for writing a CPU- and QEMU-specific ELF * note to a 32-bit VM coredump. */ int (*write_elf32_qemunote)(WriteCoreDumpFunction f, CPUState *cpu, - void *opaque); + DumpState *s); /** * @write_elf64_qemunote: Callback for writing a CPU- and QEMU-specific ELF * note to a 64-bit VM coredump. */ int (*write_elf64_qemunote)(WriteCoreDumpFunction f, CPUState *cpu, - void *opaque); + DumpState *s); /** * @virtio_is_big_endian: Callback to return %true if a CPU which supports * runtime configurable endianness is currently big-endian. diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 42f4ceb701b100c20349998b34a8..054fd46fa6054dbca6b45e23984d 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -129,6 +129,7 @@ typedef struct VirtIODevice VirtIODevice; typedef struct Visitor Visitor; typedef struct VMChangeStateEntry VMChangeStateEntry; typedef struct VMStateDescription VMStateDescription; +typedef struct DumpState DumpState; /* * Pointer types diff --git a/target/arm/arch_dump.c b/target/arm/arch_dump.c index b1f040e69f225966456d89378194..2d8e41ab8a3b72a30b6dbdf05f4b 100644 --- a/target/arm/arch_dump.c +++ b/target/arm/arch_dump.c @@ -232,12 +232,11 @@ static int aarch64_write_elf64_sve(WriteCoreDumpFunction f, #endif int arm_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque) + int cpuid, DumpState *s) { struct aarch64_note note; ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; - DumpState *s = opaque; uint64_t pstate, sp; int ret, i; @@ -360,12 +359,11 @@ static int arm_write_elf32_vfp(WriteCoreDumpFunction f, CPUARMState *env, } int arm_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque) + int cpuid, DumpState *s) { struct arm_note note; ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; - DumpState *s = opaque; int ret, i; bool fpvalid = cpu_isar_feature(aa32_vfp_simd, cpu); diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 5168e3d837e88d5c8defa77f10cc..fc8b358779c74d24aa747da0e796 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1100,9 +1100,9 @@ int arm_gen_dynamic_svereg_xml(CPUState *cpu, int base_reg); const char *arm_gdb_get_dynamic_xml(CPUState *cpu, const char *xmlname); int arm_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque); + int cpuid, DumpState *s); int arm_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque); + int cpuid, DumpState *s); #ifdef TARGET_AARCH64 int aarch64_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); diff --git a/target/i386/arch_dump.c b/target/i386/arch_dump.c index 004141fc0421ff72a938197a9ad9..c290910a04b41fc710c457aafe95 100644 --- a/target/i386/arch_dump.c +++ b/target/i386/arch_dump.c @@ -42,7 +42,7 @@ typedef struct { static int x86_64_write_elf64_note(WriteCoreDumpFunction f, CPUX86State *env, int id, - void *opaque) + DumpState *s) { x86_64_user_regs_struct regs; Elf64_Nhdr *note; @@ -94,7 +94,7 @@ static int x86_64_write_elf64_note(WriteCoreDumpFunction f, buf += descsz - sizeof(x86_64_user_regs_struct)-sizeof(target_ulong); memcpy(buf, ®s, sizeof(x86_64_user_regs_struct)); - ret = f(note, note_size, opaque); + ret = f(note, note_size, s); g_free(note); if (ret < 0) { return -1; @@ -148,7 +148,7 @@ static void x86_fill_elf_prstatus(x86_elf_prstatus *prstatus, CPUX86State *env, } static int x86_write_elf64_note(WriteCoreDumpFunction f, CPUX86State *env, - int id, void *opaque) + int id, DumpState *s) { x86_elf_prstatus prstatus; Elf64_Nhdr *note; @@ -170,7 +170,7 @@ static int x86_write_elf64_note(WriteCoreDumpFunction f, CPUX86State *env, buf += ROUND_UP(name_size, 4); memcpy(buf, &prstatus, sizeof(prstatus)); - ret = f(note, note_size, opaque); + ret = f(note, note_size, s); g_free(note); if (ret < 0) { return -1; @@ -180,7 +180,7 @@ static int x86_write_elf64_note(WriteCoreDumpFunction f, CPUX86State *env, } int x86_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque) + int cpuid, DumpState *s) { X86CPU *cpu = X86_CPU(cs); int ret; @@ -189,10 +189,10 @@ int x86_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, bool lma = !!(first_x86_cpu->env.hflags & HF_LMA_MASK); if (lma) { - ret = x86_64_write_elf64_note(f, &cpu->env, cpuid, opaque); + ret = x86_64_write_elf64_note(f, &cpu->env, cpuid, s); } else { #endif - ret = x86_write_elf64_note(f, &cpu->env, cpuid, opaque); + ret = x86_write_elf64_note(f, &cpu->env, cpuid, s); #ifdef TARGET_X86_64 } #endif @@ -201,7 +201,7 @@ int x86_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, } int x86_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque) + int cpuid, DumpState *s) { X86CPU *cpu = X86_CPU(cs); x86_elf_prstatus prstatus; @@ -224,7 +224,7 @@ int x86_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, buf += ROUND_UP(name_size, 4); memcpy(buf, &prstatus, sizeof(prstatus)); - ret = f(note, note_size, opaque); + ret = f(note, note_size, s); g_free(note); if (ret < 0) { return -1; @@ -329,7 +329,7 @@ static void qemu_get_cpustate(QEMUCPUState *s, CPUX86State *env) static inline int cpu_write_qemu_note(WriteCoreDumpFunction f, CPUX86State *env, - void *opaque, + DumpState *s, int type) { QEMUCPUState state; @@ -369,7 +369,7 @@ static inline int cpu_write_qemu_note(WriteCoreDumpFunction f, buf += ROUND_UP(name_size, 4); memcpy(buf, &state, sizeof(state)); - ret = f(note, note_size, opaque); + ret = f(note, note_size, s); g_free(note); if (ret < 0) { return -1; @@ -379,19 +379,19 @@ static inline int cpu_write_qemu_note(WriteCoreDumpFunction f, } int x86_cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cs, - void *opaque) + DumpState *s) { X86CPU *cpu = X86_CPU(cs); - return cpu_write_qemu_note(f, &cpu->env, opaque, 1); + return cpu_write_qemu_note(f, &cpu->env, s, 1); } int x86_cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cs, - void *opaque) + DumpState *s) { X86CPU *cpu = X86_CPU(cs); - return cpu_write_qemu_note(f, &cpu->env, opaque, 0); + return cpu_write_qemu_note(f, &cpu->env, s, 0); } int cpu_get_dump_info(ArchDumpInfo *info, diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 82004b65b944132781821248914f..b75108d6a3adb90a2e183c73c81d 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1938,13 +1938,13 @@ extern const VMStateDescription vmstate_x86_cpu; int x86_cpu_pending_interrupt(CPUState *cs, int interrupt_request); int x86_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu, - int cpuid, void *opaque); + int cpuid, DumpState *s); int x86_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu, - int cpuid, void *opaque); + int cpuid, DumpState *s); int x86_cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu, - void *opaque); + DumpState *s); int x86_cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu, - void *opaque); + DumpState *s); void x86_cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, Error **errp); diff --git a/target/ppc/arch_dump.c b/target/ppc/arch_dump.c index 1139cead9fed0258f7eb3b00cee5..f58e6359d5eb927bb4fd0a621bc8 100644 --- a/target/ppc/arch_dump.c +++ b/target/ppc/arch_dump.c @@ -270,23 +270,23 @@ ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) static int ppc_write_all_elf_notes(const char *note_name, WriteCoreDumpFunction f, PowerPCCPU *cpu, int id, - void *opaque) + DumpState *s) { - NoteFuncArg arg = { .state = opaque }; + NoteFuncArg arg = { .state = s }; int ret = -1; int note_size; const NoteFuncDesc *nf; for (nf = note_func; nf->note_contents_func; nf++) { - arg.note.hdr.n_namesz = cpu_to_dump32(opaque, sizeof(arg.note.name)); - arg.note.hdr.n_descsz = cpu_to_dump32(opaque, nf->contents_size); + arg.note.hdr.n_namesz = cpu_to_dump32(s, sizeof(arg.note.name)); + arg.note.hdr.n_descsz = cpu_to_dump32(s, nf->contents_size); strncpy(arg.note.name, note_name, sizeof(arg.note.name)); (*nf->note_contents_func)(&arg, cpu); note_size = sizeof(arg.note) - sizeof(arg.note.contents) + nf->contents_size; - ret = f(&arg.note, note_size, opaque); + ret = f(&arg.note, note_size, s); if (ret < 0) { return -1; } @@ -295,15 +295,15 @@ static int ppc_write_all_elf_notes(const char *note_name, } int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque) + int cpuid, DumpState *s) { PowerPCCPU *cpu = POWERPC_CPU(cs); - return ppc_write_all_elf_notes("CORE", f, cpu, cpuid, opaque); + return ppc_write_all_elf_notes("CORE", f, cpu, cpuid, s); } int ppc32_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque) + int cpuid, DumpState *s) { PowerPCCPU *cpu = POWERPC_CPU(cs); - return ppc_write_all_elf_notes("CORE", f, cpu, cpuid, opaque); + return ppc_write_all_elf_notes("CORE", f, cpu, cpuid, s); } diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index a4c893cfadbb75a2c1600259a6de..f7d28fe093fa6568a62227e26b27 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1354,9 +1354,9 @@ void ppc_gdb_gen_spr_xml(PowerPCCPU *cpu); const char *ppc_gdb_get_dynamic_xml(CPUState *cs, const char *xml_name); #endif int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque); + int cpuid, DumpState *s); int ppc32_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque); + int cpuid, DumpState *s); #ifndef CONFIG_USER_ONLY void ppc_cpu_do_interrupt(CPUState *cpu); bool ppc_cpu_exec_interrupt(CPUState *cpu, int int_req); diff --git a/target/riscv/arch_dump.c b/target/riscv/arch_dump.c index 709f621d826a953f5f41c2164c19..736a232956e16e0b0becf100af5f 100644 --- a/target/riscv/arch_dump.c +++ b/target/riscv/arch_dump.c @@ -64,12 +64,11 @@ static void riscv64_note_init(struct riscv64_note *note, DumpState *s, } int riscv_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque) + int cpuid, DumpState *s) { struct riscv64_note note; RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; - DumpState *s = opaque; int ret, i = 0; const char name[] = "CORE"; @@ -134,12 +133,11 @@ static void riscv32_note_init(struct riscv32_note *note, DumpState *s, } int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque) + int cpuid, DumpState *s) { struct riscv32_note note; RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; - DumpState *s = opaque; int ret, i; const char name[] = "CORE"; diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 5c7acc055ac9a36546e6e46a1761..9699504721c86529fa7f3cb1ffe4 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -505,9 +505,9 @@ extern const char * const riscv_fpr_regnames[]; const char *riscv_cpu_get_trap_name(target_ulong cause, bool async); void riscv_cpu_do_interrupt(CPUState *cpu); int riscv_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque); + int cpuid, DumpState *s); int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque); + int cpuid, DumpState *s); int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero); diff --git a/target/s390x/arch_dump.c b/target/s390x/arch_dump.c index 08daf93ae1f09fffb08a6d94b4de..f60a14920d45e6b9c61bcd06147a 100644 --- a/target/s390x/arch_dump.c +++ b/target/s390x/arch_dump.c @@ -204,7 +204,7 @@ static const NoteFuncDesc note_linux[] = { static int s390x_write_elf64_notes(const char *note_name, WriteCoreDumpFunction f, S390CPU *cpu, int id, - void *opaque, + DumpState *s, const NoteFuncDesc *funcs) { Note note; @@ -222,7 +222,7 @@ static int s390x_write_elf64_notes(const char *note_name, (*nf->note_contents_func)(¬e, cpu, id); note_size = sizeof(note) - sizeof(note.contents) + nf->contents_size; - ret = f(¬e, note_size, opaque); + ret = f(¬e, note_size, s); if (ret < 0) { return -1; @@ -235,16 +235,16 @@ static int s390x_write_elf64_notes(const char *note_name, int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque) + int cpuid, DumpState *s) { S390CPU *cpu = S390_CPU(cs); int r; - r = s390x_write_elf64_notes("CORE", f, cpu, cpuid, opaque, note_core); + r = s390x_write_elf64_notes("CORE", f, cpu, cpuid, s, note_core); if (r) { return r; } - return s390x_write_elf64_notes("LINUX", f, cpu, cpuid, opaque, note_linux); + return s390x_write_elf64_notes("LINUX", f, cpu, cpuid, s, note_linux); } int cpu_get_dump_info(ArchDumpInfo *info, diff --git a/target/s390x/s390x-internal.h b/target/s390x/s390x-internal.h index 6aba7fd0ca8a3b158dc3f1cba9fb..b5ae0ae3642e28ed106a7cdc46e1 100644 --- a/target/s390x/s390x-internal.h +++ b/target/s390x/s390x-internal.h @@ -227,7 +227,7 @@ static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb, /* arch_dump.c */ int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque); + int cpuid, DumpState *s); /* cc_helper.c */ ++++++ dump-Rework-dump_calculate_size-function.patch ++++++ From: Janosch Frank <fran...@linux.ibm.com> Date: Thu, 11 Aug 2022 12:10:59 +0000 Subject: dump: Rework dump_calculate_size function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Git-commit: c370d5300f9ac1f90f8158082d22262b904fe30e References: jsc#PED-1716 dump_calculate_size() sums up all the sizes of the guest memory blocks. Since we already have a function that calculates the size of a single memory block (dump_get_memblock_size()) we can simply iterate over the blocks and use the function instead of calculating the size ourselves. Signed-off-by: Janosch Frank <fran...@linux.ibm.com> Reviewed-by: Marc-André Lureau <marcandre.lur...@redhat.com> Reviewed-by: Janis Schoetterl-Glausch <s...@linux.ibm.com> Message-Id: <20220811121111.9878-7-fran...@linux.ibm.com> Signed-off-by: Li Zhang <lizh...@suse.de> --- dump/dump.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/dump/dump.c b/dump/dump.c index b043337bc73217730f7b38d46484..d82cc46d7d8fc5562057a26d8f7b 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -1548,25 +1548,19 @@ bool qemu_system_dump_in_progress(void) return (qatomic_read(&state->status) == DUMP_STATUS_ACTIVE); } -/* calculate total size of memory to be dumped (taking filter into - * acoount.) */ +/* + * calculate total size of memory to be dumped (taking filter into + * account.) + */ static int64_t dump_calculate_size(DumpState *s) { GuestPhysBlock *block; - int64_t size = 0, total = 0, left = 0, right = 0; + int64_t total = 0; QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) { - if (dump_has_filter(s)) { - /* calculate the overlapped region. */ - left = MAX(s->filter_area_begin, block->target_start); - right = MIN(s->filter_area_begin + s->filter_area_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; + total += dump_filtered_memblock_size(block, + s->filter_area_begin, + s->filter_area_length); } return total; ++++++ dump-Rework-filter-area-variables.patch ++++++ From: Janosch Frank <fran...@linux.ibm.com> Date: Thu, 11 Aug 2022 12:10:58 +0000 Subject: dump: Rework filter area variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Git-commit: dddf725f70bfe7f5adb41fa31dbd06e767271bda References: jsc#PED-1716 While the DumpState begin and length variables directly mirror the API variable names they are not very descriptive. So let's add a "filter_area_" prefix and make has_filter a function checking length > 0. Signed-off-by: Janosch Frank <fran...@linux.ibm.com> Reviewed-by: Marc-André Lureau <marcandre.lur...@redhat.com> Message-Id: <20220811121111.9878-6-fran...@linux.ibm.com> Signed-off-by: Li Zhang <lizh...@suse.de> --- dump/dump.c | 53 +++++++++++++++++++++++++------------------ include/sysemu/dump.h | 13 ++++++++--- 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/dump/dump.c b/dump/dump.c index e204912a89560c3e7724b9359a1e..b043337bc73217730f7b38d46484 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -59,6 +59,11 @@ static inline bool dump_is_64bit(DumpState *s) return s->dump_info.d_class == ELFCLASS64; } +static inline bool dump_has_filter(DumpState *s) +{ + return s->filter_area_length > 0; +} + uint16_t cpu_to_dump16(DumpState *s, uint16_t val) { if (s->dump_info.d_endian == ELFDATA2LSB) { @@ -443,29 +448,30 @@ static void get_offset_range(hwaddr phys_addr, *p_offset = -1; *p_filesz = 0; - if (s->has_filter) { - if (phys_addr < s->begin || phys_addr >= s->begin + s->length) { + if (dump_has_filter(s)) { + if (phys_addr < s->filter_area_begin || + phys_addr >= s->filter_area_begin + s->filter_area_length) { return; } } QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) { - if (s->has_filter) { - if (block->target_start >= s->begin + s->length || - block->target_end <= s->begin) { + if (dump_has_filter(s)) { + if (block->target_start >= s->filter_area_begin + s->filter_area_length || + block->target_end <= s->filter_area_begin) { /* This block is out of the range */ continue; } - if (s->begin <= block->target_start) { + if (s->filter_area_begin <= block->target_start) { start = block->target_start; } else { - start = s->begin; + start = s->filter_area_begin; } size_in_block = block->target_end - start; - if (s->begin + s->length < block->target_end) { - size_in_block -= block->target_end - (s->begin + s->length); + if (s->filter_area_begin + s->filter_area_length < block->target_end) { + size_in_block -= block->target_end - (s->filter_area_begin + s->filter_area_length); } } else { start = block->target_start; @@ -638,12 +644,12 @@ static void dump_iterate(DumpState *s, Error **errp) int64_t memblock_size, memblock_start; QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) { - memblock_start = dump_filtered_memblock_start(block, s->begin, s->length); + memblock_start = dump_filtered_memblock_start(block, s->filter_area_begin, s->filter_area_length); if (memblock_start == -1) { continue; } - memblock_size = dump_filtered_memblock_size(block, s->begin, s->length); + memblock_size = dump_filtered_memblock_size(block, s->filter_area_begin, s->filter_area_length); /* Write the memory to file */ write_memory(s, block, memblock_start, memblock_size, errp); @@ -1504,14 +1510,14 @@ static int validate_start_block(DumpState *s) { GuestPhysBlock *block; - if (!s->has_filter) { + if (!dump_has_filter(s)) { return 0; } QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) { /* This block is out of the range */ - if (block->target_start >= s->begin + s->length || - block->target_end <= s->begin) { + if (block->target_start >= s->filter_area_begin + s->filter_area_length || + block->target_end <= s->filter_area_begin) { continue; } return 0; @@ -1550,10 +1556,10 @@ static int64_t dump_calculate_size(DumpState *s) int64_t size = 0, total = 0, left = 0, right = 0; QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) { - if (s->has_filter) { + if (dump_has_filter(s)) { /* calculate the overlapped region. */ - left = MAX(s->begin, block->target_start); - right = MIN(s->begin + s->length, block->target_end); + left = MAX(s->filter_area_begin, block->target_start); + right = MIN(s->filter_area_begin + s->filter_area_length, block->target_end); size = right - left; size = size > 0 ? size : 0; } else { @@ -1643,9 +1649,12 @@ static void dump_init(DumpState *s, int fd, bool has_format, } s->fd = fd; - s->has_filter = has_filter; - s->begin = begin; - s->length = length; + if (has_filter && !length) { + error_setg(errp, QERR_INVALID_PARAMETER, "length"); + goto cleanup; + } + s->filter_area_begin = begin; + s->filter_area_length = length; memory_mapping_list_init(&s->list); @@ -1778,8 +1787,8 @@ static void dump_init(DumpState *s, int fd, bool has_format, return; } - if (s->has_filter) { - memory_mapping_filter(&s->list, s->begin, s->length); + if (dump_has_filter(s)) { + memory_mapping_filter(&s->list, s->filter_area_begin, s->filter_area_length); } /* diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h index 7fce1d4af67c357bd4d80b936290..b62513d87d669fb7e7650edf574e 100644 --- a/include/sysemu/dump.h +++ b/include/sysemu/dump.h @@ -166,9 +166,16 @@ typedef struct DumpState { hwaddr memory_offset; int fd; - bool has_filter; - int64_t begin; - int64_t length; + /* + * Dump filter area variables + * + * A filtered dump only contains the guest memory designated by + * the start address and length variables defined below. + * + * If length is 0, no filtering is applied. + */ + int64_t filter_area_begin; /* Start address of partial guest memory area */ + int64_t filter_area_length; /* Length of partial guest memory area */ uint8_t *note_buf; /* buffer for notes */ size_t note_buf_offset; /* the writing place in note_buf */ ++++++ dump-Rework-get_start_block.patch ++++++ From: Janosch Frank <fran...@linux.ibm.com> Date: Thu, 11 Aug 2022 12:10:57 +0000 Subject: dump: Rework get_start_block MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Git-commit: 0c2994ac9009577b967529ce18e269da5b280351 References: jsc#PED-1716 get_start_block() returns the start address of the first memory block or -1. With the GuestPhysBlock iterator conversion we don't need to set the start address and can therefore remove that code and the "start" DumpState struct member. The only functionality left is the validation of the start block so it only makes sense to re-name the function to validate_start_block() Signed-off-by: Janosch Frank <fran...@linux.ibm.com> Reviewed-by: Marc-André Lureau <marcandre.lur...@redhat.com> Reviewed-by: Janis Schoetterl-Glausch <s...@linux.ibm.com> Message-Id: <20220811121111.9878-5-fran...@linux.ibm.com> Signed-off-by: Li Zhang <lizh...@suse.de> --- dump/dump.c | 20 ++++++-------------- include/sysemu/dump.h | 2 -- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/dump/dump.c b/dump/dump.c index 340de5a1e7a463573a14a0565682..e204912a89560c3e7724b9359a1e 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -1500,30 +1500,22 @@ static void create_kdump_vmcore(DumpState *s, Error **errp) } } -static ram_addr_t get_start_block(DumpState *s) +static int validate_start_block(DumpState *s) { GuestPhysBlock *block; if (!s->has_filter) { - s->next_block = QTAILQ_FIRST(&s->guest_phys_blocks.head); return 0; } QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) { + /* This block is out of the range */ if (block->target_start >= s->begin + s->length || block->target_end <= s->begin) { - /* This block is out of the range */ continue; } - - s->next_block = block; - if (s->begin > block->target_start) { - s->start = s->begin - block->target_start; - } else { - s->start = 0; - } - return s->start; - } + return 0; + } return -1; } @@ -1670,8 +1662,8 @@ static void dump_init(DumpState *s, int fd, bool has_format, goto cleanup; } - s->start = get_start_block(s); - if (s->start == -1) { + /* Is the filter filtering everything? */ + if (validate_start_block(s) == -1) { error_setg(errp, QERR_INVALID_PARAMETER, "begin"); goto cleanup; } diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h index ffc2ea1072f3d6dca792925a7fdc..7fce1d4af67c357bd4d80b936290 100644 --- a/include/sysemu/dump.h +++ b/include/sysemu/dump.h @@ -166,8 +166,6 @@ typedef struct DumpState { hwaddr memory_offset; int fd; - GuestPhysBlock *next_block; - ram_addr_t start; bool has_filter; int64_t begin; int64_t length; ++++++ dump-Split-elf-header-functions-into-pre.patch ++++++ From: Janosch Frank <fran...@linux.ibm.com> Date: Thu, 11 Aug 2022 12:11:00 +0000 Subject: dump: Split elf header functions into prepare and write MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Git-commit: 670e76998a61ca171200fcded3865b294a2d1243 References: jsc#PED-1716 Let's split the write from the modification of the elf header so we can consolidate the write of the data in one function. Signed-off-by: Janosch Frank <fran...@linux.ibm.com> Reviewed-by: Janis Schoetterl-Glausch <s...@linux.ibm.com> Reviewed-by: Marc-André Lureau <marcandre.lur...@redhat.com> Message-Id: <20220811121111.9878-8-fran...@linux.ibm.com> Signed-off-by: Li Zhang <lizh...@suse.de> --- dump/dump.c | 100 ++++++++++++++++++++++++++++------------------------ 1 file changed, 53 insertions(+), 47 deletions(-) diff --git a/dump/dump.c b/dump/dump.c index d82cc46d7d8fc5562057a26d8f7b..8a2a97a85eb151d06072fa38fec5 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -131,7 +131,7 @@ static int fd_write_vmcore(const void *buf, size_t size, void *opaque) return 0; } -static void write_elf64_header(DumpState *s, Error **errp) +static void prepare_elf64_header(DumpState *s, Elf64_Ehdr *elf_header) { /* * phnum in the elf header is 16 bit, if we have more segments we @@ -139,34 +139,27 @@ static void write_elf64_header(DumpState *s, Error **errp) * special section. */ uint16_t phnum = MIN(s->phdr_num, PN_XNUM); - Elf64_Ehdr elf_header; - int ret; - 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_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, s->phdr_offset); - elf_header.e_phentsize = cpu_to_dump16(s, sizeof(Elf64_Phdr)); - elf_header.e_phnum = cpu_to_dump16(s, phnum); + 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_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, s->phdr_offset); + elf_header->e_phentsize = cpu_to_dump16(s, sizeof(Elf64_Phdr)); + elf_header->e_phnum = cpu_to_dump16(s, phnum); if (s->shdr_num) { - elf_header.e_shoff = cpu_to_dump64(s, s->shdr_offset); - elf_header.e_shentsize = cpu_to_dump16(s, sizeof(Elf64_Shdr)); - elf_header.e_shnum = cpu_to_dump16(s, s->shdr_num); - } - - ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s); - if (ret < 0) { - error_setg_errno(errp, -ret, "dump: failed to write elf header"); + elf_header->e_shoff = cpu_to_dump64(s, s->shdr_offset); + elf_header->e_shentsize = cpu_to_dump16(s, sizeof(Elf64_Shdr)); + elf_header->e_shnum = cpu_to_dump16(s, s->shdr_num); } } -static void write_elf32_header(DumpState *s, Error **errp) +static void prepare_elf32_header(DumpState *s, Elf32_Ehdr *elf_header) { /* * phnum in the elf header is 16 bit, if we have more segments we @@ -174,28 +167,45 @@ static void write_elf32_header(DumpState *s, Error **errp) * special section. */ uint16_t phnum = MIN(s->phdr_num, PN_XNUM); - Elf32_Ehdr elf_header; - int ret; - 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] = s->dump_info.d_endian; - elf_header.e_ident[EI_VERSION] = EV_CURRENT; - 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, s->phdr_offset); - elf_header.e_phentsize = cpu_to_dump16(s, sizeof(Elf32_Phdr)); - elf_header.e_phnum = cpu_to_dump16(s, phnum); + 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] = s->dump_info.d_endian; + elf_header->e_ident[EI_VERSION] = EV_CURRENT; + 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, s->phdr_offset); + elf_header->e_phentsize = cpu_to_dump16(s, sizeof(Elf32_Phdr)); + elf_header->e_phnum = cpu_to_dump16(s, phnum); if (s->shdr_num) { - elf_header.e_shoff = cpu_to_dump32(s, s->shdr_offset); - elf_header.e_shentsize = cpu_to_dump16(s, sizeof(Elf32_Shdr)); - elf_header.e_shnum = cpu_to_dump16(s, s->shdr_num); + elf_header->e_shoff = cpu_to_dump32(s, s->shdr_offset); + elf_header->e_shentsize = cpu_to_dump16(s, sizeof(Elf32_Shdr)); + elf_header->e_shnum = cpu_to_dump16(s, s->shdr_num); } +} - ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s); +static void write_elf_header(DumpState *s, Error **errp) +{ + Elf32_Ehdr elf32_header; + Elf64_Ehdr elf64_header; + size_t header_size; + void *header_ptr; + int ret; + + if (dump_is_64bit(s)) { + prepare_elf64_header(s, &elf64_header); + header_size = sizeof(elf64_header); + header_ptr = &elf64_header; + } else { + prepare_elf32_header(s, &elf32_header); + header_size = sizeof(elf32_header); + header_ptr = &elf32_header; + } + + ret = fd_write_vmcore(header_ptr, header_size, s); if (ret < 0) { error_setg_errno(errp, -ret, "dump: failed to write elf header"); } @@ -564,11 +574,7 @@ static void dump_begin(DumpState *s, Error **errp) */ /* write elf header to vmcore */ - if (dump_is_64bit(s)) { - write_elf64_header(s, errp); - } else { - write_elf32_header(s, errp); - } + write_elf_header(s, errp); if (*errp) { return; } ++++++ dump-Use-a-buffer-for-ELF-section-data-a.patch ++++++ From: Janosch Frank <fran...@linux.ibm.com> Date: Mon, 17 Oct 2022 08:38:13 +0000 Subject: dump: Use a buffer for ELF section data and headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Git-commit: e41ed29bcee5cb16715317bcf290f6b5c196eb0a References: jsc#PED-1716 Currently we're writing the NULL section header if we overflow the physical header number in the ELF header. But in the future we'll add custom section headers AND section data. To facilitate this we need to rearange section handling a bit. As with the other ELF headers we split the code into a prepare and a write step. Signed-off-by: Janosch Frank <fran...@linux.ibm.com> Reviewed-by: Marc-André Lureau <marcandre.lur...@redhat.com> Message-Id: <20221017083822.43118-2-fran...@linux.ibm.com> Signed-off-by: Li Zhang <lizh...@suse.de> --- dump/dump.c | 75 +++++++++++++++++++++++++++++-------------- include/sysemu/dump.h | 2 ++ 2 files changed, 53 insertions(+), 24 deletions(-) diff --git a/dump/dump.c b/dump/dump.c index a905316fe52ba59bfb66c94348f6..9d25a33ccd521c7c97d2fb97a9c6 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -380,31 +380,60 @@ static void write_elf_phdr_note(DumpState *s, Error **errp) } } -static void write_elf_section(DumpState *s, int type, Error **errp) +static void prepare_elf_section_hdr_zero(DumpState *s) { - Elf32_Shdr shdr32; - Elf64_Shdr shdr64; - int shdr_size; - void *shdr; - int ret; + if (dump_is_64bit(s)) { + Elf64_Shdr *shdr64 = s->elf_section_hdrs; - if (type == 0) { - shdr_size = sizeof(Elf32_Shdr); - memset(&shdr32, 0, shdr_size); - shdr32.sh_info = cpu_to_dump32(s, s->phdr_num); - shdr = &shdr32; + shdr64->sh_info = cpu_to_dump32(s, s->phdr_num); } else { - shdr_size = sizeof(Elf64_Shdr); - memset(&shdr64, 0, shdr_size); - shdr64.sh_info = cpu_to_dump32(s, s->phdr_num); - shdr = &shdr64; + Elf32_Shdr *shdr32 = s->elf_section_hdrs; + + shdr32->sh_info = cpu_to_dump32(s, s->phdr_num); + } +} + +static void prepare_elf_section_hdrs(DumpState *s) +{ + size_t len, sizeof_shdr; + + /* + * Section ordering: + * - HDR zero + */ + sizeof_shdr = dump_is_64bit(s) ? sizeof(Elf64_Shdr) : sizeof(Elf32_Shdr); + len = sizeof_shdr * s->shdr_num; + s->elf_section_hdrs = g_malloc0(len); + + /* + * The first section header is ALWAYS a special initial section + * header. + * + * The header should be 0 with one exception being that if + * phdr_num is PN_XNUM then the sh_info field contains the real + * number of segment entries. + * + * As we zero allocate the buffer we will only need to modify + * sh_info for the PN_XNUM case. + */ + if (s->phdr_num >= PN_XNUM) { + prepare_elf_section_hdr_zero(s); } +} - ret = fd_write_vmcore(shdr, shdr_size, s); +static void write_elf_section_headers(DumpState *s, Error **errp) +{ + size_t sizeof_shdr = dump_is_64bit(s) ? sizeof(Elf64_Shdr) : sizeof(Elf32_Shdr); + int ret; + + prepare_elf_section_hdrs(s); + + ret = fd_write_vmcore(s->elf_section_hdrs, s->shdr_num * sizeof_shdr, s); if (ret < 0) { - error_setg_errno(errp, -ret, - "dump: failed to write section header table"); + error_setg_errno(errp, -ret, "dump: failed to write section headers"); } + + g_free(s->elf_section_hdrs); } static void write_data(DumpState *s, void *buf, int length, Error **errp) @@ -591,12 +620,10 @@ static void dump_begin(DumpState *s, Error **errp) return; } - /* write section to vmcore */ - if (s->shdr_num) { - write_elf_section(s, 1, errp); - if (*errp) { - return; - } + /* write section headers to vmcore */ + write_elf_section_headers(s, errp); + if (*errp) { + return; } /* write notes to vmcore */ diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h index b62513d87d669fb7e7650edf574e..9995f65dc8b18420292beb48ee82 100644 --- a/include/sysemu/dump.h +++ b/include/sysemu/dump.h @@ -177,6 +177,8 @@ typedef struct DumpState { int64_t filter_area_begin; /* Start address of partial guest memory area */ int64_t filter_area_length; /* Length of partial guest memory area */ + void *elf_section_hdrs; /* Pointer to section header buffer */ + 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 */ ++++++ dump-Write-ELF-section-headers-right-aft.patch ++++++ From: Janosch Frank <fran...@linux.ibm.com> Date: Mon, 17 Oct 2022 08:38:14 +0000 Subject: dump: Write ELF section headers right after ELF header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Git-commit: cb415fd61e48d52f81dcf38956e3f913651cff1c References: jsc#PED-1716 Let's start bundling the writes of the headers and of the data so we have a clear ordering between them. Since the ELF header uses offsets to the headers we can freely order them. Signed-off-by: Janosch Frank <fran...@linux.ibm.com> Reviewed-by: Marc-André Lureau <marcandre.lur...@redhat.com> Message-Id: <20221017083822.43118-3-fran...@linux.ibm.com> Signed-off-by: Li Zhang <lizh...@suse.de> --- dump/dump.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/dump/dump.c b/dump/dump.c index 9d25a33ccd521c7c97d2fb97a9c6..4a38daf35cf3c4d5dd7c2216677d 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -583,6 +583,8 @@ static void dump_begin(DumpState *s, Error **errp) * -------------- * | elf header | * -------------- + * | sctn_hdr | + * -------------- * | PT_NOTE | * -------------- * | PT_LOAD | @@ -591,8 +593,6 @@ static void dump_begin(DumpState *s, Error **errp) * -------------- * | PT_LOAD | * -------------- - * | sec_hdr | - * -------------- * | elf note | * -------------- * | memory | @@ -608,20 +608,20 @@ static void dump_begin(DumpState *s, Error **errp) return; } - /* write PT_NOTE to vmcore */ - write_elf_phdr_note(s, errp); + /* write section headers to vmcore */ + write_elf_section_headers(s, errp); if (*errp) { return; } - /* write all PT_LOADs to vmcore */ - write_elf_phdr_loads(s, errp); + /* write PT_NOTE to vmcore */ + write_elf_phdr_note(s, errp); if (*errp) { return; } - /* write section headers to vmcore */ - write_elf_section_headers(s, errp); + /* write all PT_LOADs to vmcore */ + write_elf_phdr_loads(s, errp); if (*errp) { return; } @@ -1840,16 +1840,13 @@ static void dump_init(DumpState *s, int fd, bool has_format, } if (dump_is_64bit(s)) { - s->phdr_offset = sizeof(Elf64_Ehdr); - s->shdr_offset = s->phdr_offset + sizeof(Elf64_Phdr) * s->phdr_num; - s->note_offset = s->shdr_offset + sizeof(Elf64_Shdr) * s->shdr_num; - s->memory_offset = s->note_offset + s->note_size; + s->shdr_offset = sizeof(Elf64_Ehdr); + s->phdr_offset = s->shdr_offset + sizeof(Elf64_Shdr) * s->shdr_num; + s->note_offset = s->phdr_offset + sizeof(Elf64_Phdr) * s->phdr_num; } else { - - s->phdr_offset = sizeof(Elf32_Ehdr); - s->shdr_offset = s->phdr_offset + sizeof(Elf32_Phdr) * s->phdr_num; - s->note_offset = s->shdr_offset + sizeof(Elf32_Shdr) * s->shdr_num; - s->memory_offset = s->note_offset + s->note_size; + s->shdr_offset = sizeof(Elf32_Ehdr); + s->phdr_offset = s->shdr_offset + sizeof(Elf32_Shdr) * s->shdr_num; + s->note_offset = s->phdr_offset + sizeof(Elf32_Phdr) * s->phdr_num; } return; ++++++ include-elf.h-add-s390x-note-types.patch ++++++ From: Janosch Frank <fran...@linux.ibm.com> Date: Mon, 17 Oct 2022 08:38:20 +0000 Subject: include/elf.h: add s390x note types Git-commit: 5433669c7a1884cc0394c360148965edf7519884 References: jsc#PED-1716 Adding two s390x note types Signed-off-by: Janosch Frank <fran...@linux.ibm.com> Reviewed-by: Thomas Huth <th...@redhat.com> Message-Id: <20221017083822.43118-9-fran...@linux.ibm.com> Signed-off-by: Li Zhang <lizh...@suse.de> --- include/elf.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/elf.h b/include/elf.h index 3a4bcb646a18224c34e537416784..94fdcfd8dc942d61eb71b41cc96a 100644 --- a/include/elf.h +++ b/include/elf.h @@ -1649,6 +1649,8 @@ typedef struct elf64_shdr { #define NT_TASKSTRUCT 4 #define NT_AUXV 6 #define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ +#define NT_S390_PV_CPU_DATA 0x30e /* s390 protvirt cpu dump data */ +#define NT_S390_RI_CB 0x30d /* s390 runtime instrumentation */ #define NT_S390_GS_CB 0x30b /* s390 guarded storage registers */ #define NT_S390_VXRS_HIGH 0x30a /* s390 vector registers 16-31 */ #define NT_S390_VXRS_LOW 0x309 /* s390 vector registers 0-15 (lower half) */ ++++++ s390x-Add-KVM-PV-dump-interface.patch ++++++ From: Janosch Frank <fran...@linux.ibm.com> Date: Mon, 17 Oct 2022 08:38:21 +0000 Subject: s390x: Add KVM PV dump interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Git-commit: 753ca06f4706cd6e57750a606afb08c5c5299643 References: jsc#PED-1716 Let's add a few bits of code which hide the new KVM PV dump API from us via new functions. Signed-off-by: Janosch Frank <fran...@linux.ibm.com> Reviewed-by: Janis Schoetterl-Glausch <s...@linux.ibm.com> Reviewed-by: Steffen Eiden <sei...@linux.ibm.com> [ Marc-André: fix up for compilation issue ] Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com> Message-Id: <20221017083822.43118-10-fran...@linux.ibm.com> Signed-off-by: Li Zhang <lizh...@suse.de> --- hw/s390x/pv.c | 51 +++++++++++++++++++++++++++++++++++++++++++ include/hw/s390x/pv.h | 9 ++++++++ 2 files changed, 60 insertions(+) diff --git a/hw/s390x/pv.c b/hw/s390x/pv.c index 4c012f2eebd596ec86397350c9b7..728ba24547627994ac6059051f75 100644 --- a/hw/s390x/pv.c +++ b/hw/s390x/pv.c @@ -175,6 +175,57 @@ bool kvm_s390_pv_info_basic_valid(void) return info_valid; } +static int s390_pv_dump_cmd(uint64_t subcmd, uint64_t uaddr, uint64_t gaddr, + uint64_t len) +{ + struct kvm_s390_pv_dmp dmp = { + .subcmd = subcmd, + .buff_addr = uaddr, + .buff_len = len, + .gaddr = gaddr, + }; + int ret; + + ret = s390_pv_cmd(KVM_PV_DUMP, (void *)&dmp); + if (ret) { + error_report("KVM DUMP command %ld failed", subcmd); + } + return ret; +} + +int kvm_s390_dump_cpu(S390CPU *cpu, void *buff) +{ + struct kvm_s390_pv_dmp dmp = { + .subcmd = KVM_PV_DUMP_CPU, + .buff_addr = (uint64_t)buff, + .gaddr = 0, + .buff_len = info_dump.dump_cpu_buffer_len, + }; + struct kvm_pv_cmd pv = { + .cmd = KVM_PV_DUMP, + .data = (uint64_t)&dmp, + }; + + return kvm_vcpu_ioctl(CPU(cpu), KVM_S390_PV_CPU_COMMAND, &pv); +} + +int kvm_s390_dump_init(void) +{ + return s390_pv_dump_cmd(KVM_PV_DUMP_INIT, 0, 0, 0); +} + +int kvm_s390_dump_mem_state(uint64_t gaddr, size_t len, void *dest) +{ + return s390_pv_dump_cmd(KVM_PV_DUMP_CONFIG_STOR_STATE, (uint64_t)dest, + gaddr, len); +} + +int kvm_s390_dump_completion_data(void *buff) +{ + return s390_pv_dump_cmd(KVM_PV_DUMP_COMPLETE, (uint64_t)buff, 0, + info_dump.dump_config_finalize_len); +} + #define TYPE_S390_PV_GUEST "s390-pv-guest" OBJECT_DECLARE_SIMPLE_TYPE(S390PVGuest, S390_PV_GUEST) diff --git a/include/hw/s390x/pv.h b/include/hw/s390x/pv.h index e5ea0eca16c946e30ecfb0aa1c28..9360aa10914891b1a38a3fe079b9 100644 --- a/include/hw/s390x/pv.h +++ b/include/hw/s390x/pv.h @@ -51,6 +51,10 @@ uint64_t kvm_s390_pv_dmp_get_size_cpu(void); uint64_t kvm_s390_pv_dmp_get_size_mem_state(void); uint64_t kvm_s390_pv_dmp_get_size_completion_data(void); bool kvm_s390_pv_info_basic_valid(void); +int kvm_s390_dump_init(void); +int kvm_s390_dump_cpu(S390CPU *cpu, void *buff); +int kvm_s390_dump_mem_state(uint64_t addr, size_t len, void *dest); +int kvm_s390_dump_completion_data(void *buff); #else /* CONFIG_KVM */ static inline bool s390_is_pv(void) { return false; } static inline int s390_pv_query_info(void) { return 0; } @@ -66,6 +70,11 @@ static inline uint64_t kvm_s390_pv_dmp_get_size_cpu(void) { return 0; } static inline uint64_t kvm_s390_pv_dmp_get_size_mem_state(void) { return 0; } static inline uint64_t kvm_s390_pv_dmp_get_size_completion_data(void) { return 0; } static inline bool kvm_s390_pv_info_basic_valid(void) { return false; } +static inline int kvm_s390_dump_init(void) { return 0; } +static inline int kvm_s390_dump_cpu(S390CPU *cpu, void *buff) { return 0; } +static inline int kvm_s390_dump_mem_state(uint64_t addr, size_t len, + void *dest) { return 0; } +static inline int kvm_s390_dump_completion_data(void *buff) { return 0; } #endif /* CONFIG_KVM */ int s390_pv_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); ++++++ s390x-Add-protected-dump-cap.patch ++++++ From: Janosch Frank <fran...@linux.ibm.com> Date: Mon, 17 Oct 2022 08:38:18 +0000 Subject: s390x: Add protected dump cap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Git-commit: ad3b2e693daac6ed92db7361236028851d37c77c References: jsc#PED-1716 Add a protected dump capability for later feature checking. Signed-off-by: Janosch Frank <fran...@linux.ibm.com> Reviewed-by: Steffen Eiden <sei...@linux.ibm.com> Reviewed-by: Thomas Huth <th...@redhat.com> Reviewed-by: Janis Schoetterl-Glausch <s...@linux.ibm.com> Message-Id: <20221017083822.43118-7-fran...@linux.ibm.com> [ Marc-André - Add missing stubs when !kvm ] Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com> Signed-off-by: Li Zhang <lizh...@suse.de> --- target/s390x/kvm/kvm.c | 7 +++++++ target/s390x/kvm/kvm_s390x.h | 1 + target/s390x/kvm/meson.build | 2 ++ target/s390x/kvm/stubs.c | 12 ++++++++++++ 4 files changed, 22 insertions(+) diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c index 6a8dbadf7ed0f8a15a8c22e64a43..2ca0d46453a5bc12a51a7514f589 100644 --- a/target/s390x/kvm/kvm.c +++ b/target/s390x/kvm/kvm.c @@ -158,6 +158,7 @@ static int cap_hpage_1m; static int cap_vcpu_resets; static int cap_protected; static int cap_zpci_op; +static int cap_protected_dump; static bool mem_op_storage_key_support; @@ -364,6 +365,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) cap_vcpu_resets = kvm_check_extension(s, KVM_CAP_S390_VCPU_RESETS); cap_protected = kvm_check_extension(s, KVM_CAP_S390_PROTECTED); cap_zpci_op = kvm_check_extension(s, KVM_CAP_S390_ZPCI_OP); + cap_protected_dump = kvm_check_extension(s, KVM_CAP_S390_PROTECTED_DUMP); kvm_vm_enable_cap(s, KVM_CAP_S390_USER_SIGP, 0); kvm_vm_enable_cap(s, KVM_CAP_S390_VECTOR_REGISTERS, 0); @@ -2045,6 +2047,11 @@ int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch, return kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &kick); } +int kvm_s390_get_protected_dump(void) +{ + return cap_protected_dump; +} + int kvm_s390_get_ri(void) { return cap_ri; diff --git a/target/s390x/kvm/kvm_s390x.h b/target/s390x/kvm/kvm_s390x.h index aaae8570de5830512932b470eeaf..f9785564d0ba7e49eb29f289d207 100644 --- a/target/s390x/kvm/kvm_s390x.h +++ b/target/s390x/kvm/kvm_s390x.h @@ -26,6 +26,7 @@ int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state); void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu); int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu); int kvm_s390_get_hpage_1m(void); +int kvm_s390_get_protected_dump(void); int kvm_s390_get_ri(void); int kvm_s390_get_zpci_op(void); int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_clock); diff --git a/target/s390x/kvm/meson.build b/target/s390x/kvm/meson.build index d1356356b1f62103e94507c8e6ff..aef52b6686b36c235b4fa659142d 100644 --- a/target/s390x/kvm/meson.build +++ b/target/s390x/kvm/meson.build @@ -1,6 +1,8 @@ s390x_ss.add(when: 'CONFIG_KVM', if_true: files( 'kvm.c' +), if_false: files( + 'stubs.c' )) # Newer kernels on s390 check for an S390_PGSTE program header and diff --git a/target/s390x/kvm/stubs.c b/target/s390x/kvm/stubs.c new file mode 100644 index 0000000000000000000000000000000000000000..5fd63b9a7e32fc4bd54cc24056afeda6f0a7b542 --- /dev/null +++ b/target/s390x/kvm/stubs.c @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" + +#include "kvm_s390x.h" + +int kvm_s390_get_protected_dump(void) +{ + return false; +} ++++++ s390x-Introduce-PV-query-interface.patch ++++++ From: Janosch Frank <fran...@linux.ibm.com> Date: Mon, 17 Oct 2022 08:38:19 +0000 Subject: s390x: Introduce PV query interface Git-commit: 03d83ecfae46bf5e0074cb5808043b30df34064b References: jsc#PED-1716 Introduce an interface over which we can get information about UV data. Signed-off-by: Janosch Frank <fran...@linux.ibm.com> Reviewed-by: Steffen Eiden <sei...@linux.ibm.com> Reviewed-by: Janis Schoetterl-Glausch <s...@linux.ibm.com> Acked-by: Thomas Huth <th...@redhat.com> Message-Id: <20221017083822.43118-8-fran...@linux.ibm.com> Signed-off-by: Li Zhang <lizh...@suse.de> --- hw/s390x/pv.c | 61 ++++++++++++++++++++++++++++++++++++++ hw/s390x/s390-virtio-ccw.c | 6 ++++ include/hw/s390x/pv.h | 10 +++++++ 3 files changed, 77 insertions(+) diff --git a/hw/s390x/pv.c b/hw/s390x/pv.c index 401b63d6cb659c412f4f34d2d05d..4c012f2eebd596ec86397350c9b7 100644 --- a/hw/s390x/pv.c +++ b/hw/s390x/pv.c @@ -20,6 +20,11 @@ #include "exec/confidential-guest-support.h" #include "hw/s390x/ipl.h" #include "hw/s390x/pv.h" +#include "target/s390x/kvm/kvm_s390x.h" + +static bool info_valid; +static struct kvm_s390_pv_info_vm info_vm; +static struct kvm_s390_pv_info_dump info_dump; static int __s390_pv_cmd(uint32_t cmd, const char *cmdname, void *data) { @@ -56,6 +61,42 @@ static int __s390_pv_cmd(uint32_t cmd, const char *cmdname, void *data) } \ } +int s390_pv_query_info(void) +{ + struct kvm_s390_pv_info info = { + .header.id = KVM_PV_INFO_VM, + .header.len_max = sizeof(info.header) + sizeof(info.vm), + }; + int rc; + + /* Info API's first user is dump so they are bundled */ + if (!kvm_s390_get_protected_dump()) { + return 0; + } + + rc = s390_pv_cmd(KVM_PV_INFO, &info); + if (rc) { + error_report("KVM PV INFO cmd %x failed: %s", + info.header.id, strerror(-rc)); + return rc; + } + memcpy(&info_vm, &info.vm, sizeof(info.vm)); + + info.header.id = KVM_PV_INFO_DUMP; + info.header.len_max = sizeof(info.header) + sizeof(info.dump); + rc = s390_pv_cmd(KVM_PV_INFO, &info); + if (rc) { + error_report("KVM PV INFO cmd %x failed: %s", + info.header.id, strerror(-rc)); + return rc; + } + + memcpy(&info_dump, &info.dump, sizeof(info.dump)); + info_valid = true; + + return rc; +} + int s390_pv_vm_enable(void) { return s390_pv_cmd(KVM_PV_ENABLE, NULL); @@ -114,6 +155,26 @@ void s390_pv_inject_reset_error(CPUState *cs) env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV; } +uint64_t kvm_s390_pv_dmp_get_size_cpu(void) +{ + return info_dump.dump_cpu_buffer_len; +} + +uint64_t kvm_s390_pv_dmp_get_size_completion_data(void) +{ + return info_dump.dump_config_finalize_len; +} + +uint64_t kvm_s390_pv_dmp_get_size_mem_state(void) +{ + return info_dump.dump_config_mem_buffer_per_1m; +} + +bool kvm_s390_pv_info_basic_valid(void) +{ + return info_valid; +} + #define TYPE_S390_PV_GUEST "s390-pv-guest" OBJECT_DECLARE_SIMPLE_TYPE(S390PVGuest, S390_PV_GUEST) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index cc3097bfee8073bd2b08d58a50d9..7982f7973fce7c411efc3095e9be 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -366,6 +366,12 @@ static int s390_machine_protect(S390CcwMachineState *ms) ms->pv = true; + /* Will return 0 if API is not available since it's not vital */ + rc = s390_pv_query_info(); + if (rc) { + goto out_err; + } + /* Set SE header and unpack */ rc = s390_ipl_prepare_pv_header(); if (rc) { diff --git a/include/hw/s390x/pv.h b/include/hw/s390x/pv.h index 1f1f545bfc20231604b119783ef6..e5ea0eca16c946e30ecfb0aa1c28 100644 --- a/include/hw/s390x/pv.h +++ b/include/hw/s390x/pv.h @@ -38,6 +38,7 @@ static inline bool s390_is_pv(void) return ccw->pv; } +int s390_pv_query_info(void); int s390_pv_vm_enable(void); void s390_pv_vm_disable(void); int s390_pv_set_sec_parms(uint64_t origin, uint64_t length); @@ -46,8 +47,13 @@ void s390_pv_prep_reset(void); int s390_pv_verify(void); void s390_pv_unshare(void); void s390_pv_inject_reset_error(CPUState *cs); +uint64_t kvm_s390_pv_dmp_get_size_cpu(void); +uint64_t kvm_s390_pv_dmp_get_size_mem_state(void); +uint64_t kvm_s390_pv_dmp_get_size_completion_data(void); +bool kvm_s390_pv_info_basic_valid(void); #else /* CONFIG_KVM */ static inline bool s390_is_pv(void) { return false; } +static inline int s390_pv_query_info(void) { return 0; } static inline int s390_pv_vm_enable(void) { return 0; } static inline void s390_pv_vm_disable(void) {} static inline int s390_pv_set_sec_parms(uint64_t origin, uint64_t length) { return 0; } @@ -56,6 +62,10 @@ static inline void s390_pv_prep_reset(void) {} static inline int s390_pv_verify(void) { return 0; } static inline void s390_pv_unshare(void) {} static inline void s390_pv_inject_reset_error(CPUState *cs) {}; +static inline uint64_t kvm_s390_pv_dmp_get_size_cpu(void) { return 0; } +static inline uint64_t kvm_s390_pv_dmp_get_size_mem_state(void) { return 0; } +static inline uint64_t kvm_s390_pv_dmp_get_size_completion_data(void) { return 0; } +static inline bool kvm_s390_pv_info_basic_valid(void) { return false; } #endif /* CONFIG_KVM */ int s390_pv_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); ++++++ s390x-pv-Add-dump-support.patch ++++++ From: Janosch Frank <fran...@linux.ibm.com> Date: Mon, 17 Oct 2022 08:38:22 +0000 Subject: s390x: pv: Add dump support Git-commit: 113d8f4e95cf0450bea421263de6ec016c779ad0 References: jsc#PED-1716 Sometimes dumping a guest from the outside is the only way to get the data that is needed. This can be the case if a dumping mechanism like KDUMP hasn't been configured or data needs to be fetched at a specific point. Dumping a protected guest from the outside without help from fw/hw doesn't yield sufficient data to be useful. Hence we now introduce PV dump support. The PV dump support works by integrating the firmware into the dump process. New Ultravisor calls are used to initiate the dump process, dump cpu data, dump memory state and lastly complete the dump process. The UV calls are exposed by KVM via the new KVM_PV_DUMP command and its subcommands. The guest's data is fully encrypted and can only be decrypted by the entity that owns the customer communication key for the dumped guest. Also dumping needs to be allowed via a flag in the SE header. On the QEMU side of things we store the PV dump data in the newly introduced architecture ELF sections (storage state and completion data) and the cpu notes (for cpu dump data). Users can use the zgetdump tool to convert the encrypted QEMU dump to an unencrypted one. Signed-off-by: Janosch Frank <fran...@linux.ibm.com> Reviewed-by: Steffen Eiden <sei...@linux.ibm.com> Message-Id: <20221017083822.43118-11-fran...@linux.ibm.com> Signed-off-by: Li Zhang <lizh...@suse.de> --- dump/dump.c | 12 +- include/sysemu/dump.h | 5 + target/s390x/arch_dump.c | 262 +++++++++++++++++++++++++++++++++++---- 3 files changed, 246 insertions(+), 33 deletions(-) diff --git a/dump/dump.c b/dump/dump.c index eb547e3e59e90681cddfc8c4080d..24eca74b79b903662aaccfdb57ba 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -708,9 +708,9 @@ static void dump_begin(DumpState *s, Error **errp) write_elf_notes(s, errp); } -static int64_t dump_filtered_memblock_size(GuestPhysBlock *block, - int64_t filter_area_start, - int64_t filter_area_length) +int64_t dump_filtered_memblock_size(GuestPhysBlock *block, + int64_t filter_area_start, + int64_t filter_area_length) { int64_t size, left, right; @@ -728,9 +728,9 @@ static int64_t dump_filtered_memblock_size(GuestPhysBlock *block, return size; } -static int64_t dump_filtered_memblock_start(GuestPhysBlock *block, - int64_t filter_area_start, - int64_t filter_area_length) +int64_t dump_filtered_memblock_start(GuestPhysBlock *block, + int64_t filter_area_start, + int64_t filter_area_length) { if (filter_area_length) { /* return -1 if the block is not within filter area */ diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h index 38ccac7190a253b6c0da3395ac16..4ffed0b65982ea393ad3dac7bbb5 100644 --- a/include/sysemu/dump.h +++ b/include/sysemu/dump.h @@ -215,4 +215,9 @@ typedef struct 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); + +int64_t dump_filtered_memblock_size(GuestPhysBlock *block, int64_t filter_area_start, + int64_t filter_area_length); +int64_t dump_filtered_memblock_start(GuestPhysBlock *block, int64_t filter_area_start, + int64_t filter_area_length); #endif diff --git a/target/s390x/arch_dump.c b/target/s390x/arch_dump.c index f60a14920d45e6b9c61bcd06147a..a2329141e8ad89c5de90426f7863 100644 --- a/target/s390x/arch_dump.c +++ b/target/s390x/arch_dump.c @@ -12,11 +12,13 @@ */ #include "qemu/osdep.h" +#include "qemu/units.h" #include "cpu.h" #include "s390x-internal.h" #include "elf.h" #include "sysemu/dump.h" - +#include "hw/s390x/pv.h" +#include "kvm/kvm_s390x.h" struct S390xUserRegsStruct { uint64_t psw[2]; @@ -76,9 +78,16 @@ typedef struct noteStruct { uint64_t todcmp; uint32_t todpreg; uint64_t ctrs[16]; + uint8_t dynamic[1]; /* + * Would be a flexible array member, if + * that was legal inside a union. Real + * size comes from PV info interface. + */ } contents; } QEMU_PACKED Note; +static bool pv_dump_initialized; + static void s390x_write_elf64_prstatus(Note *note, S390CPU *cpu, int id) { int i; @@ -177,28 +186,39 @@ static void s390x_write_elf64_prefix(Note *note, S390CPU *cpu, int id) note->contents.prefix = cpu_to_be32((uint32_t)(cpu->env.psa)); } +static void s390x_write_elf64_pv(Note *note, S390CPU *cpu, int id) +{ + note->hdr.n_type = cpu_to_be32(NT_S390_PV_CPU_DATA); + if (!pv_dump_initialized) { + return; + } + kvm_s390_dump_cpu(cpu, ¬e->contents.dynamic); +} typedef struct NoteFuncDescStruct { int contents_size; + uint64_t (*note_size_func)(void); /* NULL for non-dynamic sized contents */ void (*note_contents_func)(Note *note, S390CPU *cpu, int id); + bool pvonly; } NoteFuncDesc; static const NoteFuncDesc note_core[] = { - {sizeof_field(Note, contents.prstatus), s390x_write_elf64_prstatus}, - {sizeof_field(Note, contents.fpregset), s390x_write_elf64_fpregset}, - { 0, NULL} + {sizeof_field(Note, contents.prstatus), NULL, s390x_write_elf64_prstatus, false}, + {sizeof_field(Note, contents.fpregset), NULL, s390x_write_elf64_fpregset, false}, + { 0, NULL, NULL, false} }; static const NoteFuncDesc note_linux[] = { - {sizeof_field(Note, contents.prefix), s390x_write_elf64_prefix}, - {sizeof_field(Note, contents.ctrs), s390x_write_elf64_ctrs}, - {sizeof_field(Note, contents.timer), s390x_write_elf64_timer}, - {sizeof_field(Note, contents.todcmp), s390x_write_elf64_todcmp}, - {sizeof_field(Note, contents.todpreg), s390x_write_elf64_todpreg}, - {sizeof_field(Note, contents.vregslo), s390x_write_elf64_vregslo}, - {sizeof_field(Note, contents.vregshi), s390x_write_elf64_vregshi}, - {sizeof_field(Note, contents.gscb), s390x_write_elf64_gscb}, - { 0, NULL} + {sizeof_field(Note, contents.prefix), NULL, s390x_write_elf64_prefix, false}, + {sizeof_field(Note, contents.ctrs), NULL, s390x_write_elf64_ctrs, false}, + {sizeof_field(Note, contents.timer), NULL, s390x_write_elf64_timer, false}, + {sizeof_field(Note, contents.todcmp), NULL, s390x_write_elf64_todcmp, false}, + {sizeof_field(Note, contents.todpreg), NULL, s390x_write_elf64_todpreg, false}, + {sizeof_field(Note, contents.vregslo), NULL, s390x_write_elf64_vregslo, false}, + {sizeof_field(Note, contents.vregshi), NULL, s390x_write_elf64_vregshi, false}, + {sizeof_field(Note, contents.gscb), NULL, s390x_write_elf64_gscb, false}, + {0, kvm_s390_pv_dmp_get_size_cpu, s390x_write_elf64_pv, true}, + { 0, NULL, NULL, false} }; static int s390x_write_elf64_notes(const char *note_name, @@ -207,22 +227,41 @@ static int s390x_write_elf64_notes(const char *note_name, DumpState *s, const NoteFuncDesc *funcs) { - Note note; + Note note, *notep; const NoteFuncDesc *nf; - int note_size; + int note_size, content_size; int ret = -1; assert(strlen(note_name) < sizeof(note.name)); for (nf = funcs; nf->note_contents_func; nf++) { - memset(¬e, 0, sizeof(note)); - note.hdr.n_namesz = cpu_to_be32(strlen(note_name) + 1); - note.hdr.n_descsz = cpu_to_be32(nf->contents_size); - g_strlcpy(note.name, note_name, sizeof(note.name)); - (*nf->note_contents_func)(¬e, cpu, id); + notep = ¬e; + if (nf->pvonly && !s390_is_pv()) { + continue; + } + + content_size = nf->note_size_func ? nf->note_size_func() : nf->contents_size; + note_size = sizeof(note) - sizeof(notep->contents) + content_size; + + /* Notes with dynamic sizes need to allocate a note */ + if (nf->note_size_func) { + notep = g_malloc(note_size); + } + + memset(notep, 0, sizeof(note)); - note_size = sizeof(note) - sizeof(note.contents) + nf->contents_size; - ret = f(¬e, note_size, s); + /* Setup note header data */ + notep->hdr.n_descsz = cpu_to_be32(content_size); + notep->hdr.n_namesz = cpu_to_be32(strlen(note_name) + 1); + g_strlcpy(notep->name, note_name, sizeof(notep->name)); + + /* Get contents and write them out */ + (*nf->note_contents_func)(notep, cpu, id); + ret = f(notep, note_size, s); + + if (nf->note_size_func) { + g_free(notep); + } if (ret < 0) { return -1; @@ -247,13 +286,179 @@ int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, return s390x_write_elf64_notes("LINUX", f, cpu, cpuid, s, note_linux); } +/* PV dump section size functions */ +static uint64_t get_mem_state_size_from_len(uint64_t len) +{ + return (len / (MiB)) * kvm_s390_pv_dmp_get_size_mem_state(); +} + +static uint64_t get_size_mem_state(DumpState *s) +{ + return get_mem_state_size_from_len(s->total_size); +} + +static uint64_t get_size_completion_data(DumpState *s) +{ + return kvm_s390_pv_dmp_get_size_completion_data(); +} + +/* PV dump section data functions*/ +static int get_data_completion(DumpState *s, uint8_t *buff) +{ + int rc; + + if (!pv_dump_initialized) { + return 0; + } + rc = kvm_s390_dump_completion_data(buff); + if (!rc) { + pv_dump_initialized = false; + } + return rc; +} + +static int get_mem_state(DumpState *s, uint8_t *buff) +{ + int64_t memblock_size, memblock_start; + GuestPhysBlock *block; + uint64_t off; + int rc; + + QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) { + memblock_start = dump_filtered_memblock_start(block, s->filter_area_begin, + s->filter_area_length); + if (memblock_start == -1) { + continue; + } + + memblock_size = dump_filtered_memblock_size(block, s->filter_area_begin, + s->filter_area_length); + + off = get_mem_state_size_from_len(block->target_start); + + rc = kvm_s390_dump_mem_state(block->target_start, + get_mem_state_size_from_len(memblock_size), + buff + off); + if (rc) { + return rc; + } + } + + return 0; +} + +static struct sections { + uint64_t (*sections_size_func)(DumpState *s); + int (*sections_contents_func)(DumpState *s, uint8_t *buff); + char sctn_str[12]; +} sections[] = { + { get_size_mem_state, get_mem_state, "pv_mem_meta"}, + { get_size_completion_data, get_data_completion, "pv_compl"}, + {NULL , NULL, ""} +}; + +static uint64_t arch_sections_write_hdr(DumpState *s, uint8_t *buff) +{ + Elf64_Shdr *shdr = (void *)buff; + struct sections *sctn = sections; + uint64_t off = s->section_offset; + + if (!pv_dump_initialized) { + return 0; + } + + for (; sctn->sections_size_func; off += shdr->sh_size, sctn++, shdr++) { + memset(shdr, 0, sizeof(*shdr)); + shdr->sh_type = SHT_PROGBITS; + shdr->sh_offset = off; + shdr->sh_size = sctn->sections_size_func(s); + shdr->sh_name = s->string_table_buf->len; + g_array_append_vals(s->string_table_buf, sctn->sctn_str, sizeof(sctn->sctn_str)); + } + + return (uintptr_t)shdr - (uintptr_t)buff; +} + + +/* Add arch specific number of sections and their respective sizes */ +static void arch_sections_add(DumpState *s) +{ + struct sections *sctn = sections; + + /* + * We only do a PV dump if we are running a PV guest, KVM supports + * the dump API and we got valid dump length information. + */ + if (!s390_is_pv() || !kvm_s390_get_protected_dump() || + !kvm_s390_pv_info_basic_valid()) { + return; + } + + /* + * Start the UV dump process by doing the initialize dump call via + * KVM as the proxy. + */ + if (!kvm_s390_dump_init()) { + pv_dump_initialized = true; + } else { + /* + * Dump init failed, maybe the guest owner disabled dumping. + * We'll continue the non-PV dump process since this is no + * reason to crash qemu. + */ + return; + } + + for (; sctn->sections_size_func; sctn++) { + s->shdr_num += 1; + s->elf_section_data_size += sctn->sections_size_func(s); + } +} + +/* + * After the PV dump has been initialized, the CPU data has been + * fetched and memory has been dumped, we need to grab the tweak data + * and the completion data. + */ +static int arch_sections_write(DumpState *s, uint8_t *buff) +{ + struct sections *sctn = sections; + int rc; + + if (!pv_dump_initialized) { + return -EINVAL; + } + + for (; sctn->sections_size_func; sctn++) { + rc = sctn->sections_contents_func(s, buff); + buff += sctn->sections_size_func(s); + if (rc) { + return rc; + } + } + return 0; +} + int cpu_get_dump_info(ArchDumpInfo *info, const struct GuestPhysBlockList *guest_phys_blocks) { info->d_machine = EM_S390; info->d_endian = ELFDATA2MSB; info->d_class = ELFCLASS64; - + /* + * This is evaluated for each dump so we can freely switch + * between PV and non-PV. + */ + if (s390_is_pv() && kvm_s390_get_protected_dump() && + kvm_s390_pv_info_basic_valid()) { + info->arch_sections_add_fn = *arch_sections_add; + info->arch_sections_write_hdr_fn = *arch_sections_write_hdr; + info->arch_sections_write_fn = *arch_sections_write; + } else { + info->arch_sections_add_fn = NULL; + info->arch_sections_write_hdr_fn = NULL; + info->arch_sections_write_fn = NULL; + } return 0; } @@ -261,7 +466,7 @@ ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) { int name_size = 8; /* "LINUX" or "CORE" + pad */ size_t elf_note_size = 0; - int note_head_size; + int note_head_size, content_size; const NoteFuncDesc *nf; assert(class == ELFCLASS64); @@ -270,12 +475,15 @@ ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) note_head_size = sizeof(Elf64_Nhdr); for (nf = note_core; nf->note_contents_func; nf++) { - elf_note_size = elf_note_size + note_head_size + name_size + - nf->contents_size; + elf_note_size = elf_note_size + note_head_size + name_size + nf->contents_size; } for (nf = note_linux; nf->note_contents_func; nf++) { + if (nf->pvonly && !s390_is_pv()) { + continue; + } + content_size = nf->contents_size ? nf->contents_size : nf->note_size_func(); elf_note_size = elf_note_size + note_head_size + name_size + - nf->contents_size; + content_size; } return (elf_note_size) * nr_cpus;