aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile8
-rw-r--r--Makefile.main11
-rw-r--r--asm/head.S1
-rw-r--r--core/init.c18
-rw-r--r--core/opal.c8
-rw-r--r--include/elf-abi.h67
6 files changed, 101 insertions, 12 deletions
diff --git a/Makefile b/Makefile
index f13bf50..d4a097f 100644
--- a/Makefile
+++ b/Makefile
@@ -38,6 +38,14 @@ KERNEL ?=
STACK_CHECK ?= $(DEBUG)
#
+# Experimental (unsupported) build options
+#
+# Little-endian does not yet build. Include it here to set ELF ABI.
+LITTLE_ENDIAN ?= 0
+# ELF v2 ABI is more efficient and compact
+ELF_ABI_v2 ?= $(LITTLE_ENDIAN)
+
+#
# Where is the source directory, must be a full path (no ~)
# Example: SRC= /home/me/skiboot
#
diff --git a/Makefile.main b/Makefile.main
index d71635b..5656cb7 100644
--- a/Makefile.main
+++ b/Makefile.main
@@ -71,8 +71,12 @@ endif
CFLAGS := -fno-strict-aliasing -pie -mbig-endian -m64
CFLAGS += -Wl,--oformat,elf64-powerpc
CFLAGS += -ffixed-r13
-CFLAGS += $(call try-cflag,$(CC),-mabi=elfv1)
CFLAGS += $(call try-cflag,$(CC),-std=gnu11)
+ifeq ($(ELF_ABI_v2),1)
+CFLAGS += $(call try-cflag,$(CC),-mabi=elfv2)
+else
+CFLAGS += $(call try-cflag,$(CC),-mabi=elfv1)
+endif
ifeq ($(SKIBOOT_GCOV),1)
CFLAGS += -fprofile-arcs -ftest-coverage -DSKIBOOT_GCOV=1
@@ -109,6 +113,11 @@ LDRFLAGS=-melf64ppc
#LDFLAGS += -Wl,-v -Wl,-Map,foomap
AFLAGS := -D__ASSEMBLY__ -mbig-endian -m64
+ifeq ($(ELF_ABI_v2),1)
+AFLAGS += $(call try-cflag,$(CC),-mabi=elfv2)
+else
+AFLAGS += $(call try-cflag,$(CC),-mabi=elfv1)
+endif
# Special tool flags:
# Do not use the floating point unit
diff --git a/asm/head.S b/asm/head.S
index 47520f9..d7c2821 100644
--- a/asm/head.S
+++ b/asm/head.S
@@ -899,6 +899,7 @@ opal_entry:
/* Convert our token into a table entry and get the
* function pointer. Also check the token.
+ * For ELFv2 ABI, the local entry point is used so no need for r12.
*/
cmpldi %r0,OPAL_LAST
bgt- 2f
diff --git a/core/init.c b/core/init.c
index c753b61..7bcb680 100644
--- a/core/init.c
+++ b/core/init.c
@@ -614,12 +614,6 @@ static void dt_init_misc(void)
dt_fixups();
}
-static void branch_null(void)
-{
- assert_fail("Branch to NULL !");
-}
-
-
typedef void (*ctorcall_t)(void);
static void __nomcount do_ctors(void)
@@ -631,6 +625,13 @@ static void __nomcount do_ctors(void)
(*call)();
}
+#ifndef PPC64_ELF_ABI_v2
+static void branch_null(void)
+{
+ assert_fail("Branch to NULL !");
+}
+
+
static void setup_branch_null_catcher(void)
{
void (*bn)(void) = branch_null;
@@ -642,6 +643,11 @@ static void setup_branch_null_catcher(void)
*/
memcpy(0, bn, 16);
}
+#else
+static void setup_branch_null_catcher(void)
+{
+}
+#endif
void setup_reset_vector(void)
{
diff --git a/core/opal.c b/core/opal.c
index 1d15abe..6087e65 100644
--- a/core/opal.c
+++ b/core/opal.c
@@ -29,6 +29,7 @@
#include <affinity.h>
#include <opal-msg.h>
#include <timer.h>
+#include <elf-abi.h>
/* Pending events to signal via opal_poll_events */
uint64_t opal_pending_events;
@@ -58,8 +59,7 @@ void opal_table_init(void)
printf("OPAL table: %p .. %p, branch table: %p\n",
s, e, opal_branch_table);
while(s < e) {
- uint64_t *func = s->func;
- opal_branch_table[s->token] = *func;
+ opal_branch_table[s->token] = function_entry_address(s->func);
opal_num_args[s->token] = s->nargs;
s++;
}
@@ -113,11 +113,9 @@ void opal_trace_entry(struct stack_frame *eframe)
void __opal_register(uint64_t token, void *func, unsigned int nargs)
{
- uint64_t *opd = func;
-
assert(token <= OPAL_LAST);
- opal_branch_table[token] = *opd;
+ opal_branch_table[token] = function_entry_address(func);
opal_num_args[token] = nargs;
}
diff --git a/include/elf-abi.h b/include/elf-abi.h
new file mode 100644
index 0000000..e8397f7
--- /dev/null
+++ b/include/elf-abi.h
@@ -0,0 +1,67 @@
+/* Copyright 2017 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ELF_ABI_H
+#define __ELF_ABI_H
+
+#ifndef __ASSEMBLY__
+
+#if defined (_CALL_ELF) && _CALL_ELF == 2
+#define ELF_ABI_v2
+#else
+#define ELF_ABI_v1
+#endif
+
+/* From linux/arch/powerpc/include/asm/code-patching.h */
+#define OP_RT_RA_MASK 0xffff0000UL
+#define LIS_R2 0x3c020000UL
+#define ADDIS_R2_R12 0x3c4c0000UL
+#define ADDI_R2_R2 0x38420000UL
+
+static inline uint64_t function_entry_address(void *func)
+{
+#ifdef ELF_ABI_v2
+ u32 *insn = func;
+ /*
+ * A PPC64 ABIv2 function may have a local and a global entry
+ * point. We use the local entry point for branch tables called
+ * from asm, only a single TOC is used, so identify and step over
+ * the global entry point sequence.
+ *
+ * The global entry point sequence is always of the form:
+ *
+ * addis r2,r12,XXXX
+ * addi r2,r2,XXXX
+ *
+ * A linker optimisation may convert the addis to lis:
+ *
+ * lis r2,XXXX
+ * addi r2,r2,XXXX
+ */
+ if ((((*insn & OP_RT_RA_MASK) == ADDIS_R2_R12) ||
+ ((*insn & OP_RT_RA_MASK) == LIS_R2)) &&
+ ((*(insn+1) & OP_RT_RA_MASK) == ADDI_R2_R2))
+ return (uint64_t)(insn + 2);
+ else
+ return (uint64_t)func;
+#else
+ return *(uint64_t *)func;
+#endif
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __COMPILER_H */