forked from luck/tmp_suning_uos_patched
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:
parent
72f6e3a8bc
commit
fbe765680d
|
@ -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 */
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 (;;) ;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user