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>
This commit is contained in:
Heiko Carstens 2012-06-05 09:59:52 +02:00 committed by Martin Schwidefsky
parent 72f6e3a8bc
commit fbe765680d
10 changed files with 38 additions and 35 deletions

View File

@ -302,12 +302,7 @@ struct _lowcore {
*/ */
__u64 ipib; /* 0x0e00 */ __u64 ipib; /* 0x0e00 */
__u32 ipib_checksum; /* 0x0e08 */ __u32 ipib_checksum; /* 0x0e08 */
/* __u64 vmcore_info; /* 0x0e0c */
* Because the vmcore_info pointer is not 8 byte aligned it never
* should not be accessed directly. For accessing the pointer, first
* copy it to a local pointer variable.
*/
__u8 vmcore_info[8]; /* 0x0e0c */
__u8 pad_0x0e14[0x0e18-0x0e14]; /* 0x0e14 */ __u8 pad_0x0e14[0x0e18-0x0e14]; /* 0x0e14 */
__u64 os_info; /* 0x0e18 */ __u64 os_info; /* 0x0e18 */
__u8 pad_0x0e20[0x0f00-0x0e20]; /* 0x0e20 */ __u8 pad_0x0e20[0x0f00-0x0e20]; /* 0x0e20 */

View File

@ -348,4 +348,14 @@ extern void (*s390_base_ext_handler_fn)(void);
".previous\n" ".previous\n"
#endif #endif
extern int memcpy_real(void *, void *, size_t);
extern void memcpy_absolute(void *, void *, size_t);
#define mem_assign_absolute(dest, val) { \
__typeof__(dest) __tmp = (val); \
\
BUILD_BUG_ON(sizeof(__tmp) != sizeof(val)); \
memcpy_absolute(&(dest), &__tmp, sizeof(__tmp)); \
}
#endif /* __ASM_S390_PROCESSOR_H */ #endif /* __ASM_S390_PROCESSOR_H */

View File

@ -381,8 +381,6 @@ clear_user(void __user *to, unsigned long n)
return n; return n;
} }
extern int memcpy_real(void *, void *, size_t);
extern void memcpy_absolute(void *, void *, size_t);
extern int copy_to_user_real(void __user *dest, void *src, size_t count); extern int copy_to_user_real(void __user *dest, void *src, size_t count);
extern int copy_from_user_real(void *dest, void __user *src, size_t count); extern int copy_from_user_real(void *dest, void __user *src, size_t count);

View File

@ -131,6 +131,8 @@ int main(void)
DEFINE(__LC_PANIC_STACK, offsetof(struct _lowcore, panic_stack)); DEFINE(__LC_PANIC_STACK, offsetof(struct _lowcore, panic_stack));
DEFINE(__LC_RESTART_STACK, offsetof(struct _lowcore, restart_stack)); DEFINE(__LC_RESTART_STACK, offsetof(struct _lowcore, restart_stack));
DEFINE(__LC_RESTART_FN, offsetof(struct _lowcore, restart_fn)); DEFINE(__LC_RESTART_FN, offsetof(struct _lowcore, restart_fn));
DEFINE(__LC_RESTART_DATA, offsetof(struct _lowcore, restart_data));
DEFINE(__LC_RESTART_SOURCE, offsetof(struct _lowcore, restart_source));
DEFINE(__LC_USER_ASCE, offsetof(struct _lowcore, user_asce)); DEFINE(__LC_USER_ASCE, offsetof(struct _lowcore, user_asce));
DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock)); DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock));
DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock)); DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock));

View File

@ -724,7 +724,9 @@ ENTRY(restart_int_handler)
mvc __PT_PSW(8,%r15),__LC_RST_OLD_PSW # store restart old psw mvc __PT_PSW(8,%r15),__LC_RST_OLD_PSW # store restart old psw
ahi %r15,-STACK_FRAME_OVERHEAD # create stack frame on stack ahi %r15,-STACK_FRAME_OVERHEAD # create stack frame on stack
xc 0(STACK_FRAME_OVERHEAD,%r15),0(%r15) xc 0(STACK_FRAME_OVERHEAD,%r15),0(%r15)
lm %r1,%r3,__LC_RESTART_FN # load fn, parm & source cpu l %r1,__LC_RESTART_FN # load fn, parm & source cpu
l %r2,__LC_RESTART_DATA
l %r3,__LC_RESTART_SOURCE
ltr %r3,%r3 # test source cpu address ltr %r3,%r3 # test source cpu address
jm 1f # negative -> skip source stop jm 1f # negative -> skip source stop
0: sigp %r4,%r3,SIGP_SENSE # sigp sense to source cpu 0: sigp %r4,%r3,SIGP_SENSE # sigp sense to source cpu

View File

@ -751,7 +751,9 @@ ENTRY(restart_int_handler)
mvc __PT_PSW(16,%r15),__LC_RST_OLD_PSW # store restart old psw mvc __PT_PSW(16,%r15),__LC_RST_OLD_PSW # store restart old psw
aghi %r15,-STACK_FRAME_OVERHEAD # create stack frame on stack aghi %r15,-STACK_FRAME_OVERHEAD # create stack frame on stack
xc 0(STACK_FRAME_OVERHEAD,%r15),0(%r15) xc 0(STACK_FRAME_OVERHEAD,%r15),0(%r15)
lmg %r1,%r3,__LC_RESTART_FN # load fn, parm & source cpu lg %r1,__LC_RESTART_FN # load fn, parm & source cpu
lg %r2,__LC_RESTART_DATA
lg %r3,__LC_RESTART_SOURCE
ltgr %r3,%r3 # test source cpu address ltgr %r3,%r3 # test source cpu address
jm 1f # negative -> skip source stop jm 1f # negative -> skip source stop
0: sigp %r4,%r3,SIGP_SENSE # sigp sense to source cpu 0: sigp %r4,%r3,SIGP_SENSE # sigp sense to source cpu

View File

@ -1528,15 +1528,12 @@ static struct shutdown_action __refdata dump_action = {
static void dump_reipl_run(struct shutdown_trigger *trigger) static void dump_reipl_run(struct shutdown_trigger *trigger)
{ {
struct { unsigned long ipib = (unsigned long) &reipl_block_actual;
void *addr; unsigned int csum;
__u32 csum;
} __packed ipib;
ipib.csum = csum_partial(reipl_block_actual, csum = csum_partial(reipl_block_actual, reipl_block_actual->hdr.len, 0);
reipl_block_actual->hdr.len, 0); mem_assign_absolute(S390_lowcore.ipib, ipib);
ipib.addr = reipl_block_actual; mem_assign_absolute(S390_lowcore.ipib_checksum, csum);
memcpy_absolute(&S390_lowcore.ipib, &ipib, sizeof(ipib));
dump_run(trigger); dump_run(trigger);
} }

View File

@ -60,7 +60,7 @@ void __init os_info_init(void)
os_info.version_minor = OS_INFO_VERSION_MINOR; os_info.version_minor = OS_INFO_VERSION_MINOR;
os_info.magic = OS_INFO_MAGIC; os_info.magic = OS_INFO_MAGIC;
os_info.csum = os_info_csum(&os_info); os_info.csum = os_info_csum(&os_info);
memcpy_absolute(&S390_lowcore.os_info, &ptr, sizeof(ptr)); mem_assign_absolute(S390_lowcore.os_info, (unsigned long) ptr);
} }
#ifdef CONFIG_CRASH_DUMP #ifdef CONFIG_CRASH_DUMP

View File

@ -430,10 +430,11 @@ static void __init setup_lowcore(void)
lc->restart_source = -1UL; lc->restart_source = -1UL;
/* Setup absolute zero lowcore */ /* Setup absolute zero lowcore */
memcpy_absolute(&S390_lowcore.restart_stack, &lc->restart_stack, mem_assign_absolute(S390_lowcore.restart_stack, lc->restart_stack);
4 * sizeof(unsigned long)); mem_assign_absolute(S390_lowcore.restart_fn, lc->restart_fn);
memcpy_absolute(&S390_lowcore.restart_psw, &lc->restart_psw, mem_assign_absolute(S390_lowcore.restart_data, lc->restart_data);
sizeof(lc->restart_psw)); mem_assign_absolute(S390_lowcore.restart_source, lc->restart_source);
mem_assign_absolute(S390_lowcore.restart_psw, lc->restart_psw);
set_prefix((u32)(unsigned long) lc); set_prefix((u32)(unsigned long) lc);
lowcore_ptr[0] = lc; lowcore_ptr[0] = lc;
@ -598,9 +599,7 @@ static void __init setup_memory_end(void)
static void __init setup_vmcoreinfo(void) static void __init setup_vmcoreinfo(void)
{ {
#ifdef CONFIG_KEXEC #ifdef CONFIG_KEXEC
unsigned long ptr = paddr_vmcoreinfo_note(); mem_assign_absolute(S390_lowcore.vmcore_info, paddr_vmcoreinfo_note());
memcpy_absolute(&S390_lowcore.vmcore_info, &ptr, sizeof(ptr));
#endif #endif
} }

View File

@ -273,26 +273,24 @@ static void pcpu_delegate(struct pcpu *pcpu, void (*func)(void *),
void *data, unsigned long stack) void *data, unsigned long stack)
{ {
struct _lowcore *lc = lowcore_ptr[pcpu - pcpu_devices]; struct _lowcore *lc = lowcore_ptr[pcpu - pcpu_devices];
struct { unsigned long source_cpu = stap();
unsigned long stack;
void *func;
void *data;
unsigned long source;
} restart = { stack, func, data, stap() };
__load_psw_mask(psw_kernel_bits); __load_psw_mask(psw_kernel_bits);
if (pcpu->address == restart.source) if (pcpu->address == source_cpu)
func(data); /* should not return */ func(data); /* should not return */
/* Stop target cpu (if func returns this stops the current cpu). */ /* Stop target cpu (if func returns this stops the current cpu). */
pcpu_sigp_retry(pcpu, SIGP_STOP, 0); pcpu_sigp_retry(pcpu, SIGP_STOP, 0);
/* Restart func on the target cpu and stop the current cpu. */ /* Restart func on the target cpu and stop the current cpu. */
memcpy_absolute(&lc->restart_stack, &restart, sizeof(restart)); mem_assign_absolute(lc->restart_stack, stack);
mem_assign_absolute(lc->restart_fn, (unsigned long) func);
mem_assign_absolute(lc->restart_data, (unsigned long) data);
mem_assign_absolute(lc->restart_source, source_cpu);
asm volatile( asm volatile(
"0: sigp 0,%0,%2 # sigp restart to target cpu\n" "0: sigp 0,%0,%2 # sigp restart to target cpu\n"
" brc 2,0b # busy, try again\n" " brc 2,0b # busy, try again\n"
"1: sigp 0,%1,%3 # sigp stop to current cpu\n" "1: sigp 0,%1,%3 # sigp stop to current cpu\n"
" brc 2,1b # busy, try again\n" " brc 2,1b # busy, try again\n"
: : "d" (pcpu->address), "d" (restart.source), : : "d" (pcpu->address), "d" (source_cpu),
"K" (SIGP_RESTART), "K" (SIGP_STOP) "K" (SIGP_RESTART), "K" (SIGP_STOP)
: "0", "1", "cc"); : "0", "1", "cc");
for (;;) ; for (;;) ;