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 */
__u32 ipib_checksum; /* 0x0e08 */
/*
* 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 */
__u64 vmcore_info; /* 0x0e0c */
__u8 pad_0x0e14[0x0e18-0x0e14]; /* 0x0e14 */
__u64 os_info; /* 0x0e18 */
__u8 pad_0x0e20[0x0f00-0x0e20]; /* 0x0e20 */

View file

@ -348,4 +348,14 @@ extern void (*s390_base_ext_handler_fn)(void);
".previous\n"
#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 */

View file

@ -381,8 +381,6 @@ clear_user(void __user *to, unsigned long 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_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_RESTART_STACK, offsetof(struct _lowcore, restart_stack));
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_INT_CLOCK, offsetof(struct _lowcore, int_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
ahi %r15,-STACK_FRAME_OVERHEAD # create stack frame on stack
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
jm 1f # negative -> skip source stop
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
aghi %r15,-STACK_FRAME_OVERHEAD # create stack frame on stack
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
jm 1f # negative -> skip source stop
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)
{
struct {
void *addr;
__u32 csum;
} __packed ipib;
unsigned long ipib = (unsigned long) &reipl_block_actual;
unsigned int csum;
ipib.csum = csum_partial(reipl_block_actual,
reipl_block_actual->hdr.len, 0);
ipib.addr = reipl_block_actual;
memcpy_absolute(&S390_lowcore.ipib, &ipib, sizeof(ipib));
csum = csum_partial(reipl_block_actual, reipl_block_actual->hdr.len, 0);
mem_assign_absolute(S390_lowcore.ipib, ipib);
mem_assign_absolute(S390_lowcore.ipib_checksum, csum);
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.magic = OS_INFO_MAGIC;
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

View file

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

View file

@ -273,26 +273,24 @@ static void pcpu_delegate(struct pcpu *pcpu, void (*func)(void *),
void *data, unsigned long stack)
{
struct _lowcore *lc = lowcore_ptr[pcpu - pcpu_devices];
struct {
unsigned long stack;
void *func;
void *data;
unsigned long source;
} restart = { stack, func, data, stap() };
unsigned long source_cpu = stap();
__load_psw_mask(psw_kernel_bits);
if (pcpu->address == restart.source)
if (pcpu->address == source_cpu)
func(data); /* should not return */
/* Stop target cpu (if func returns this stops the current cpu). */
pcpu_sigp_retry(pcpu, SIGP_STOP, 0);
/* 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(
"0: sigp 0,%0,%2 # sigp restart to target cpu\n"
" brc 2,0b # busy, try again\n"
"1: sigp 0,%1,%3 # sigp stop to current cpu\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)
: "0", "1", "cc");
for (;;) ;