diff options
Diffstat (limited to 'purgatory/arch/s390')
-rw-r--r-- | purgatory/arch/s390/Makefile | 10 | ||||
-rw-r--r-- | purgatory/arch/s390/console-s390.c | 14 | ||||
-rw-r--r-- | purgatory/arch/s390/purgatory-s390.c | 93 | ||||
-rw-r--r-- | purgatory/arch/s390/setup-s390.S | 47 |
4 files changed, 164 insertions, 0 deletions
diff --git a/purgatory/arch/s390/Makefile b/purgatory/arch/s390/Makefile new file mode 100644 index 0000000..c94cc3c --- /dev/null +++ b/purgatory/arch/s390/Makefile @@ -0,0 +1,10 @@ +# +# Purgatory s390 +# + +s390_PURGATORY_SRCS += purgatory/arch/s390/console-s390.c +s390_PURGATORY_SRCS += purgatory/arch/s390/setup-s390.S +s390_PURGATORY_SRCS += purgatory/arch/s390/purgatory-s390.c + +dist += purgatory/arch/s390/Makefile $(s390_PURGATORY_SRCS) + diff --git a/purgatory/arch/s390/console-s390.c b/purgatory/arch/s390/console-s390.c new file mode 100644 index 0000000..fe4bd91 --- /dev/null +++ b/purgatory/arch/s390/console-s390.c @@ -0,0 +1,14 @@ +/* + * S390 console code (currently not implemented) + * + * Copyright IBM Corp. 2011 + * + * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com> + */ + +#include <purgatory.h> +#include "unused.h" + +void putchar(int UNUSED(ch)) +{ +} diff --git a/purgatory/arch/s390/purgatory-s390.c b/purgatory/arch/s390/purgatory-s390.c new file mode 100644 index 0000000..f438cf6 --- /dev/null +++ b/purgatory/arch/s390/purgatory-s390.c @@ -0,0 +1,93 @@ +/* + * S390 purgatory + * + * Copyright IBM Corp. 2011 + * + * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com> + */ + +#include <stdint.h> +#include <stddef.h> +#include <string.h> +#include "../../../kexec/kexec-sha256.h" + +#define MIN(x, y) ((x) < (y) ? (x) : (y)) +#define MAX(x, y) ((x) > (y) ? (x) : (y)) + +extern struct sha256_region sha256_regions[SHA256_REGIONS]; + +unsigned long crash_base = (unsigned long) -1; +unsigned long crash_size = (unsigned long) -1; + +/* + * Implement memcpy using the mvcle instruction + */ +static void memcpy_fast(void *target, void *src, unsigned long size) +{ + register unsigned long __target asm("2") = (unsigned long) target; + register unsigned long __size1 asm("3") = size; + register unsigned long __src asm("4") = (unsigned long) src; + register unsigned long __size2 asm("5") = size; + + asm volatile ( + "0: mvcle %0,%2,0\n" + " jo 0b\n" + : "+d" (__target), "+d" (__size1), "+d" (__src), "+d" (__size2) + : + : "cc", "memory" + ); +} + +/* + * Swap memory areas + */ +static void memswap(void *addr1, void *addr2, unsigned long size) +{ + unsigned long off, copy_len; + static char buf[1024]; + + for (off = 0; off < size; off += sizeof(buf)) { + copy_len = MIN(size - off, sizeof(buf)); + memcpy_fast(buf, (void *) addr2 + off, copy_len); + memcpy_fast(addr2 + off, addr1 + off, copy_len); + memcpy_fast(addr1 + off, buf, copy_len); + } +} + +/* + * Nothing to do + */ +void setup_arch(void) +{ +} + +/* + * Do swap of [crash base - crash base + size] with [0 - crash size] + * + * We swap all kexec segments except of purgatory. The rest is copied + * from [0 - crash size] to [crash base - crash base + size]. + * We use [0x2000 - 0x10000] for purgatory. This area is never used + * by s390 Linux kernels. + * + * This functions assumes that the sha256_regions[] is sorted. + */ +void post_verification_setup_arch(void) +{ + unsigned long start, len, last = crash_base + 0x10000; + struct sha256_region *ptr, *end; + + end = &sha256_regions[sizeof(sha256_regions)/sizeof(sha256_regions[0])]; + for (ptr = sha256_regions; ptr < end; ptr++) { + if (!ptr->start) + continue; + start = MAX(ptr->start, crash_base + 0x10000); + len = ptr->len - (start - ptr->start); + memcpy_fast((void *) last, (void *) last - crash_base, + start - last); + memswap((void *) start - crash_base, (void *) start, len); + last = start + len; + } + memcpy_fast((void *) last, (void *) last - crash_base, + crash_base + crash_size - last); + memcpy_fast((void *) crash_base, (void *) 0, 0x2000); +} diff --git a/purgatory/arch/s390/setup-s390.S b/purgatory/arch/s390/setup-s390.S new file mode 100644 index 0000000..215478a --- /dev/null +++ b/purgatory/arch/s390/setup-s390.S @@ -0,0 +1,47 @@ +/* + * Purgatory setup code + * + * Copyright IBM Corp. 2011 + * + * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com> + */ + + .text + .globl purgatory_start + .balign 16 +purgatory_start: +#ifdef __s390x__ + larl %r5,gprs_save_area + stmg %r6,%r15,0(%r5) + larl %r15,lstack_end + aghi %r15,-160 + + cghi %r2,0 + je verify_checksums + + brasl %r14,purgatory + larl %r14,kdump_psw + lpswe 0(%r14) + +verify_checksums: + brasl %r14,verify_sha256_digest + larl %r5,gprs_save_area + lmg %r6,%r15,0(%r5) + br %r14 + .section ".data" + .balign 16 +kdump_psw: + .quad 0x0000000180000000 + .quad 0x0000000000010010 + + .bss +gprs_save_area: + .fill 80 + + .balign 4096 +lstack: + .skip 4096 +lstack_end: +#else +0: j 0 +#endif |