From: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
To: kexec@lists.infradead.org
Subject: [PATCH v2 12/14] Read kexec backup region
Date: Fri, 28 Oct 2011 18:49:09 +0900 [thread overview]
Message-ID: <20111028094909.20940.48359.stgit@localhost6.localdomain6> (raw)
In-Reply-To: <20111028094454.20940.1209.stgit@localhost6.localdomain6>
Deal with the first 640kB memory backed up by kdump by interpreting
the read request to the region as the request to the backup region
that is specially prepared to preserve the original first kernel's
memory situtation.
The first 640kB memory contains the data necessary for paging: PTE,
for example. So, initialization must be done before trying to read
memory requiring paging to read such as VMALLOC'ed data.
Signed-off-by: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
---
makedumpfile.c | 45 +++++++++++----
makedumpfile.h | 41 ++++++++++++++
sadump_info.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
sadump_info.h | 6 ++
4 files changed, 249 insertions(+), 11 deletions(-)
diff --git a/makedumpfile.c b/makedumpfile.c
index 44f6ee6..df82a48 100644
--- a/makedumpfile.c
+++ b/makedumpfile.c
@@ -829,6 +829,7 @@ get_symbol_info(void)
SYMBOL_INIT(cpu_online_mask, "cpu_online_mask");
if (SYMBOL(cpu_online_mask) == NOT_FOUND_SYMBOL)
SYMBOL_INIT(cpu_online_mask, "cpu_online_map");
+ SYMBOL_INIT(kexec_crash_image, "kexec_crash_image");
if (SYMBOL(node_data) != NOT_FOUND_SYMBOL)
SYMBOL_ARRAY_TYPE_INIT(node_data, "node_data");
@@ -1115,6 +1116,23 @@ get_structure_info(void)
}
#endif /* __x86_64__ */
+ OFFSET_INIT(kimage.segment, "kimage", "segment");
+
+ MEMBER_ARRAY_LENGTH_INIT(kimage.segment, "kimage", "segment");
+
+ SIZE_INIT(kexec_segment, "kexec_segment");
+ OFFSET_INIT(kexec_segment.mem, "kexec_segment", "mem");
+
+ OFFSET_INIT(elf64_hdr.e_phnum, "elf64_hdr", "e_phnum");
+ OFFSET_INIT(elf64_hdr.e_phentsize, "elf64_hdr", "e_phentsize");
+ OFFSET_INIT(elf64_hdr.e_phoff, "elf64_hdr", "e_phoff");
+
+ SIZE_INIT(elf64_hdr, "elf64_hdr");
+ OFFSET_INIT(elf64_phdr.p_type, "elf64_phdr", "p_type");
+ OFFSET_INIT(elf64_phdr.p_offset, "elf64_phdr", "p_offset");
+ OFFSET_INIT(elf64_phdr.p_paddr, "elf64_phdr", "p_paddr");
+ OFFSET_INIT(elf64_phdr.p_memsz, "elf64_phdr", "p_memsz");
+
return TRUE;
}
@@ -2619,6 +2637,16 @@ out:
if (!get_versiondep_info())
return FALSE;
+ /*
+ * NOTE: This must be done before refering to
+ * VMALLOC'ed memory. The first 640kB contains data
+ * necessary for paging, like PTE. The absence of the
+ * region affects reading VMALLOC'ed memory such as
+ * module data.
+ */
+ if (info->flag_sadump)
+ sadump_kdump_backup_region_init();
+
if (!get_numnodes())
return FALSE;
@@ -2756,6 +2784,12 @@ set_bit_on_1st_bitmap(unsigned long long pfn)
}
int
+clear_bit_on_1st_bitmap(unsigned long long pfn)
+{
+ return set_bitmap(info->bitmap1, pfn, 0);
+}
+
+int
clear_bit_on_2nd_bitmap(unsigned long long pfn)
{
return set_bitmap(info->bitmap2, pfn, 0);
@@ -2796,17 +2830,6 @@ is_in_segs(unsigned long long paddr)
return FALSE;
}
-static inline int
-is_zero_page(unsigned char *buf, long page_size)
-{
- size_t i;
-
- for (i = 0; i < page_size; i++)
- if (buf[i])
- return FALSE;
- return TRUE;
-}
-
int
read_cache(struct cache_data *cd)
{
diff --git a/makedumpfile.h b/makedumpfile.h
index 020d99c..6ae37d9 100644
--- a/makedumpfile.h
+++ b/makedumpfile.h
@@ -181,6 +181,7 @@ isAnon(unsigned long mapping)
#define STRNEQ(A, B) (A && B && \
(strncmp((char *)(A), (char *)(B), strlen((char *)(B))) == 0))
+#define USHORT(ADDR) *((unsigned short *)(ADDR))
#define UINT(ADDR) *((unsigned int *)(ADDR))
#define ULONG(ADDR) *((unsigned long *)(ADDR))
@@ -996,6 +997,7 @@ struct symbol_table {
unsigned long long __per_cpu_offset;
unsigned long long __per_cpu_load;
unsigned long long cpu_online_mask;
+ unsigned long long kexec_crash_image;
};
struct size_table {
@@ -1027,6 +1029,8 @@ struct size_table {
long user_regs_struct;
long cpumask;
long cpumask_t;
+ long kexec_segment;
+ long elf64_hdr;
};
struct offset_table {
@@ -1135,6 +1139,27 @@ struct offset_table {
long fs;
long gs;
} user_regs_struct;
+
+ struct kimage_s {
+ long segment;
+ } kimage;
+
+ struct kexec_segment_s {
+ long mem;
+ } kexec_segment;
+
+ struct elf64_hdr_s {
+ long e_phnum;
+ long e_phentsize;
+ long e_phoff;
+ } elf64_hdr;
+
+ struct elf64_phdr_s {
+ long p_type;
+ long p_offset;
+ long p_paddr;
+ long p_memsz;
+ } elf64_phdr;
};
/*
@@ -1159,6 +1184,9 @@ struct array_table {
struct free_area_at {
long free_list;
} free_area;
+ struct kimage_at {
+ long segment;
+ } kimage;
};
struct number_table {
@@ -1331,7 +1359,20 @@ is_dumpable(struct dump_bitmap *bitmap, unsigned long long pfn)
return is_on(bitmap->buf, pfn%PFN_BUFBITMAP);
}
+static inline int
+is_zero_page(unsigned char *buf, long page_size)
+{
+ size_t i;
+
+ for (i = 0; i < page_size; i++)
+ if (buf[i])
+ return FALSE;
+ return TRUE;
+}
+
void write_vmcoreinfo_data(void);
+int set_bit_on_1st_bitmap(unsigned long long pfn);
+int clear_bit_on_1st_bitmap(unsigned long long pfn);
#ifdef __x86__
diff --git a/sadump_info.c b/sadump_info.c
index 2538da6..69296ce 100644
--- a/sadump_info.c
+++ b/sadump_info.c
@@ -77,6 +77,12 @@ struct sadump_info {
FILE *file_elf_note;
char *cpu_online_mask_buf;
size_t cpumask_size;
+/* Backup Region, First 640K of System RAM. */
+#define KEXEC_BACKUP_SRC_END 0x0009ffff
+ unsigned long long backup_src_start;
+ unsigned long backup_src_size;
+ unsigned long long backup_offset;
+ int kdump_backed_up;
};
static char *guid_to_str(efi_guid_t *guid, char *buf, size_t buflen);
@@ -188,6 +194,30 @@ sadump_copy_1st_bitmap_from_memory(void)
offset_page += sizeof(buf);
}
+ /*
+ * kdump uses the first 640kB on the 2nd kernel. But both
+ * bitmaps should reflect the 1st kernel memory situation. We
+ * modify bitmap accordingly.
+ */
+ if (si->kdump_backed_up) {
+ unsigned long long paddr, pfn, backup_src_pfn;
+
+ for (paddr = si->backup_src_start;
+ paddr < si->backup_src_start + si->backup_src_size;
+ paddr += info->page_size) {
+
+ pfn = paddr_to_pfn(paddr);
+ backup_src_pfn = paddr_to_pfn(paddr +
+ si->backup_offset -
+ si->backup_src_start);
+
+ if (is_dumpable(info->bitmap_memory, backup_src_pfn))
+ set_bit_on_1st_bitmap(pfn);
+ else
+ clear_bit_on_1st_bitmap(pfn);
+ }
+ }
+
return TRUE;
}
@@ -920,6 +950,11 @@ readpmem_sadump(unsigned long long paddr, void *bufptr, size_t size)
char buf[info->page_size];
int fd_memory;
+ if (si->kdump_backed_up &&
+ paddr >= si->backup_src_start &&
+ paddr < si->backup_src_start + si->backup_src_size)
+ paddr += si->backup_offset - si->backup_src_start;
+
pfn = paddr_to_pfn(paddr);
page_offset = paddr % info->page_size;
@@ -1774,4 +1809,137 @@ free_sadump_info(void)
free(si->cpu_online_mask_buf);
}
+void
+sadump_kdump_backup_region_init(void)
+{
+ unsigned char buf[BUFSIZE];
+ unsigned long i, total, kexec_crash_image_p, elfcorehdr_p;
+ Elf64_Off e_phoff;
+ uint16_t e_phnum, e_phentsize;
+ unsigned long long backup_offset;
+ unsigned long backup_src_start, backup_src_size;
+ size_t bufsize;
+
+ if (!readmem(VADDR, SYMBOL(kexec_crash_image), &kexec_crash_image_p,
+ sizeof(unsigned long))) {
+ ERRMSG("Can't read kexec_crash_image pointer. %s\n",
+ strerror(errno));
+ return;
+ }
+
+ if (!kexec_crash_image_p) {
+ DEBUG_MSG("sadump: kexec crash image was not loaded\n");
+ return;
+ }
+
+ if (!readmem(VADDR, kexec_crash_image_p+OFFSET(kimage.segment),
+ buf, SIZE(kexec_segment)*ARRAY_LENGTH(kimage.segment))) {
+ ERRMSG("Can't read kexec_crash_image->segment. %s\n",
+ strerror(errno));
+ return;
+ }
+
+ elfcorehdr_p = 0;
+ for (i = 0; i < ARRAY_LENGTH(kimage.segment); ++i) {
+ char e_ident[EI_NIDENT];
+ unsigned mem;
+
+ mem=ULONG(buf+i*SIZE(kexec_segment)+OFFSET(kexec_segment.mem));
+ if (!mem)
+ continue;
+
+ if (!readmem(PADDR, mem, e_ident, SELFMAG)) {
+ DEBUG_MSG("sadump: failed to read elfcorehdr buffer\n");
+ return;
+ }
+
+ if (strncmp(ELFMAG, e_ident, SELFMAG) == 0) {
+ elfcorehdr_p = mem;
+ break;
+ }
+ }
+ if (!elfcorehdr_p) {
+ DEBUG_MSG("sadump: kexec_crash_image contains no elfcorehdr "
+ "segment\n");
+ return;
+ }
+
+ if (!readmem(PADDR, elfcorehdr_p, buf, SIZE(elf64_hdr))) {
+ ERRMSG("Can't read elfcorehdr ELF header. %s\n",
+ strerror(errno));
+ return;
+ }
+
+ e_phnum = USHORT(buf + OFFSET(elf64_hdr.e_phnum));
+ e_phentsize = USHORT(buf + OFFSET(elf64_hdr.e_phentsize));
+ e_phoff = ULONG(buf + OFFSET(elf64_hdr.e_phoff));
+
+ backup_src_start = backup_src_size = backup_offset = 0;
+ for (i = 0; i < e_phnum; ++i) {
+ unsigned long p_type, p_offset, p_paddr, p_memsz;
+
+ if (!readmem(PADDR, elfcorehdr_p+e_phoff+i*e_phentsize, buf,
+ e_phentsize)) {
+ ERRMSG("Can't read elfcorehdr program header. %s\n",
+ strerror(errno));
+ return;
+ }
+
+ p_type = UINT(buf + OFFSET(elf64_phdr.p_type));
+ p_offset = ULONG(buf + OFFSET(elf64_phdr.p_offset));
+ p_paddr = ULONG(buf + OFFSET(elf64_phdr.p_paddr));
+ p_memsz = ULONG(buf + OFFSET(elf64_phdr.p_memsz));
+
+ if (p_type == PT_LOAD &&
+ p_paddr <= KEXEC_BACKUP_SRC_END &&
+ p_paddr + p_memsz <= p_offset) {
+
+ backup_src_start = p_paddr;
+ backup_src_size = p_memsz;
+ backup_offset = p_offset;
+
+DEBUG_MSG("sadump: SRC_START: %#016lx SRC_SIZE: %#016lx SRC_OFFSET: %#016llx\n",
+ backup_src_start, backup_src_size, backup_offset);
+
+ break;
+ }
+ }
+ if (i == e_phnum) {
+DEBUG_MSG("sadump: No PT_LOAD in elfcorehdr for backup area\n");
+ return;
+ }
+
+ bufsize = BUFSIZE;
+ for (total = 0; total < backup_src_size; total += bufsize) {
+
+ if (backup_src_size - total < BUFSIZE)
+ bufsize = backup_src_size - total;
+
+ if (!readmem(PADDR, backup_offset + total, buf, bufsize)) {
+ ERRMSG("Can't read bacckup region. %s\n",
+ strerror(errno));
+ return;
+ }
+
+ /*
+ * We're assuming that the backup region is full of 0
+ * before kdump saves the first 640kB memory of the
+ * 1st kernel in the region.
+ */
+ if (!is_zero_page(buf, bufsize)) {
+
+ si->kdump_backed_up = TRUE;
+ si->backup_src_start = backup_src_start;
+ si->backup_src_size = backup_src_size;
+ si->backup_offset = backup_offset;
+
+ DEBUG_MSG("sadump: kdump backup region used\n");
+
+ return;
+ }
+ }
+
+ DEBUG_MSG("sadump: kdump backup region unused\n");
+}
+
#endif /* defined(__x86__) && defined(__x86_64__) */
diff --git a/sadump_info.h b/sadump_info.h
index f90ea5a..1f74ee5 100644
--- a/sadump_info.h
+++ b/sadump_info.h
@@ -54,6 +54,7 @@ long sadump_page_size(void);
char *sadump_head_disk_name_memory(void);
char *sadump_format_type_name(void);
void free_sadump_info(void);
+void sadump_kdump_backup_region_init(void);
static inline int sadump_is_supported_arch(void)
{
@@ -154,6 +155,11 @@ static inline int sadump_is_supported_arch(void)
return FALSE;
}
+static inline void sadump_kdump_backup_region_init(void)
+{
+ return;
+}
+
#endif
#endif /* _SADUMP_INFO_H */
_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec
next prev parent reply other threads:[~2011-10-28 9:49 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-10-28 9:48 [PATCH v2 00/14] Support Fujitsu Stand Alone Dump Format HATAYAMA Daisuke
2011-10-28 9:48 ` [PATCH v2 01/14] Add sadump module header file HATAYAMA Daisuke
2011-10-28 9:48 ` [PATCH v2 02/14] Extend DumpInfo structure HATAYAMA Daisuke
2011-10-28 9:48 ` [PATCH v2 03/14] Implement command-line processing HATAYAMA Daisuke
2011-10-28 9:48 ` [PATCH v2 04/14] Verify and read VMCORE(s) in sadump-related formats HATAYAMA Daisuke
2011-10-28 9:48 ` [PATCH v2 05/14] Export helpers for bitmap table handling HATAYAMA Daisuke
2011-10-28 9:48 ` [PATCH v2 06/14] Initialize internal data according to sadump-related formats HATAYAMA Daisuke
2011-10-28 9:48 ` [PATCH v2 07/14] Initialize debug information for ELF note extraction HATAYAMA Daisuke
2011-10-28 9:48 ` [PATCH v2 08/14] Implement readmem() interface on sadump-related formats HATAYAMA Daisuke
2011-10-28 9:48 ` [PATCH v2 09/14] Estimate phys_base based on linux_banner position HATAYAMA Daisuke
2011-10-28 9:48 ` [PATCH v2 10/14] Generate and save VMCOREINFO and ELF note information HATAYAMA Daisuke
2011-12-20 8:18 ` Atsushi Kumagai
2011-12-20 9:31 ` HATAYAMA Daisuke
2011-12-21 8:22 ` Atsushi Kumagai
2011-12-21 8:39 ` HATAYAMA Daisuke
2011-10-28 9:49 ` [PATCH v2 11/14] Procees CPUs based on online ones HATAYAMA Daisuke
2011-10-28 9:49 ` HATAYAMA Daisuke [this message]
2011-10-28 9:49 ` [PATCH v2 13/14] Add description of sadump-related formts in usage information HATAYAMA Daisuke
2011-10-28 9:49 ` [PATCH v2 14/14] Add description of sadump-related formats in manual page HATAYAMA Daisuke
2011-10-28 12:05 ` [PATCH v2 00/14] Support Fujitsu Stand Alone Dump Format tachibana
2011-12-15 6:47 ` HATAYAMA Daisuke
2011-12-15 8:55 ` tachibana
2011-12-15 9:09 ` HATAYAMA Daisuke
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20111028094909.20940.48359.stgit@localhost6.localdomain6 \
--to=d.hatayama@jp.fujitsu.com \
--cc=kexec@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox