[S390] zcore: CPU registers are not saved under LPAR
authorMichael Holzheu <holzheu@linux.vnet.ibm.com>
Wed, 24 Mar 2010 10:49:50 +0000 (11:49 +0100)
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>
Wed, 24 Mar 2010 10:49:53 +0000 (11:49 +0100)
To save the registers for all CPUs a sigp "store status" is done that
stores the registers to address absolute zero. To access storage at
absolute zero, normally the address of the prefix register of the
accessing CPU has to be used. This does not work when large pages are
active (currently only under LPAR). In order to fix that problem,
instead of memcpy memcpy_real is used, which switches to real mode
where prefixing works.

Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/include/asm/system.h
arch/s390/kernel/smp.c
arch/s390/mm/maccess.c
drivers/s390/char/zcore.c

index 67ee6c3..12be42b 100644 (file)
@@ -110,6 +110,7 @@ extern void pfault_fini(void);
 #endif /* CONFIG_PFAULT */
 
 extern void cmma_init(void);
+extern int memcpy_real(void *, void *, size_t);
 
 #define finish_arch_switch(prev) do {                                       \
        set_fs(current->thread.mm_segment);                                  \
index 29f65bc..d7d24fc 100644 (file)
@@ -292,9 +292,9 @@ static void __init smp_get_save_area(unsigned int cpu, unsigned int phy_cpu)
        zfcpdump_save_areas[cpu] = kmalloc(sizeof(struct save_area), GFP_KERNEL);
        while (raw_sigp(phy_cpu, sigp_stop_and_store_status) == sigp_busy)
                cpu_relax();
-       memcpy(zfcpdump_save_areas[cpu],
-              (void *)(unsigned long) store_prefix() + SAVE_AREA_BASE,
-              sizeof(struct save_area));
+       memcpy_real(zfcpdump_save_areas[cpu],
+                   (void *)(unsigned long) store_prefix() + SAVE_AREA_BASE,
+                   sizeof(struct save_area));
 }
 
 struct save_area *zfcpdump_save_areas[NR_CPUS + 1];
index 8175627..a8c2af8 100644 (file)
@@ -59,3 +59,29 @@ long probe_kernel_write(void *dst, void *src, size_t size)
        }
        return copied < 0 ? -EFAULT : 0;
 }
+
+int memcpy_real(void *dest, void *src, size_t count)
+{
+       register unsigned long _dest asm("2") = (unsigned long) dest;
+       register unsigned long _len1 asm("3") = (unsigned long) count;
+       register unsigned long _src  asm("4") = (unsigned long) src;
+       register unsigned long _len2 asm("5") = (unsigned long) count;
+       unsigned long flags;
+       int rc = -EFAULT;
+
+       if (!count)
+               return 0;
+       flags = __raw_local_irq_stnsm(0xf8UL);
+       asm volatile (
+               "0:     mvcle   %1,%2,0x0\n"
+               "1:     jo      0b\n"
+               "       lhi     %0,0x0\n"
+               "2:\n"
+               EX_TABLE(1b,2b)
+               : "+d" (rc), "+d" (_dest), "+d" (_src), "+d" (_len1),
+                 "+d" (_len2), "=m" (*((long *) dest))
+               : "m" (*((long *) src))
+               : "cc", "memory");
+       __raw_local_irq_ssm(flags);
+       return rc;
+}
index 3438658..3166d85 100644 (file)
@@ -141,33 +141,6 @@ static int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count)
        return memcpy_hsa(dest, src, count, TO_KERNEL);
 }
 
-static int memcpy_real(void *dest, unsigned long src, size_t count)
-{
-       unsigned long flags;
-       int rc = -EFAULT;
-       register unsigned long _dest asm("2") = (unsigned long) dest;
-       register unsigned long _len1 asm("3") = (unsigned long) count;
-       register unsigned long _src  asm("4") = src;
-       register unsigned long _len2 asm("5") = (unsigned long) count;
-
-       if (count == 0)
-               return 0;
-       flags = __raw_local_irq_stnsm(0xf8UL); /* switch to real mode */
-       asm volatile (
-               "0:     mvcle   %1,%2,0x0\n"
-               "1:     jo      0b\n"
-               "       lhi     %0,0x0\n"
-               "2:\n"
-               EX_TABLE(1b,2b)
-               : "+d" (rc), "+d" (_dest), "+d" (_src), "+d" (_len1),
-                 "+d" (_len2), "=m" (*((long*)dest))
-               : "m" (*((long*)src))
-               : "cc", "memory");
-       __raw_local_irq_ssm(flags);
-
-       return rc;
-}
-
 static int memcpy_real_user(void __user *dest, unsigned long src, size_t count)
 {
        static char buf[4096];
@@ -175,7 +148,7 @@ static int memcpy_real_user(void __user *dest, unsigned long src, size_t count)
 
        while (offs < count) {
                size = min(sizeof(buf), count - offs);
-               if (memcpy_real(buf, src + offs, size))
+               if (memcpy_real(buf, (void *) src + offs, size))
                        return -EFAULT;
                if (copy_to_user(dest + offs, buf, size))
                        return -EFAULT;
@@ -663,7 +636,7 @@ static int __init zcore_reipl_init(void)
        if (ipib_info.ipib < ZFCPDUMP_HSA_SIZE)
                rc = memcpy_hsa_kernel(ipl_block, ipib_info.ipib, PAGE_SIZE);
        else
-               rc = memcpy_real(ipl_block, ipib_info.ipib, PAGE_SIZE);
+               rc = memcpy_real(ipl_block, (void *) ipib_info.ipib, PAGE_SIZE);
        if (rc) {
                free_page((unsigned long) ipl_block);
                return rc;