aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Holzheu <holzheu@linux.vnet.ibm.com>2010-03-24 06:49:50 -0400
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2010-03-24 06:49:53 -0400
commit92fe31329cb3a2b02f1c7616965872d6a34bcf08 (patch)
tree678d046b5864d302e424a2377cf1974b95b1d1f8
parentae6be51ed01d6c4aaf249a207b4434bc7785853b (diff)
[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: Michael Holzheu <holzheu@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/include/asm/system.h1
-rw-r--r--arch/s390/kernel/smp.c6
-rw-r--r--arch/s390/mm/maccess.c26
-rw-r--r--drivers/s390/char/zcore.c31
4 files changed, 32 insertions, 32 deletions
diff --git a/arch/s390/include/asm/system.h b/arch/s390/include/asm/system.h
index 67ee6c3c6bb3..12be42baa055 100644
--- a/arch/s390/include/asm/system.h
+++ b/arch/s390/include/asm/system.h
@@ -110,6 +110,7 @@ extern void pfault_fini(void);
110#endif /* CONFIG_PFAULT */ 110#endif /* CONFIG_PFAULT */
111 111
112extern void cmma_init(void); 112extern void cmma_init(void);
113extern int memcpy_real(void *, void *, size_t);
113 114
114#define finish_arch_switch(prev) do { \ 115#define finish_arch_switch(prev) do { \
115 set_fs(current->thread.mm_segment); \ 116 set_fs(current->thread.mm_segment); \
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 29f65bce55e1..d7d24fc3d6b7 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -292,9 +292,9 @@ static void __init smp_get_save_area(unsigned int cpu, unsigned int phy_cpu)
292 zfcpdump_save_areas[cpu] = kmalloc(sizeof(struct save_area), GFP_KERNEL); 292 zfcpdump_save_areas[cpu] = kmalloc(sizeof(struct save_area), GFP_KERNEL);
293 while (raw_sigp(phy_cpu, sigp_stop_and_store_status) == sigp_busy) 293 while (raw_sigp(phy_cpu, sigp_stop_and_store_status) == sigp_busy)
294 cpu_relax(); 294 cpu_relax();
295 memcpy(zfcpdump_save_areas[cpu], 295 memcpy_real(zfcpdump_save_areas[cpu],
296 (void *)(unsigned long) store_prefix() + SAVE_AREA_BASE, 296 (void *)(unsigned long) store_prefix() + SAVE_AREA_BASE,
297 sizeof(struct save_area)); 297 sizeof(struct save_area));
298} 298}
299 299
300struct save_area *zfcpdump_save_areas[NR_CPUS + 1]; 300struct save_area *zfcpdump_save_areas[NR_CPUS + 1];
diff --git a/arch/s390/mm/maccess.c b/arch/s390/mm/maccess.c
index 81756271dc44..a8c2af8c650f 100644
--- a/arch/s390/mm/maccess.c
+++ b/arch/s390/mm/maccess.c
@@ -59,3 +59,29 @@ long probe_kernel_write(void *dst, void *src, size_t size)
59 } 59 }
60 return copied < 0 ? -EFAULT : 0; 60 return copied < 0 ? -EFAULT : 0;
61} 61}
62
63int memcpy_real(void *dest, void *src, size_t count)
64{
65 register unsigned long _dest asm("2") = (unsigned long) dest;
66 register unsigned long _len1 asm("3") = (unsigned long) count;
67 register unsigned long _src asm("4") = (unsigned long) src;
68 register unsigned long _len2 asm("5") = (unsigned long) count;
69 unsigned long flags;
70 int rc = -EFAULT;
71
72 if (!count)
73 return 0;
74 flags = __raw_local_irq_stnsm(0xf8UL);
75 asm volatile (
76 "0: mvcle %1,%2,0x0\n"
77 "1: jo 0b\n"
78 " lhi %0,0x0\n"
79 "2:\n"
80 EX_TABLE(1b,2b)
81 : "+d" (rc), "+d" (_dest), "+d" (_src), "+d" (_len1),
82 "+d" (_len2), "=m" (*((long *) dest))
83 : "m" (*((long *) src))
84 : "cc", "memory");
85 __raw_local_irq_ssm(flags);
86 return rc;
87}
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index 3438658b66b7..3166d85914f2 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -141,33 +141,6 @@ static int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count)
141 return memcpy_hsa(dest, src, count, TO_KERNEL); 141 return memcpy_hsa(dest, src, count, TO_KERNEL);
142} 142}
143 143
144static int memcpy_real(void *dest, unsigned long src, size_t count)
145{
146 unsigned long flags;
147 int rc = -EFAULT;
148 register unsigned long _dest asm("2") = (unsigned long) dest;
149 register unsigned long _len1 asm("3") = (unsigned long) count;
150 register unsigned long _src asm("4") = src;
151 register unsigned long _len2 asm("5") = (unsigned long) count;
152
153 if (count == 0)
154 return 0;
155 flags = __raw_local_irq_stnsm(0xf8UL); /* switch to real mode */
156 asm volatile (
157 "0: mvcle %1,%2,0x0\n"
158 "1: jo 0b\n"
159 " lhi %0,0x0\n"
160 "2:\n"
161 EX_TABLE(1b,2b)
162 : "+d" (rc), "+d" (_dest), "+d" (_src), "+d" (_len1),
163 "+d" (_len2), "=m" (*((long*)dest))
164 : "m" (*((long*)src))
165 : "cc", "memory");
166 __raw_local_irq_ssm(flags);
167
168 return rc;
169}
170
171static int memcpy_real_user(void __user *dest, unsigned long src, size_t count) 144static int memcpy_real_user(void __user *dest, unsigned long src, size_t count)
172{ 145{
173 static char buf[4096]; 146 static char buf[4096];
@@ -175,7 +148,7 @@ static int memcpy_real_user(void __user *dest, unsigned long src, size_t count)
175 148
176 while (offs < count) { 149 while (offs < count) {
177 size = min(sizeof(buf), count - offs); 150 size = min(sizeof(buf), count - offs);
178 if (memcpy_real(buf, src + offs, size)) 151 if (memcpy_real(buf, (void *) src + offs, size))
179 return -EFAULT; 152 return -EFAULT;
180 if (copy_to_user(dest + offs, buf, size)) 153 if (copy_to_user(dest + offs, buf, size))
181 return -EFAULT; 154 return -EFAULT;
@@ -663,7 +636,7 @@ static int __init zcore_reipl_init(void)
663 if (ipib_info.ipib < ZFCPDUMP_HSA_SIZE) 636 if (ipib_info.ipib < ZFCPDUMP_HSA_SIZE)
664 rc = memcpy_hsa_kernel(ipl_block, ipib_info.ipib, PAGE_SIZE); 637 rc = memcpy_hsa_kernel(ipl_block, ipib_info.ipib, PAGE_SIZE);
665 else 638 else
666 rc = memcpy_real(ipl_block, ipib_info.ipib, PAGE_SIZE); 639 rc = memcpy_real(ipl_block, (void *) ipib_info.ipib, PAGE_SIZE);
667 if (rc) { 640 if (rc) {
668 free_page((unsigned long) ipl_block); 641 free_page((unsigned long) ipl_block);
669 return rc; 642 return rc;