Skip to content

Commit

Permalink
s390/crash: Use old os_info to create PT_LOAD headers
Browse files Browse the repository at this point in the history
This is a preparatory rework to allow uncoupling virtual
and physical addresses spaces.

The vmcore ELF program headers describe virtual memory
regions of a crashed kernel. User level tools use that
information for the kernel text and data analysis (e.g
vmcore-dmesg extracts the kernel log).

Currently the kernel image is covered by program headers
describing the identity mapping regions. But in the future
the kernel image will be mapped into separate region outside
of the identity mapping. Create the additional ELF program
header that covers kernel image only, so that vmcore tools
could locate kernel text and data.

Further, the identity mapping in crashed and capture kernels
will have different base address. Due to that __va() macro
can not be used in the capture kernel. Instead, read crashed
kernel identity mapping base address from os_info and use
it for PT_LOAD type program headers creation.

Acked-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
  • Loading branch information
Alexander Gordeev committed Apr 17, 2024
1 parent 378e32a commit f4cac27
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 5 deletions.
3 changes: 3 additions & 0 deletions arch/s390/include/asm/os_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
#define OS_INFO_VMEMMAP 7
#define OS_INFO_AMODE31_START 8
#define OS_INFO_AMODE31_END 9
#define OS_INFO_IMAGE_START 10
#define OS_INFO_IMAGE_END 11
#define OS_INFO_IMAGE_PHYS 12

#define OS_INFO_FLAG_REIPL_CLEAR (1UL << 0)

Expand Down
41 changes: 36 additions & 5 deletions arch/s390/kernel/crash_dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,11 @@ static void *ehdr_init(Elf64_Ehdr *ehdr, int mem_chunk_cnt)
ehdr->e_phoff = sizeof(Elf64_Ehdr);
ehdr->e_ehsize = sizeof(Elf64_Ehdr);
ehdr->e_phentsize = sizeof(Elf64_Phdr);
ehdr->e_phnum = mem_chunk_cnt + 1;
/*
* Number of memory chunk PT_LOAD program headers plus one kernel
* image PT_LOAD program header plus one PT_NOTE program header.
*/
ehdr->e_phnum = mem_chunk_cnt + 1 + 1;
return ehdr + 1;
}

Expand Down Expand Up @@ -501,22 +505,42 @@ static int get_mem_chunk_cnt(void)
*/
static void loads_init(Elf64_Phdr *phdr)
{
unsigned long old_identity_base = os_info_old_value(OS_INFO_IDENTITY_BASE);
phys_addr_t start, end;
u64 idx;

for_each_physmem_range(idx, &oldmem_type, &start, &end) {
phdr->p_filesz = end - start;
phdr->p_type = PT_LOAD;
phdr->p_vaddr = old_identity_base + start;
phdr->p_offset = start;
phdr->p_vaddr = (unsigned long)__va(start);
phdr->p_paddr = start;
phdr->p_filesz = end - start;
phdr->p_memsz = end - start;
phdr->p_flags = PF_R | PF_W | PF_X;
phdr->p_align = PAGE_SIZE;
phdr++;
}
}

/*
* Prepare PT_LOAD type program header for kernel image region
*/
static void text_init(Elf64_Phdr *phdr)
{
unsigned long start_phys = os_info_old_value(OS_INFO_IMAGE_PHYS);
unsigned long start = os_info_old_value(OS_INFO_IMAGE_START);
unsigned long end = os_info_old_value(OS_INFO_IMAGE_END);

phdr->p_type = PT_LOAD;
phdr->p_vaddr = start;
phdr->p_filesz = end - start;
phdr->p_memsz = end - start;
phdr->p_offset = start_phys;
phdr->p_paddr = start_phys;
phdr->p_flags = PF_R | PF_W | PF_X;
phdr->p_align = PAGE_SIZE;
}

/*
* Initialize notes (new kernel)
*/
Expand Down Expand Up @@ -557,6 +581,8 @@ static size_t get_elfcorehdr_size(int mem_chunk_cnt)
size += nt_vmcoreinfo_size();
/* nt_final */
size += sizeof(Elf64_Nhdr);
/* PT_LOAD type program header for kernel text region */
size += sizeof(Elf64_Phdr);
/* PT_LOADS */
size += mem_chunk_cnt * sizeof(Elf64_Phdr);

Expand All @@ -568,7 +594,7 @@ static size_t get_elfcorehdr_size(int mem_chunk_cnt)
*/
int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size)
{
Elf64_Phdr *phdr_notes, *phdr_loads;
Elf64_Phdr *phdr_notes, *phdr_loads, *phdr_text;
size_t alloc_size;
int mem_chunk_cnt;
void *ptr, *hdr;
Expand Down Expand Up @@ -606,14 +632,19 @@ int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size)
/* Init program headers */
phdr_notes = ptr;
ptr = PTR_ADD(ptr, sizeof(Elf64_Phdr));
phdr_text = ptr;
ptr = PTR_ADD(ptr, sizeof(Elf64_Phdr));
phdr_loads = ptr;
ptr = PTR_ADD(ptr, sizeof(Elf64_Phdr) * mem_chunk_cnt);
/* Init notes */
hdr_off = PTR_DIFF(ptr, hdr);
ptr = notes_init(phdr_notes, ptr, ((unsigned long) hdr) + hdr_off);
/* Init kernel text program header */
text_init(phdr_text);
/* Init loads */
hdr_off = PTR_DIFF(ptr, hdr);
loads_init(phdr_loads);
/* Finalize program headers */
hdr_off = PTR_DIFF(ptr, hdr);
*addr = (unsigned long long) hdr;
*size = (unsigned long long) hdr_off;
BUG_ON(elfcorehdr_size > alloc_size);
Expand Down
3 changes: 3 additions & 0 deletions arch/s390/kernel/os_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ void __init os_info_init(void)
os_info_entry_add_val(OS_INFO_VMEMMAP, (unsigned long)vmemmap);
os_info_entry_add_val(OS_INFO_AMODE31_START, AMODE31_START);
os_info_entry_add_val(OS_INFO_AMODE31_END, AMODE31_END);
os_info_entry_add_val(OS_INFO_IMAGE_START, (unsigned long)_stext);
os_info_entry_add_val(OS_INFO_IMAGE_END, (unsigned long)_end);
os_info_entry_add_val(OS_INFO_IMAGE_PHYS, __pa_symbol(_stext));
os_info.csum = os_info_csum(&os_info);
abs_lc = get_abs_lowcore();
abs_lc->os_info = __pa(&os_info);
Expand Down

0 comments on commit f4cac27

Please sign in to comment.