s390/smp: make absolute lowcore / cpu restart parameter accesses more robust
authorHeiko Carstens <heiko.carstens@de.ibm.com>
Tue, 5 Jun 2012 07:59:52 +0000 (09:59 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Thu, 14 Jun 2012 07:09:02 +0000 (09:09 +0200)
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>
arch/s390/include/asm/lowcore.h
arch/s390/include/asm/processor.h
arch/s390/include/asm/uaccess.h
arch/s390/kernel/asm-offsets.c
arch/s390/kernel/entry.S
arch/s390/kernel/entry64.S
arch/s390/kernel/ipl.c
arch/s390/kernel/os_info.c
arch/s390/kernel/setup.c
arch/s390/kernel/smp.c

index 47853debb3b9de98eed2a3ac70a0cb95c3a19412..a47c6e221a9528c190a5ae979bdd3dadd4390850 100644 (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 */
index 20d0585cf905675422ad406d406401eba2bd6f82..f1700c5c88847965fe953ae81267f95f15b6214c 100644 (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           */
index 1f3a79bcd262722e251d575009cec172a9c77509..7e7285179aadaabed883788fabeb2e568cf8aa2f 100644 (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);
 
index 83e6edf5cf17345d592636a49229394777600c82..0e974ddd156be9bba82e52718c20a2981b9e88a7 100644 (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));
index 3787f9e6907aad3ffe7564b0886517d28dd9fe89..4ea53cd7c8c35e314cd9ab6926d46a4417ebef38 100644 (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
index d5f02e480e5102f5dd675faa594eb4cbc6acb38d..2813e831ba3284b884ead5801d57dfbdcc6c8472 100644 (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
index 2f6cfd460cb6ad5a04fd033ea7f515b49ba3e487..25241cd8ddd830de177c1bd95864cbe847ca87d5 100644 (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;
-
-       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));
+       unsigned long ipib = (unsigned long) &reipl_block_actual;
+       unsigned int csum;
+
+       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);
 }
 
index 95fa5ac6c4cedbf6d287ca25708b906cb1f35c4c..46480d81df00029aa395f39861a7d40dd7f49bde 100644 (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
index 489d1d8d96b068f63b61886ee3c55d50f52b3913..49158cb19274d95fbf6d2965aca58ad91f813938 100644 (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
 }
 
index e01408429ad6ab60101c8ed298bd7a0716b56cb9..dc602a61233f8227979287a64ca2d89fc1ce2ebe 100644 (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 (;;) ;