s390/boot: allocate amode31 section in decompressor
authorAlexander Gordeev <agordeev@linux.ibm.com>
Mon, 27 Sep 2021 12:18:26 +0000 (14:18 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 12 Jul 2022 14:34:56 +0000 (16:34 +0200)
[ Upstream commit e3ec8e0f5711d73f7e5d5c3cffdf4fad4f1487b9 ]

The memory for amode31 section is allocated from the decompressed
kernel. Instead, allocate that memory from the decompressor. This
is a prerequisite to allow initialization of the virtual memory
before the decompressed kernel takes over.

Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
arch/s390/boot/compressed/decompressor.h
arch/s390/boot/startup.c
arch/s390/kernel/entry.h
arch/s390/kernel/setup.c
arch/s390/kernel/vmlinux.lds.S

index a59f75c..f75cc31 100644 (file)
@@ -24,6 +24,7 @@ struct vmlinux_info {
        unsigned long dynsym_start;
        unsigned long rela_dyn_start;
        unsigned long rela_dyn_end;
+       unsigned long amode31_size;
 };
 
 /* Symbols defined by linker scripts */
index b13352d..1aa11a8 100644 (file)
@@ -15,6 +15,7 @@
 #include "uv.h"
 
 unsigned long __bootdata_preserved(__kaslr_offset);
+unsigned long __bootdata(__amode31_base);
 unsigned long __bootdata_preserved(VMALLOC_START);
 unsigned long __bootdata_preserved(VMALLOC_END);
 struct page *__bootdata_preserved(vmemmap);
@@ -233,6 +234,12 @@ static void offset_vmlinux_info(unsigned long offset)
        vmlinux.dynsym_start += offset;
 }
 
+static unsigned long reserve_amode31(unsigned long safe_addr)
+{
+       __amode31_base = PAGE_ALIGN(safe_addr);
+       return safe_addr + vmlinux.amode31_size;
+}
+
 void startup_kernel(void)
 {
        unsigned long random_lma;
@@ -247,6 +254,7 @@ void startup_kernel(void)
        setup_lpp();
        store_ipl_parmblock();
        safe_addr = mem_safe_offset();
+       safe_addr = reserve_amode31(safe_addr);
        safe_addr = read_ipl_report(safe_addr);
        uv_query_info();
        rescue_initrd(safe_addr);
index 7f2696e..6083090 100644 (file)
@@ -70,5 +70,6 @@ extern struct exception_table_entry _stop_amode31_ex_table[];
 #define __amode31_data __section(".amode31.data")
 #define __amode31_ref __section(".amode31.refs")
 extern long _start_amode31_refs[], _end_amode31_refs[];
+extern unsigned long __amode31_base;
 
 #endif /* _ENTRY_H */
index 8ede12c..e38de9e 100644 (file)
@@ -95,10 +95,10 @@ EXPORT_SYMBOL(console_irq);
  * relocated above 2 GB, because it has to use 31 bit addresses.
  * Such code and data is part of the .amode31 section.
  */
-unsigned long __amode31_ref __samode31 = __pa(&_samode31);
-unsigned long __amode31_ref __eamode31 = __pa(&_eamode31);
-unsigned long __amode31_ref __stext_amode31 = __pa(&_stext_amode31);
-unsigned long __amode31_ref __etext_amode31 = __pa(&_etext_amode31);
+unsigned long __amode31_ref __samode31 = (unsigned long)&_samode31;
+unsigned long __amode31_ref __eamode31 = (unsigned long)&_eamode31;
+unsigned long __amode31_ref __stext_amode31 = (unsigned long)&_stext_amode31;
+unsigned long __amode31_ref __etext_amode31 = (unsigned long)&_etext_amode31;
 struct exception_table_entry __amode31_ref *__start_amode31_ex_table = _start_amode31_ex_table;
 struct exception_table_entry __amode31_ref *__stop_amode31_ex_table = _stop_amode31_ex_table;
 
@@ -149,6 +149,7 @@ struct mem_detect_info __bootdata(mem_detect);
 struct initrd_data __bootdata(initrd_data);
 
 unsigned long __bootdata_preserved(__kaslr_offset);
+unsigned long __bootdata(__amode31_base);
 unsigned int __bootdata_preserved(zlib_dfltcc_support);
 EXPORT_SYMBOL(zlib_dfltcc_support);
 u64 __bootdata_preserved(stfle_fac_list[16]);
@@ -800,6 +801,7 @@ static void __init reserve_kernel(void)
 
        memblock_reserve(0, STARTUP_NORMAL_OFFSET);
        memblock_reserve((unsigned long)sclp_early_sccb, EXT_SCCB_READ_SCP);
+       memblock_reserve(__amode31_base, __eamode31 - __samode31);
        memblock_reserve((unsigned long)_stext, PFN_PHYS(start_pfn)
                         - (unsigned long)_stext);
 }
@@ -820,20 +822,14 @@ static void __init setup_memory(void)
 
 static void __init relocate_amode31_section(void)
 {
-       unsigned long amode31_addr, amode31_size;
-       long amode31_offset;
+       unsigned long amode31_size = __eamode31 - __samode31;
+       long amode31_offset = __amode31_base - __samode31;
        long *ptr;
 
-       /* Allocate a new AMODE31 capable memory region */
-       amode31_size = __eamode31 - __samode31;
        pr_info("Relocating AMODE31 section of size 0x%08lx\n", amode31_size);
-       amode31_addr = (unsigned long)memblock_alloc_low(amode31_size, PAGE_SIZE);
-       if (!amode31_addr)
-               panic("Failed to allocate memory for AMODE31 section\n");
-       amode31_offset = amode31_addr - __samode31;
 
        /* Move original AMODE31 section to the new one */
-       memmove((void *)amode31_addr, (void *)__samode31, amode31_size);
+       memmove((void *)__amode31_base, (void *)__samode31, amode31_size);
        /* Zero out the old AMODE31 section to catch invalid accesses within it */
        memset((void *)__samode31, 0, amode31_size);
 
index 63bdb9e..42c4352 100644 (file)
@@ -212,6 +212,7 @@ SECTIONS
                QUAD(__dynsym_start)                            /* dynsym_start */
                QUAD(__rela_dyn_start)                          /* rela_dyn_start */
                QUAD(__rela_dyn_end)                            /* rela_dyn_end */
+               QUAD(_eamode31 - _samode31)                     /* amode31_size */
        } :NONE
 
        /* Debugging sections.  */