diff options
author | Nicholas Piggin <npiggin@gmail.com> | 2017-01-05 19:35:47 +1000 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2017-02-06 18:40:48 +1100 |
commit | 4ebde139333659b6de4516830a2785b8a89c08a4 (patch) | |
tree | a04a547f3971f98a2bff5f777884daf19e5bf863 | |
parent | 420d62d8f545204ff615b3062b01babb8b98e11c (diff) | |
download | skiboot-4ebde139333659b6de4516830a2785b8a89c08a4.zip skiboot-4ebde139333659b6de4516830a2785b8a89c08a4.tar.gz skiboot-4ebde139333659b6de4516830a2785b8a89c08a4.tar.bz2 |
Initial support for the ELFv2 ABI
Provide an experimental option to compile using ELFv2 ABI even on big
endian builds. ELFv2 + BE is not officially supported by the toolchain,
but it works quite well. It may be useful as a small step toward a
little-endian build.
This saves about 200kB of text/data.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | Makefile.main | 11 | ||||
-rw-r--r-- | asm/head.S | 1 | ||||
-rw-r--r-- | core/init.c | 18 | ||||
-rw-r--r-- | core/opal.c | 8 | ||||
-rw-r--r-- | include/elf-abi.h | 67 |
6 files changed, 101 insertions, 12 deletions
@@ -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 @@ -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 */ |