Commit 92fe3132 authored by Michael Holzheu's avatar Michael Holzheu Committed by Martin Schwidefsky

[S390] zcore: CPU registers are not saved under LPAR

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: default avatarMichael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent ae6be51e
...@@ -110,6 +110,7 @@ extern void pfault_fini(void); ...@@ -110,6 +110,7 @@ extern void pfault_fini(void);
#endif /* CONFIG_PFAULT */ #endif /* CONFIG_PFAULT */
extern void cmma_init(void); extern void cmma_init(void);
extern int memcpy_real(void *, void *, size_t);
#define finish_arch_switch(prev) do { \ #define finish_arch_switch(prev) do { \
set_fs(current->thread.mm_segment); \ set_fs(current->thread.mm_segment); \
......
...@@ -292,9 +292,9 @@ static void __init smp_get_save_area(unsigned int cpu, unsigned int phy_cpu) ...@@ -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); zfcpdump_save_areas[cpu] = kmalloc(sizeof(struct save_area), GFP_KERNEL);
while (raw_sigp(phy_cpu, sigp_stop_and_store_status) == sigp_busy) while (raw_sigp(phy_cpu, sigp_stop_and_store_status) == sigp_busy)
cpu_relax(); cpu_relax();
memcpy(zfcpdump_save_areas[cpu], memcpy_real(zfcpdump_save_areas[cpu],
(void *)(unsigned long) store_prefix() + SAVE_AREA_BASE, (void *)(unsigned long) store_prefix() + SAVE_AREA_BASE,
sizeof(struct save_area)); sizeof(struct save_area));
} }
struct save_area *zfcpdump_save_areas[NR_CPUS + 1]; struct save_area *zfcpdump_save_areas[NR_CPUS + 1];
......
...@@ -59,3 +59,29 @@ long probe_kernel_write(void *dst, void *src, size_t size) ...@@ -59,3 +59,29 @@ long probe_kernel_write(void *dst, void *src, size_t size)
} }
return copied < 0 ? -EFAULT : 0; 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;
}
...@@ -141,33 +141,6 @@ static int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count) ...@@ -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); 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 int memcpy_real_user(void __user *dest, unsigned long src, size_t count)
{ {
static char buf[4096]; static char buf[4096];
...@@ -175,7 +148,7 @@ static int memcpy_real_user(void __user *dest, unsigned long src, size_t count) ...@@ -175,7 +148,7 @@ static int memcpy_real_user(void __user *dest, unsigned long src, size_t count)
while (offs < count) { while (offs < count) {
size = min(sizeof(buf), count - offs); size = min(sizeof(buf), count - offs);
if (memcpy_real(buf, src + offs, size)) if (memcpy_real(buf, (void *) src + offs, size))
return -EFAULT; return -EFAULT;
if (copy_to_user(dest + offs, buf, size)) if (copy_to_user(dest + offs, buf, size))
return -EFAULT; return -EFAULT;
...@@ -663,7 +636,7 @@ static int __init zcore_reipl_init(void) ...@@ -663,7 +636,7 @@ static int __init zcore_reipl_init(void)
if (ipib_info.ipib < ZFCPDUMP_HSA_SIZE) if (ipib_info.ipib < ZFCPDUMP_HSA_SIZE)
rc = memcpy_hsa_kernel(ipl_block, ipib_info.ipib, PAGE_SIZE); rc = memcpy_hsa_kernel(ipl_block, ipib_info.ipib, PAGE_SIZE);
else else
rc = memcpy_real(ipl_block, ipib_info.ipib, PAGE_SIZE); rc = memcpy_real(ipl_block, (void *) ipib_info.ipib, PAGE_SIZE);
if (rc) { if (rc) {
free_page((unsigned long) ipl_block); free_page((unsigned long) ipl_block);
return rc; return rc;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment