summaryrefslogtreecommitdiffstats
path: root/purgatory/arch/ppc64
diff options
context:
space:
mode:
Diffstat (limited to 'purgatory/arch/ppc64')
-rw-r--r--purgatory/arch/ppc64/Makefile28
-rw-r--r--purgatory/arch/ppc64/console-ppc64.c45
-rw-r--r--purgatory/arch/ppc64/crashdump_backup.c39
-rw-r--r--purgatory/arch/ppc64/hvCall.S27
-rw-r--r--purgatory/arch/ppc64/hvCall.h8
-rw-r--r--purgatory/arch/ppc64/misc.S197
-rw-r--r--purgatory/arch/ppc64/ppc64_asm.h16
-rw-r--r--purgatory/arch/ppc64/purgatory-ppc64.c44
-rw-r--r--purgatory/arch/ppc64/purgatory-ppc64.h6
-rw-r--r--purgatory/arch/ppc64/v2wrap.S137
10 files changed, 547 insertions, 0 deletions
diff --git a/purgatory/arch/ppc64/Makefile b/purgatory/arch/ppc64/Makefile
new file mode 100644
index 0000000..8ca2719
--- /dev/null
+++ b/purgatory/arch/ppc64/Makefile
@@ -0,0 +1,28 @@
+#
+# Purgatory ppc64
+#
+
+ppc64_PURGATORY_SRCS += purgatory/arch/ppc64/v2wrap.S
+ppc64_PURGATORY_SRCS += purgatory/arch/ppc64/hvCall.S
+ppc64_PURGATORY_SRCS += purgatory/arch/ppc64/purgatory-ppc64.c
+ppc64_PURGATORY_SRCS += purgatory/arch/ppc64/console-ppc64.c
+ppc64_PURGATORY_SRCS += purgatory/arch/ppc64/crashdump_backup.c
+ppc64_PURGATORY_SRCS += purgatory/arch/ppc64/misc.S
+
+ppc64_PURGATORY_EXTRA_CFLAGS += -m64 -msoft-float \
+ -fno-exceptions
+ppc64_PURGATORY_EXTRA_ASFLAGS += -m64
+ifeq ($(SUBARCH),BE)
+ ppc64_PURGATORY_EXTRA_LDFLAGS += -melf64ppc
+ ppc64_PURGATORY_EXTRA_CFLAGS += -mcall-aixdesc
+ ppc64_PURGATORY_EXTRA_ASFLAGS += -mcall-aixdesc
+else
+ ppc64_PURGATORY_EXTRA_LDFLAGS += -melf64lppc
+ ppc64_PURGATORY_EXTRA_CFLAGS += -mlittle-endian
+ ppc64_PURGATORY_EXTRA_ASFLAGS += -mlittle-endian
+endif
+
+dist += purgatory/arch/ppc64/Makefile $(ppc64_PURGATORY_SRCS) \
+ purgatory/arch/ppc64/hvCall.h \
+ purgatory/arch/ppc64/ppc64_asm.h \
+ purgatory/arch/ppc64/purgatory-ppc64.h
diff --git a/purgatory/arch/ppc64/console-ppc64.c b/purgatory/arch/ppc64/console-ppc64.c
new file mode 100644
index 0000000..2403312
--- /dev/null
+++ b/purgatory/arch/ppc64/console-ppc64.c
@@ -0,0 +1,45 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Created by: Mohan Kumar M (mohan@in.ibm.com)
+ *
+ * Copyright (C) IBM Corporation, 2005. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <purgatory.h>
+#include "hvCall.h"
+#include <byteswap.h>
+#include <endian.h>
+#include <asm/byteorder.h>
+
+extern int debug;
+
+void putchar(int c)
+{
+ char buff[16] = "";
+ unsigned long *lbuf = (unsigned long *)buff;
+
+ if (!debug) /* running on non pseries */
+ return;
+
+ if (c == '\n')
+ putchar('\r');
+
+ buff[0] = c;
+ plpar_hcall_norets(H_PUT_TERM_CHAR, 0, 1,
+ __cpu_to_be64(lbuf[0]), __cpu_to_be64(lbuf[1]));
+ return;
+}
diff --git a/purgatory/arch/ppc64/crashdump_backup.c b/purgatory/arch/ppc64/crashdump_backup.c
new file mode 100644
index 0000000..7ba5aff
--- /dev/null
+++ b/purgatory/arch/ppc64/crashdump_backup.c
@@ -0,0 +1,39 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Created by: Mohan Kumar M (mohan@in.ibm.com)
+ *
+ * Copyright (C) IBM Corporation, 2005. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include "../../../kexec/arch/ppc64/crashdump-ppc64.h"
+
+extern unsigned long backup_start;
+
+/* Backup first 32KB of memory to backup region reserved by kexec */
+void crashdump_backup_memory(void)
+{
+ void *dest, *src;
+
+ src = (void *)BACKUP_SRC_START;
+
+ if (backup_start) {
+ dest = (void *)(backup_start);
+ memcpy(dest, src, BACKUP_SRC_SIZE);
+ }
+}
diff --git a/purgatory/arch/ppc64/hvCall.S b/purgatory/arch/ppc64/hvCall.S
new file mode 100644
index 0000000..a96c489
--- /dev/null
+++ b/purgatory/arch/ppc64/hvCall.S
@@ -0,0 +1,27 @@
+/*
+ * This file contains the generic function to perform a call to the
+ * pSeries LPAR hypervisor.
+ *
+ * Taken from linux/arch/powerpc/platforms/pseries/hvCall.S
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include "ppc64_asm.h"
+
+#define HVSC .long 0x44000022
+.text
+ .machine ppc64
+.globl DOTSYM(plpar_hcall_norets)
+DOTSYM(plpar_hcall_norets):
+ or 6,6,6 # medium low priority
+ mfcr 0
+ stw 0,8(1)
+
+ HVSC /* invoke the hypervisor */
+
+ lwz 0,8(1)
+ mtcrf 0xff,0
+ blr /* return r3 = status */
diff --git a/purgatory/arch/ppc64/hvCall.h b/purgatory/arch/ppc64/hvCall.h
new file mode 100644
index 0000000..187e24d
--- /dev/null
+++ b/purgatory/arch/ppc64/hvCall.h
@@ -0,0 +1,8 @@
+#ifndef HVCALL_H
+#define HVCALL_H
+
+#define H_PUT_TERM_CHAR 0x58
+
+long plpar_hcall_norets(unsigned long opcode, ...);
+
+#endif
diff --git a/purgatory/arch/ppc64/misc.S b/purgatory/arch/ppc64/misc.S
new file mode 100644
index 0000000..4ee188d
--- /dev/null
+++ b/purgatory/arch/ppc64/misc.S
@@ -0,0 +1,197 @@
+/*
+ * This is from linux/arch/powerpc/lib/crtsavres.S:
+ *
+ * Special support for eabi and SVR4
+ *
+ * Copyright (C) 1995, 1996, 1998, 2000, 2001 Free Software Foundation, Inc.
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ * Written By Michael Meissner
+ *
+ * Based on gcc/config/rs6000/crtsavres.asm from gcc
+ * 64 bit additions from reading the PPC elf64abi document.
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * In addition to the permissions in the GNU General Public License, the
+ * Free Software Foundation gives you unlimited permission to link the
+ * compiled version of this file with other programs, and to distribute
+ * those programs without any restriction coming from the use of this
+ * file. (The General Public License restrictions do apply in other
+ * respects; for example, they cover modification of the file, and
+ * distribution when not linked into another program.)
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * As a special exception, if you link this library with files
+ * compiled with GCC to produce an executable, this does not cause
+ * the resulting executable to be covered by the GNU General Public License.
+ * This exception does not however invalidate any other reasons why
+ * the executable file might be covered by the GNU General Public License.
+ */
+
+#define r0 0
+#define r1 1
+#define r2 2
+#define r3 3
+#define r4 4
+#define r5 5
+#define r6 6
+#define r7 7
+#define r8 8
+#define r9 9
+#define r10 10
+#define r11 11
+#define r12 12
+#define r13 13
+#define r14 14
+#define r15 15
+#define r16 16
+#define r17 17
+#define r18 18
+#define r19 19
+#define r20 20
+#define r21 21
+#define r22 22
+#define r23 23
+#define r24 24
+#define r25 25
+#define r26 26
+#define r27 27
+#define r28 28
+#define r29 29
+#define r30 30
+#define r31 31
+
+ .text
+
+.globl _savegpr0_14
+_savegpr0_14:
+ std r14,-144(r1)
+.globl _savegpr0_15
+_savegpr0_15:
+ std r15,-136(r1)
+.globl _savegpr0_16
+_savegpr0_16:
+ std r16,-128(r1)
+.globl _savegpr0_17
+_savegpr0_17:
+ std r17,-120(r1)
+.globl _savegpr0_18
+_savegpr0_18:
+ std r18,-112(r1)
+.globl _savegpr0_19
+_savegpr0_19:
+ std r19,-104(r1)
+.globl _savegpr0_20
+_savegpr0_20:
+ std r20,-96(r1)
+.globl _savegpr0_21
+_savegpr0_21:
+ std r21,-88(r1)
+.globl _savegpr0_22
+_savegpr0_22:
+ std r22,-80(r1)
+.globl _savegpr0_23
+_savegpr0_23:
+ std r23,-72(r1)
+.globl _savegpr0_24
+_savegpr0_24:
+ std r24,-64(r1)
+.globl _savegpr0_25
+_savegpr0_25:
+ std r25,-56(r1)
+.globl _savegpr0_26
+_savegpr0_26:
+ std r26,-48(r1)
+.globl _savegpr0_27
+_savegpr0_27:
+ std r27,-40(r1)
+.globl _savegpr0_28
+_savegpr0_28:
+ std r28,-32(r1)
+.globl _savegpr0_29
+_savegpr0_29:
+ std r29,-24(r1)
+.globl _savegpr0_30
+_savegpr0_30:
+ std r30,-16(r1)
+.globl _savegpr0_31
+_savegpr0_31:
+ std r31,-8(r1)
+ std r0,16(r1)
+ blr
+
+.globl _restgpr0_14
+_restgpr0_14:
+ ld r14,-144(r1)
+.globl _restgpr0_15
+_restgpr0_15:
+ ld r15,-136(r1)
+.globl _restgpr0_16
+_restgpr0_16:
+ ld r16,-128(r1)
+.globl _restgpr0_17
+_restgpr0_17:
+ ld r17,-120(r1)
+.globl _restgpr0_18
+_restgpr0_18:
+ ld r18,-112(r1)
+.globl _restgpr0_19
+_restgpr0_19:
+ ld r19,-104(r1)
+.globl _restgpr0_20
+_restgpr0_20:
+ ld r20,-96(r1)
+.globl _restgpr0_21
+_restgpr0_21:
+ ld r21,-88(r1)
+.globl _restgpr0_22
+_restgpr0_22:
+ ld r22,-80(r1)
+.globl _restgpr0_23
+_restgpr0_23:
+ ld r23,-72(r1)
+.globl _restgpr0_24
+_restgpr0_24:
+ ld r24,-64(r1)
+.globl _restgpr0_25
+_restgpr0_25:
+ ld r25,-56(r1)
+.globl _restgpr0_26
+_restgpr0_26:
+ ld r26,-48(r1)
+.globl _restgpr0_27
+_restgpr0_27:
+ ld r27,-40(r1)
+.globl _restgpr0_28
+_restgpr0_28:
+ ld r28,-32(r1)
+.globl _restgpr0_29
+_restgpr0_29:
+ ld r0,16(r1)
+ ld r29,-24(r1)
+ mtlr r0
+ ld r30,-16(r1)
+ ld r31,-8(r1)
+ blr
+
+.globl _restgpr0_30
+_restgpr0_30:
+ ld r30,-16(r1)
+.globl _restgpr0_31
+_restgpr0_31:
+ ld r0,16(r1)
+ ld r31,-8(r1)
+ mtlr r0
+ blr
diff --git a/purgatory/arch/ppc64/ppc64_asm.h b/purgatory/arch/ppc64/ppc64_asm.h
new file mode 100644
index 0000000..b8746fd
--- /dev/null
+++ b/purgatory/arch/ppc64/ppc64_asm.h
@@ -0,0 +1,16 @@
+/*
+ * ppc64_asm.h - common defines for PPC64 assembly parts
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+/*
+ * ABIv1 requires dot symbol while ABIv2 does not.
+ */
+#if defined(_CALL_ELF) && _CALL_ELF == 2
+#define DOTSYM(a) a
+#else
+#define GLUE(a,b) a##b
+#define DOTSYM(a) GLUE(.,a)
+#endif
diff --git a/purgatory/arch/ppc64/purgatory-ppc64.c b/purgatory/arch/ppc64/purgatory-ppc64.c
new file mode 100644
index 0000000..7248ac8
--- /dev/null
+++ b/purgatory/arch/ppc64/purgatory-ppc64.c
@@ -0,0 +1,44 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Created by: Mohan Kumar M (mohan@in.ibm.com)
+ *
+ * Copyright (C) IBM Corporation, 2005. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <purgatory.h>
+#include "purgatory-ppc64.h"
+
+unsigned int panic_kernel = 0;
+unsigned long backup_start = 0;
+unsigned long stack = 0;
+unsigned long dt_offset = 0;
+unsigned long my_toc = 0;
+unsigned long kernel = 0;
+unsigned int debug = 0;
+unsigned long opal_base = 0;
+unsigned long opal_entry = 0;
+
+void setup_arch(void)
+{
+ return;
+}
+
+void post_verification_setup_arch(void)
+{
+ if (panic_kernel)
+ crashdump_backup_memory();
+}
diff --git a/purgatory/arch/ppc64/purgatory-ppc64.h b/purgatory/arch/ppc64/purgatory-ppc64.h
new file mode 100644
index 0000000..52eaf43
--- /dev/null
+++ b/purgatory/arch/ppc64/purgatory-ppc64.h
@@ -0,0 +1,6 @@
+#ifndef PURGATORY_PPC64_H
+#define PURGATORY_PPC64_H
+
+void crashdump_backup_memory(void);
+
+#endif /* PURGATORY_PPC64_H */
diff --git a/purgatory/arch/ppc64/v2wrap.S b/purgatory/arch/ppc64/v2wrap.S
new file mode 100644
index 0000000..3534080
--- /dev/null
+++ b/purgatory/arch/ppc64/v2wrap.S
@@ -0,0 +1,137 @@
+#
+# kexec: Linux boots Linux
+#
+# Copyright (C) 2004 - 2005, Milton D Miller II, IBM Corporation
+# Copyright (C) 2006, Mohan Kumar M (mohan@in.ibm.com), IBM Corporation
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation (version 2 of the License).
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+#include "ppc64_asm.h"
+
+# v2wrap.S
+# a wrapper to call purgatory code to backup first
+# 32kB of first kernel into the backup region
+# reserved by kexec-tools.
+# Invokes ppc64 kernel with the expected arguments
+# of kernel(device-tree, phys-offset, 0)
+
+#
+# calling convention:
+# r3 = physical number of this cpu (all cpus)
+# r4 = address of this chunk (master only)
+# master enters at purgatory_start (aka first byte of this chunk)
+# slaves (additional cpus), if any, enter a copy of the
+# first 0x100 bytes of this code relocated to 0x0
+#
+# in other words,
+# a copy of the first 0x100 bytes of this code is copied to 0
+# and the slaves are sent to address 0x60
+# with r3 = their physical cpu number.
+
+#define LOADADDR(rn,name) \
+ lis rn,name##@highest; \
+ ori rn,rn,name##@higher; \
+ rldicr rn,rn,32,31; \
+ oris rn,rn,name##@h; \
+ ori rn,rn,name##@l
+
+ .machine ppc64
+ .align 8
+ .globl purgatory_start
+purgatory_start: b master
+ .org purgatory_start + 0x5c # ABI: possible run_at_load flag at 0x5c
+ .globl run_at_load
+run_at_load:
+ .long 0
+ .size run_at_load, . - run_at_load
+ .org purgatory_start + 0x60 # ABI: slaves start at 60 with r3=phys
+slave: b $
+ .org purgatory_start + 0x100 # ABI: end of copied region
+ .size purgatory_start, . - purgatory_start
+
+#
+# The above 0x100 bytes at purgatory_start are replaced with the
+# code from the kernel (or next stage) by kexec/arch/ppc64/kexec-elf-ppc64.c
+#
+
+master:
+ or 1,1,1 # low priority to let other threads catchup
+ isync
+ mr 17,3 # save cpu id to r17
+ mr 15,4 # save physical address in reg15
+
+ LOADADDR(6,my_toc)
+ ld 2,0(6) #setup toc
+
+ LOADADDR(6,stack)
+ ld 1,0(6) #setup stack
+
+ subi 1,1,112
+ bl DOTSYM(purgatory)
+ nop
+
+ or 3,3,3 # ok now to high priority, lets boot
+ lis 6,0x1
+ mtctr 6 # delay a bit for slaves to catch up
+83: bdnz 83b # before we overwrite 0-100 again
+
+ LOADADDR(16, dt_offset)
+ ld 3,0(16) # load device-tree address
+ mr 16,3 # save dt address in reg16
+#ifdef __BIG_ENDIAN__
+ lwz 6,20(3) # fetch version number
+#else
+ li 4,20
+ lwbrx 6,3,4 # fetch BE version number
+#endif
+ cmpwi 0,6,2 # v2 ?
+ blt 80f
+#ifdef __BIG_ENDIAN__
+ stw 17,28(3) # save my cpu number as boot_cpu_phys
+#else
+ li 4,28
+ stwbrx 17,3,4 # Store my cpu as BE value
+#endif
+80:
+ LOADADDR(6,opal_base) # For OPAL early debug
+ ld 8,0(6) # load the OPAL base address in r8
+ LOADADDR(6,opal_entry) # For OPAL early debug
+ ld 9,0(6) # load the OPAL entry address in r9
+ LOADADDR(6,kernel)
+ ld 4,0(6) # load the kernel address
+ LOADADDR(6,run_at_load) # the load flag
+ lwz 7,0(6) # possibly patched by kexec-elf-ppc64
+ stw 7,0x5c(4) # and patch it into the kernel
+ mr 3,16 # restore dt address
+
+ mfmsr 5
+ andi. 10,5,1 # test MSR_LE
+ bne little_endian
+
+ li 5,0 # r5 will be 0 for kernel
+ mtctr 4 # prepare branch to
+ bctr # start kernel
+
+little_endian: # book3s-only
+ mtsrr0 4 # prepare branch to
+
+ clrrdi 5,5,1 # clear MSR_LE
+ mtsrr1 5
+
+ li 5,0 # r5 will be 0 for kernel
+
+ # skip cache flush, do we care?
+
+ rfid # update MSR and start kernel