s390/mm: allocate Real Memory Copy Area in decompressor
authorAlexander Gordeev <agordeev@linux.ibm.com>
Sun, 11 Dec 2022 07:18:57 +0000 (08:18 +0100)
committerHeiko Carstens <hca@linux.ibm.com>
Fri, 13 Jan 2023 13:15:06 +0000 (14:15 +0100)
Move Real Memory Copy Area allocation to the decompressor.
As result, memcpy_real() and memcpy_real_iter() movers
become usable since the very moment the kernel starts.

Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
arch/s390/boot/startup.c
arch/s390/boot/vmem.c
arch/s390/include/asm/maccess.h
arch/s390/kernel/setup.c
arch/s390/mm/maccess.c

index c5d59df..cb4b743 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/elf.h>
 #include <asm/boot_data.h>
 #include <asm/sections.h>
+#include <asm/maccess.h>
 #include <asm/cpu_mf.h>
 #include <asm/setup.h>
 #include <asm/kasan.h>
@@ -19,6 +20,7 @@
 unsigned long __bootdata_preserved(__kaslr_offset);
 unsigned long __bootdata_preserved(__abs_lowcore);
 unsigned long __bootdata_preserved(__memcpy_real_area);
+pte_t *__bootdata_preserved(memcpy_real_ptep);
 unsigned long __bootdata(__amode31_base);
 unsigned long __bootdata_preserved(VMALLOC_START);
 unsigned long __bootdata_preserved(VMALLOC_END);
index af9124c..41ff38a 100644 (file)
@@ -5,6 +5,7 @@
 #include <asm/facility.h>
 #include <asm/sections.h>
 #include <asm/mem_detect.h>
+#include <asm/maccess.h>
 #include "decompressor.h"
 #include "boot.h"
 
 #define swapper_pg_dir         vmlinux.swapper_pg_dir_off
 #define invalid_pg_dir         vmlinux.invalid_pg_dir_off
 
+/*
+ * Mimic virt_to_kpte() in lack of init_mm symbol. Skip pmd NULL check though.
+ */
+static inline pte_t *__virt_to_kpte(unsigned long va)
+{
+       return pte_offset_kernel(pmd_offset(pud_offset(p4d_offset(pgd_offset_k(va), va), va), va), va);
+}
+
 unsigned long __bootdata_preserved(s390_invalid_asce);
 unsigned long __bootdata(pgalloc_pos);
 unsigned long __bootdata(pgalloc_end);
 unsigned long __bootdata(pgalloc_low);
 
 enum populate_mode {
+       POPULATE_NONE,
        POPULATE_ONE2ONE,
 };
 
@@ -88,6 +98,8 @@ static pte_t *boot_pte_alloc(void)
 static unsigned long _pa(unsigned long addr, enum populate_mode mode)
 {
        switch (mode) {
+       case POPULATE_NONE:
+               return -1;
        case POPULATE_ONE2ONE:
                return addr;
        default:
@@ -259,6 +271,9 @@ void setup_vmem(unsigned long online_end, unsigned long asce_limit)
        pgtable_populate_begin(online_end);
        pgtable_populate(0, sizeof(struct lowcore), POPULATE_ONE2ONE);
        pgtable_populate(0, online_end, POPULATE_ONE2ONE);
+       pgtable_populate(__memcpy_real_area, __memcpy_real_area + PAGE_SIZE,
+                        POPULATE_NONE);
+       memcpy_real_ptep = __virt_to_kpte(__memcpy_real_area);
        pgtable_populate_end();
 
        S390_lowcore.kernel_asce = swapper_pg_dir | asce_bits;
index c7fa838..cfec314 100644 (file)
@@ -7,7 +7,7 @@
 struct iov_iter;
 
 extern unsigned long __memcpy_real_area;
-void memcpy_real_init(void);
+extern pte_t *memcpy_real_ptep;
 size_t memcpy_real_iter(struct iov_iter *iter, unsigned long src, size_t count);
 int memcpy_real(void *dest, unsigned long src, size_t count);
 #ifdef CONFIG_CRASH_DUMP
index 1ffaa85..9ae2f6b 100644 (file)
@@ -1046,7 +1046,7 @@ void __init setup_arch(char **cmdline_p)
         * Create kernel page tables.
         */
         paging_init();
-       memcpy_real_init();
+
        /*
         * After paging_init created the kernel page table, the new PSWs
         * in lowcore can now run with DAT enabled.
index a6314e2..7c66b3a 100644 (file)
@@ -21,7 +21,7 @@
 #include <asm/maccess.h>
 
 unsigned long __bootdata_preserved(__memcpy_real_area);
-static __ro_after_init pte_t *memcpy_real_ptep;
+pte_t *__bootdata_preserved(memcpy_real_ptep);
 static DEFINE_MUTEX(memcpy_real_mutex);
 
 static notrace long s390_kernel_write_odd(void *dst, const void *src, size_t size)
@@ -79,13 +79,6 @@ notrace void *s390_kernel_write(void *dst, const void *src, size_t size)
        return dst;
 }
 
-void __init memcpy_real_init(void)
-{
-       memcpy_real_ptep = vmem_get_alloc_pte(__memcpy_real_area, true);
-       if (!memcpy_real_ptep)
-               panic("Couldn't setup memcpy real area");
-}
-
 size_t memcpy_real_iter(struct iov_iter *iter, unsigned long src, size_t count)
 {
        size_t len, copied, res = 0;