summaryrefslogtreecommitdiffstats
path: root/purgatory/arch/s390
diff options
context:
space:
mode:
Diffstat (limited to 'purgatory/arch/s390')
-rw-r--r--purgatory/arch/s390/Makefile10
-rw-r--r--purgatory/arch/s390/console-s390.c14
-rw-r--r--purgatory/arch/s390/purgatory-s390.c93
-rw-r--r--purgatory/arch/s390/setup-s390.S47
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