diff options
author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2012-06-05 03:59:52 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2012-06-14 03:09:02 -0400 |
commit | fbe765680d1fe9d08187ea4dad5041a7955a2c3a (patch) | |
tree | cfa5ba11106bb5535552cf6b29ff6aa81f32c606 | |
parent | 72f6e3a8bc956fddf6e004ae9b804977d1458e77 (diff) |
s390/smp: make absolute lowcore / cpu restart parameter accesses more robust
Setting the cpu restart parameters is done in three different fashions:
- directly setting the four parameters individually
- copying the four parameters with memcpy (using 4 * sizeof(long))
- copying the four parameters using a private structure
In addition code in entry*.S relies on a certain order of the restart
members of struct _lowcore.
Make all of this more robust to future changes by adding a
mem_absolute_assign(dest, val) define, which assigns val to dest
using absolute addressing mode. Also the load multiple instructions
in entry*.S have been split into separate load instruction so the
order of the struct _lowcore members doesn't matter anymore.
In addition move the prototypes of memcpy_real/absolute from uaccess.h
to processor.h. These memcpy* variants are not related to uaccess at all.
string.h doesn't seem to match as well, so lets use processor.h.
Also replace the eight byte array in struct _lowcore which represents a
misaliged u64 with a u64. The compiler will always create code that
handles the misaligned u64 correctly.
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | arch/s390/include/asm/lowcore.h | 7 | ||||
-rw-r--r-- | arch/s390/include/asm/processor.h | 10 | ||||
-rw-r--r-- | arch/s390/include/asm/uaccess.h | 2 | ||||
-rw-r--r-- | arch/s390/kernel/asm-offsets.c | 2 | ||||
-rw-r--r-- | arch/s390/kernel/entry.S | 4 | ||||
-rw-r--r-- | arch/s390/kernel/entry64.S | 4 | ||||
-rw-r--r-- | arch/s390/kernel/ipl.c | 15 | ||||
-rw-r--r-- | arch/s390/kernel/os_info.c | 2 | ||||
-rw-r--r-- | arch/s390/kernel/setup.c | 13 | ||||
-rw-r--r-- | arch/s390/kernel/smp.c | 16 |
10 files changed, 39 insertions, 36 deletions
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index 47853debb3b9..a47c6e221a95 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h | |||
@@ -302,12 +302,7 @@ struct _lowcore { | |||
302 | */ | 302 | */ |
303 | __u64 ipib; /* 0x0e00 */ | 303 | __u64 ipib; /* 0x0e00 */ |
304 | __u32 ipib_checksum; /* 0x0e08 */ | 304 | __u32 ipib_checksum; /* 0x0e08 */ |
305 | /* | 305 | __u64 vmcore_info; /* 0x0e0c */ |
306 | * Because the vmcore_info pointer is not 8 byte aligned it never | ||
307 | * should not be accessed directly. For accessing the pointer, first | ||
308 | * copy it to a local pointer variable. | ||
309 | */ | ||
310 | __u8 vmcore_info[8]; /* 0x0e0c */ | ||
311 | __u8 pad_0x0e14[0x0e18-0x0e14]; /* 0x0e14 */ | 306 | __u8 pad_0x0e14[0x0e18-0x0e14]; /* 0x0e14 */ |
312 | __u64 os_info; /* 0x0e18 */ | 307 | __u64 os_info; /* 0x0e18 */ |
313 | __u8 pad_0x0e20[0x0f00-0x0e20]; /* 0x0e20 */ | 308 | __u8 pad_0x0e20[0x0f00-0x0e20]; /* 0x0e20 */ |
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index 20d0585cf905..f1700c5c8884 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h | |||
@@ -348,4 +348,14 @@ extern void (*s390_base_ext_handler_fn)(void); | |||
348 | ".previous\n" | 348 | ".previous\n" |
349 | #endif | 349 | #endif |
350 | 350 | ||
351 | extern int memcpy_real(void *, void *, size_t); | ||
352 | extern void memcpy_absolute(void *, void *, size_t); | ||
353 | |||
354 | #define mem_assign_absolute(dest, val) { \ | ||
355 | __typeof__(dest) __tmp = (val); \ | ||
356 | \ | ||
357 | BUILD_BUG_ON(sizeof(__tmp) != sizeof(val)); \ | ||
358 | memcpy_absolute(&(dest), &__tmp, sizeof(__tmp)); \ | ||
359 | } | ||
360 | |||
351 | #endif /* __ASM_S390_PROCESSOR_H */ | 361 | #endif /* __ASM_S390_PROCESSOR_H */ |
diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h index 1f3a79bcd262..7e7285179aad 100644 --- a/arch/s390/include/asm/uaccess.h +++ b/arch/s390/include/asm/uaccess.h | |||
@@ -381,8 +381,6 @@ clear_user(void __user *to, unsigned long n) | |||
381 | return n; | 381 | return n; |
382 | } | 382 | } |
383 | 383 | ||
384 | extern int memcpy_real(void *, void *, size_t); | ||
385 | extern void memcpy_absolute(void *, void *, size_t); | ||
386 | extern int copy_to_user_real(void __user *dest, void *src, size_t count); | 384 | extern int copy_to_user_real(void __user *dest, void *src, size_t count); |
387 | extern int copy_from_user_real(void *dest, void __user *src, size_t count); | 385 | extern int copy_from_user_real(void *dest, void __user *src, size_t count); |
388 | 386 | ||
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index 83e6edf5cf17..0e974ddd156b 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c | |||
@@ -131,6 +131,8 @@ int main(void) | |||
131 | DEFINE(__LC_PANIC_STACK, offsetof(struct _lowcore, panic_stack)); | 131 | DEFINE(__LC_PANIC_STACK, offsetof(struct _lowcore, panic_stack)); |
132 | DEFINE(__LC_RESTART_STACK, offsetof(struct _lowcore, restart_stack)); | 132 | DEFINE(__LC_RESTART_STACK, offsetof(struct _lowcore, restart_stack)); |
133 | DEFINE(__LC_RESTART_FN, offsetof(struct _lowcore, restart_fn)); | 133 | DEFINE(__LC_RESTART_FN, offsetof(struct _lowcore, restart_fn)); |
134 | DEFINE(__LC_RESTART_DATA, offsetof(struct _lowcore, restart_data)); | ||
135 | DEFINE(__LC_RESTART_SOURCE, offsetof(struct _lowcore, restart_source)); | ||
134 | DEFINE(__LC_USER_ASCE, offsetof(struct _lowcore, user_asce)); | 136 | DEFINE(__LC_USER_ASCE, offsetof(struct _lowcore, user_asce)); |
135 | DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock)); | 137 | DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock)); |
136 | DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock)); | 138 | DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock)); |
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 3787f9e6907a..4ea53cd7c8c3 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S | |||
@@ -724,7 +724,9 @@ ENTRY(restart_int_handler) | |||
724 | mvc __PT_PSW(8,%r15),__LC_RST_OLD_PSW # store restart old psw | 724 | mvc __PT_PSW(8,%r15),__LC_RST_OLD_PSW # store restart old psw |
725 | ahi %r15,-STACK_FRAME_OVERHEAD # create stack frame on stack | 725 | ahi %r15,-STACK_FRAME_OVERHEAD # create stack frame on stack |
726 | xc 0(STACK_FRAME_OVERHEAD,%r15),0(%r15) | 726 | xc 0(STACK_FRAME_OVERHEAD,%r15),0(%r15) |
727 | lm %r1,%r3,__LC_RESTART_FN # load fn, parm & source cpu | 727 | l %r1,__LC_RESTART_FN # load fn, parm & source cpu |
728 | l %r2,__LC_RESTART_DATA | ||
729 | l %r3,__LC_RESTART_SOURCE | ||
728 | ltr %r3,%r3 # test source cpu address | 730 | ltr %r3,%r3 # test source cpu address |
729 | jm 1f # negative -> skip source stop | 731 | jm 1f # negative -> skip source stop |
730 | 0: sigp %r4,%r3,SIGP_SENSE # sigp sense to source cpu | 732 | 0: sigp %r4,%r3,SIGP_SENSE # sigp sense to source cpu |
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index d5f02e480e51..2813e831ba32 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S | |||
@@ -751,7 +751,9 @@ ENTRY(restart_int_handler) | |||
751 | mvc __PT_PSW(16,%r15),__LC_RST_OLD_PSW # store restart old psw | 751 | mvc __PT_PSW(16,%r15),__LC_RST_OLD_PSW # store restart old psw |
752 | aghi %r15,-STACK_FRAME_OVERHEAD # create stack frame on stack | 752 | aghi %r15,-STACK_FRAME_OVERHEAD # create stack frame on stack |
753 | xc 0(STACK_FRAME_OVERHEAD,%r15),0(%r15) | 753 | xc 0(STACK_FRAME_OVERHEAD,%r15),0(%r15) |
754 | lmg %r1,%r3,__LC_RESTART_FN # load fn, parm & source cpu | 754 | lg %r1,__LC_RESTART_FN # load fn, parm & source cpu |
755 | lg %r2,__LC_RESTART_DATA | ||
756 | lg %r3,__LC_RESTART_SOURCE | ||
755 | ltgr %r3,%r3 # test source cpu address | 757 | ltgr %r3,%r3 # test source cpu address |
756 | jm 1f # negative -> skip source stop | 758 | jm 1f # negative -> skip source stop |
757 | 0: sigp %r4,%r3,SIGP_SENSE # sigp sense to source cpu | 759 | 0: sigp %r4,%r3,SIGP_SENSE # sigp sense to source cpu |
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 2f6cfd460cb6..25241cd8ddd8 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c | |||
@@ -1528,15 +1528,12 @@ static struct shutdown_action __refdata dump_action = { | |||
1528 | 1528 | ||
1529 | static void dump_reipl_run(struct shutdown_trigger *trigger) | 1529 | static void dump_reipl_run(struct shutdown_trigger *trigger) |
1530 | { | 1530 | { |
1531 | struct { | 1531 | unsigned long ipib = (unsigned long) &reipl_block_actual; |
1532 | void *addr; | 1532 | unsigned int csum; |
1533 | __u32 csum; | 1533 | |
1534 | } __packed ipib; | 1534 | csum = csum_partial(reipl_block_actual, reipl_block_actual->hdr.len, 0); |
1535 | 1535 | mem_assign_absolute(S390_lowcore.ipib, ipib); | |
1536 | ipib.csum = csum_partial(reipl_block_actual, | 1536 | mem_assign_absolute(S390_lowcore.ipib_checksum, csum); |
1537 | reipl_block_actual->hdr.len, 0); | ||
1538 | ipib.addr = reipl_block_actual; | ||
1539 | memcpy_absolute(&S390_lowcore.ipib, &ipib, sizeof(ipib)); | ||
1540 | dump_run(trigger); | 1537 | dump_run(trigger); |
1541 | } | 1538 | } |
1542 | 1539 | ||
diff --git a/arch/s390/kernel/os_info.c b/arch/s390/kernel/os_info.c index 95fa5ac6c4ce..46480d81df00 100644 --- a/arch/s390/kernel/os_info.c +++ b/arch/s390/kernel/os_info.c | |||
@@ -60,7 +60,7 @@ void __init os_info_init(void) | |||
60 | os_info.version_minor = OS_INFO_VERSION_MINOR; | 60 | os_info.version_minor = OS_INFO_VERSION_MINOR; |
61 | os_info.magic = OS_INFO_MAGIC; | 61 | os_info.magic = OS_INFO_MAGIC; |
62 | os_info.csum = os_info_csum(&os_info); | 62 | os_info.csum = os_info_csum(&os_info); |
63 | memcpy_absolute(&S390_lowcore.os_info, &ptr, sizeof(ptr)); | 63 | mem_assign_absolute(S390_lowcore.os_info, (unsigned long) ptr); |
64 | } | 64 | } |
65 | 65 | ||
66 | #ifdef CONFIG_CRASH_DUMP | 66 | #ifdef CONFIG_CRASH_DUMP |
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 489d1d8d96b0..49158cb19274 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -430,10 +430,11 @@ static void __init setup_lowcore(void) | |||
430 | lc->restart_source = -1UL; | 430 | lc->restart_source = -1UL; |
431 | 431 | ||
432 | /* Setup absolute zero lowcore */ | 432 | /* Setup absolute zero lowcore */ |
433 | memcpy_absolute(&S390_lowcore.restart_stack, &lc->restart_stack, | 433 | mem_assign_absolute(S390_lowcore.restart_stack, lc->restart_stack); |
434 | 4 * sizeof(unsigned long)); | 434 | mem_assign_absolute(S390_lowcore.restart_fn, lc->restart_fn); |
435 | memcpy_absolute(&S390_lowcore.restart_psw, &lc->restart_psw, | 435 | mem_assign_absolute(S390_lowcore.restart_data, lc->restart_data); |
436 | sizeof(lc->restart_psw)); | 436 | mem_assign_absolute(S390_lowcore.restart_source, lc->restart_source); |
437 | mem_assign_absolute(S390_lowcore.restart_psw, lc->restart_psw); | ||
437 | 438 | ||
438 | set_prefix((u32)(unsigned long) lc); | 439 | set_prefix((u32)(unsigned long) lc); |
439 | lowcore_ptr[0] = lc; | 440 | lowcore_ptr[0] = lc; |
@@ -598,9 +599,7 @@ static void __init setup_memory_end(void) | |||
598 | static void __init setup_vmcoreinfo(void) | 599 | static void __init setup_vmcoreinfo(void) |
599 | { | 600 | { |
600 | #ifdef CONFIG_KEXEC | 601 | #ifdef CONFIG_KEXEC |
601 | unsigned long ptr = paddr_vmcoreinfo_note(); | 602 | mem_assign_absolute(S390_lowcore.vmcore_info, paddr_vmcoreinfo_note()); |
602 | |||
603 | memcpy_absolute(&S390_lowcore.vmcore_info, &ptr, sizeof(ptr)); | ||
604 | #endif | 603 | #endif |
605 | } | 604 | } |
606 | 605 | ||
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index e01408429ad6..dc602a61233f 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -273,26 +273,24 @@ static void pcpu_delegate(struct pcpu *pcpu, void (*func)(void *), | |||
273 | void *data, unsigned long stack) | 273 | void *data, unsigned long stack) |
274 | { | 274 | { |
275 | struct _lowcore *lc = lowcore_ptr[pcpu - pcpu_devices]; | 275 | struct _lowcore *lc = lowcore_ptr[pcpu - pcpu_devices]; |
276 | struct { | 276 | unsigned long source_cpu = stap(); |
277 | unsigned long stack; | ||
278 | void *func; | ||
279 | void *data; | ||
280 | unsigned long source; | ||
281 | } restart = { stack, func, data, stap() }; | ||
282 | 277 | ||
283 | __load_psw_mask(psw_kernel_bits); | 278 | __load_psw_mask(psw_kernel_bits); |
284 | if (pcpu->address == restart.source) | 279 | if (pcpu->address == source_cpu) |
285 | func(data); /* should not return */ | 280 | func(data); /* should not return */ |
286 | /* Stop target cpu (if func returns this stops the current cpu). */ | 281 | /* Stop target cpu (if func returns this stops the current cpu). */ |
287 | pcpu_sigp_retry(pcpu, SIGP_STOP, 0); | 282 | pcpu_sigp_retry(pcpu, SIGP_STOP, 0); |
288 | /* Restart func on the target cpu and stop the current cpu. */ | 283 | /* Restart func on the target cpu and stop the current cpu. */ |
289 | memcpy_absolute(&lc->restart_stack, &restart, sizeof(restart)); | 284 | mem_assign_absolute(lc->restart_stack, stack); |
285 | mem_assign_absolute(lc->restart_fn, (unsigned long) func); | ||
286 | mem_assign_absolute(lc->restart_data, (unsigned long) data); | ||
287 | mem_assign_absolute(lc->restart_source, source_cpu); | ||
290 | asm volatile( | 288 | asm volatile( |
291 | "0: sigp 0,%0,%2 # sigp restart to target cpu\n" | 289 | "0: sigp 0,%0,%2 # sigp restart to target cpu\n" |
292 | " brc 2,0b # busy, try again\n" | 290 | " brc 2,0b # busy, try again\n" |
293 | "1: sigp 0,%1,%3 # sigp stop to current cpu\n" | 291 | "1: sigp 0,%1,%3 # sigp stop to current cpu\n" |
294 | " brc 2,1b # busy, try again\n" | 292 | " brc 2,1b # busy, try again\n" |
295 | : : "d" (pcpu->address), "d" (restart.source), | 293 | : : "d" (pcpu->address), "d" (source_cpu), |
296 | "K" (SIGP_RESTART), "K" (SIGP_STOP) | 294 | "K" (SIGP_RESTART), "K" (SIGP_STOP) |
297 | : "0", "1", "cc"); | 295 | : "0", "1", "cc"); |
298 | for (;;) ; | 296 | for (;;) ; |