From d0164e7e480ad2ffd3fe73fe53c46087e5e137a6 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Thu, 7 Dec 2023 16:54:06 +0100 Subject: [PATCH 09/14] s390x: uncouple physical and virtual memory spaces Rework VTOP and PTOV macros to reflect the future uncoupling of physical and virtual address spaces in kernel. Existing versions are not affected. Signed-off-by: Alexander Gordeev Signed-off-by: Lianbo Jiang --- defs.h | 20 +++++- s390x.c | 212 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 228 insertions(+), 4 deletions(-) diff --git a/defs.h b/defs.h index 5218a94fe4a4..20237b72a10b 100644 --- a/defs.h +++ b/defs.h @@ -4564,9 +4564,9 @@ struct efi_memory_desc_t { #define _64BIT_ #define MACHINE_TYPE "S390X" -#define PTOV(X) ((unsigned long)(X)+(machdep->kvbase)) -#define VTOP(X) ((unsigned long)(X)-(machdep->kvbase)) -#define IS_VMALLOC_ADDR(X) (vt->vmalloc_start && (ulong)(X) >= vt->vmalloc_start) +#define PTOV(X) s390x_PTOV((ulong)(X)) +#define VTOP(X) s390x_VTOP((ulong)(X)) +#define IS_VMALLOC_ADDR(X) s390x_IS_VMALLOC_ADDR(X) #define PTRS_PER_PTE 512 #define PTRS_PER_PMD 1024 #define PTRS_PER_PGD 2048 @@ -6827,7 +6827,21 @@ void get_s390_panicmsg(char *); * s390x.c */ #ifdef S390X + +struct machine_specific +{ + ulong (*virt_to_phys)(ulong vaddr); + ulong (*phys_to_virt)(ulong paddr); + int (*is_vmalloc_addr)(ulong vaddr); + ulong __kaslr_offset_phys; + ulong amode31_start; + ulong amode31_end; +}; + void s390x_init(int); +ulong s390x_PTOV(ulong); +ulong s390x_VTOP(ulong); +int s390x_IS_VMALLOC_ADDR(ulong); void s390x_dump_machdep_table(ulong); #define display_idt_table() \ error(FATAL, "-d option is not applicable to S390X architecture\n") diff --git a/s390x.c b/s390x.c index 957b839a5fa9..794ae825906d 100644 --- a/s390x.c +++ b/s390x.c @@ -47,6 +47,7 @@ #define S390X_PSW_MASK_PSTATE 0x0001000000000000UL #define S390X_LC_VMCORE_INFO 0xe0c +#define S390X_LC_OS_INFO 0xe18 /* * Flags for Region and Segment table entries. @@ -168,6 +169,19 @@ static struct line_number_hook s390x_line_number_hooks[]; static int s390x_is_uvaddr(ulong, struct task_context *); static int s390x_get_kvaddr_ranges(struct vaddr_range *); static int set_s390x_max_physmem_bits(void); +static ulong s390x_generic_VTOP(ulong vaddr); +static ulong s390x_generic_PTOV(ulong paddr); +static int s390x_generic_IS_VMALLOC_ADDR(ulong vaddr); +static ulong s390x_vr_VTOP(ulong vaddr); +static ulong s390x_vr_PTOV(ulong paddr); +static int s390x_vr_IS_VMALLOC_ADDR(ulong vaddr); +static int s390x_vr_is_kvaddr(ulong); + +struct machine_specific s390x_machine_specific = { + .virt_to_phys = s390x_generic_VTOP, + .phys_to_virt = s390x_generic_PTOV, + .is_vmalloc_addr = s390x_generic_IS_VMALLOC_ADDR, +}; /* * struct lowcore name (old: "_lowcore", new: "lowcore") @@ -546,6 +560,191 @@ static void s390x_check_kaslr(void) free(vmcoreinfo); } +#define OS_INFO_VERSION_MAJOR 1 +#define OS_INFO_VERSION_MINOR 1 + +#define OS_INFO_VMCOREINFO 0 +#define OS_INFO_REIPL_BLOCK 1 +#define OS_INFO_FLAGS_ENTRY 2 +#define OS_INFO_RESERVED 3 +#define OS_INFO_IDENTITY_BASE 4 +#define OS_INFO_KASLR_OFFSET 5 +#define OS_INFO_KASLR_OFF_PHYS 6 +#define OS_INFO_VMEMMAP 7 +#define OS_INFO_AMODE31_START 8 +#define OS_INFO_AMODE31_END 9 + +struct os_info_entry { + union { + __u64 addr; + __u64 val; + }; + __u64 size; + __u32 csum; +} __attribute__((packed)); + +struct os_info { + __u64 magic; + __u32 csum; + __u16 version_major; + __u16 version_minor; + __u64 crashkernel_addr; + __u64 crashkernel_size; + struct os_info_entry entry[10]; + __u8 reserved[3864]; +} __attribute__((packed)); + +struct vm_info { + __u64 __identity_base; + __u64 __kaslr_offset; + __u64 __kaslr_offset_phys; + __u64 amode31_start; + __u64 amode31_end; +}; + +static bool +vmcoreinfo_read_u64(const char *key, __u64 *val) +{ + char *string; + + string = pc->read_vmcoreinfo(key); + if (string) { + *val = strtoul(string, NULL, 16); + free(string); + return true; + } + + return false; +} + +static bool vmcoreinfo_read_vm_info(struct vm_info *_vm_info) +{ + struct vm_info vm_info; + + if (!vmcoreinfo_read_u64("IDENTITYBASE", &vm_info.__identity_base) || + !vmcoreinfo_read_u64("KERNELOFFSET", &vm_info.__kaslr_offset) || + !vmcoreinfo_read_u64("KERNELOFFPHYS", &vm_info.__kaslr_offset_phys) || + !vmcoreinfo_read_u64("SAMODE31", &vm_info.amode31_start) || + !vmcoreinfo_read_u64("EAMODE31", &vm_info.amode31_end)) + return false; + + *_vm_info = vm_info; + + return true; +} + +static bool os_info_read_vm_info(struct vm_info *vm_info) +{ + struct os_info os_info; + ulong addr; + + if (!readmem(S390X_LC_OS_INFO, PHYSADDR, &addr, + sizeof(addr), "s390x os_info ptr", + QUIET|RETURN_ON_ERROR)) + return false; + + if (addr == 0) + return true; + + if (!readmem(addr, PHYSADDR, &os_info, + offsetof(struct os_info, reserved), "s390x os_info header", + QUIET|RETURN_ON_ERROR)) + return false; + + vm_info->__identity_base = os_info.entry[OS_INFO_IDENTITY_BASE].val; + vm_info->__kaslr_offset = os_info.entry[OS_INFO_KASLR_OFFSET].val; + vm_info->__kaslr_offset_phys = os_info.entry[OS_INFO_KASLR_OFF_PHYS].val; + vm_info->amode31_start = os_info.entry[OS_INFO_AMODE31_START].val; + vm_info->amode31_end = os_info.entry[OS_INFO_AMODE31_END].val; + + return true; +} + +static bool vm_info_empty(struct vm_info *vm_info) +{ + return !vm_info->__kaslr_offset; +} + +static bool s390x_init_vm(void) +{ + struct vm_info vm_info; + + if (pc->flags & PROC_KCORE) { + if (!vmcoreinfo_read_vm_info(&vm_info)) + return true; + } else { + if (!os_info_read_vm_info(&vm_info)) + return false; + } + if (vm_info_empty(&vm_info)) + return true; + + machdep->identity_map_base = vm_info.__identity_base; + machdep->kvbase = vm_info.__kaslr_offset; + machdep->machspec->__kaslr_offset_phys = vm_info.__kaslr_offset_phys; + machdep->machspec->amode31_start = vm_info.amode31_start; + machdep->machspec->amode31_end = vm_info.amode31_end; + + machdep->is_kvaddr = s390x_vr_is_kvaddr; + machdep->machspec->virt_to_phys = s390x_vr_VTOP; + machdep->machspec->phys_to_virt = s390x_vr_PTOV; + machdep->machspec->is_vmalloc_addr = s390x_vr_IS_VMALLOC_ADDR; + + return true; +} + +static ulong s390x_generic_VTOP(ulong vaddr) +{ + return vaddr - machdep->kvbase; +} + +static ulong s390x_generic_PTOV(ulong paddr) +{ + return paddr + machdep->kvbase; +} + +static int s390x_generic_IS_VMALLOC_ADDR(ulong vaddr) +{ + return vt->vmalloc_start && vaddr >= vt->vmalloc_start; +} + +static ulong s390x_vr_VTOP(ulong vaddr) +{ + if (vaddr < LOWCORE_SIZE) + return vaddr; + if ((vaddr < machdep->machspec->amode31_end) && + (vaddr >= machdep->machspec->amode31_start)) + return vaddr; + if (vaddr < machdep->kvbase) + return vaddr - machdep->identity_map_base; + return vaddr - machdep->kvbase + machdep->machspec->__kaslr_offset_phys; +} + +static ulong s390x_vr_PTOV(ulong paddr) +{ + return paddr + machdep->identity_map_base; +} + +static int s390x_vr_IS_VMALLOC_ADDR(ulong vaddr) +{ + return (vaddr >= vt->vmalloc_start && vaddr < machdep->kvbase); +} + +ulong s390x_VTOP(ulong vaddr) +{ + return machdep->machspec->virt_to_phys(vaddr); +} + +ulong s390x_PTOV(ulong paddr) +{ + return machdep->machspec->phys_to_virt(paddr); +} + +int s390x_IS_VMALLOC_ADDR(ulong vaddr) +{ + return machdep->machspec->is_vmalloc_addr(vaddr); +} + /* * Do all necessary machine-specific setup here. This is called several * times during initialization. @@ -560,6 +759,7 @@ s390x_init(int when) machdep->process_elf_notes = s390x_process_elf_notes; break; case PRE_SYMTAB: + machdep->machspec = &s390x_machine_specific; machdep->verify_symbol = s390x_verify_symbol; if (pc->flags & KERNEL_DEBUG_QUERY) return; @@ -587,6 +787,8 @@ s390x_init(int when) machdep->kvbase = 0; machdep->identity_map_base = 0; machdep->is_kvaddr = generic_is_kvaddr; + if (!s390x_init_vm()) + error(FATAL, "cannot initialize VM parameters."); machdep->is_uvaddr = s390x_is_uvaddr; machdep->eframe_search = s390x_eframe_search; machdep->back_trace = s390x_back_trace_cmd; @@ -681,7 +883,9 @@ s390x_dump_machdep_table(ulong arg) fprintf(fp, " dis_filter: s390x_dis_filter()\n"); fprintf(fp, " cmd_mach: s390x_cmd_mach()\n"); fprintf(fp, " get_smp_cpus: s390x_get_smp_cpus()\n"); - fprintf(fp, " is_kvaddr: generic_is_kvaddr()\n"); + fprintf(fp, " is_kvaddr: %s()\n", machdep->is_kvaddr == s390x_vr_is_kvaddr ? + "s390x_vr_is_kvaddr" : + "generic_is_kvaddr"); fprintf(fp, " is_uvaddr: s390x_is_uvaddr()\n"); fprintf(fp, " verify_paddr: generic_verify_paddr()\n"); fprintf(fp, " get_kvaddr_ranges: s390x_get_kvaddr_ranges()\n"); @@ -702,6 +906,12 @@ s390x_dump_machdep_table(ulong arg) fprintf(fp, " machspec: %lx\n", (ulong)machdep->machspec); } +static int +s390x_vr_is_kvaddr(ulong vaddr) +{ + return (vaddr < LOWCORE_SIZE) || (vaddr >= machdep->identity_map_base); +} + /* * Check if address is in context's address space */ -- 2.41.0