rk: remove unused PIE support
Change-Id: Ib7793724ef4e1c681898813e4ca5dd47a1960ae2 Signed-off-by: Tao Huang <huangtao@rock-chips.com>
This commit is contained in:
parent
fba107bd06
commit
053de347cd
13 changed files with 0 additions and 1013 deletions
|
|
@ -1,167 +0,0 @@
|
|||
Position Independent Executables (PIEs)
|
||||
=======================================
|
||||
|
||||
About
|
||||
=====
|
||||
|
||||
The PIE framework is designed to allow normal C code from the kernel to be
|
||||
embedded into the kernel, loaded at arbirary addresses, and executed.
|
||||
|
||||
A PIE is a position independent executable is a piece of self contained code
|
||||
that can be relocated to any address. Before the code is run, a simple list
|
||||
of offset based relocations has to be performed.
|
||||
|
||||
Copyright 2013 Texas Instruments, Inc
|
||||
Russ Dill <russ.dill@ti.com>
|
||||
|
||||
Motivation
|
||||
==========
|
||||
|
||||
Without the PIE framework, the only way to support platforms that require
|
||||
code loaded to and run from arbitrary addresses was to write the code in
|
||||
assembly. For example, a platform may have suspend/resume steps that
|
||||
disable/enable SDRAM and must be run from on chip SRAM.
|
||||
|
||||
In addition to the SRAM virtual address not being known at compile time
|
||||
for device tree platforms, the code must often run with the MMU enabled or
|
||||
disabled (physical vs virtual address).
|
||||
|
||||
Design
|
||||
======
|
||||
|
||||
The PIE code is separated into two main pieces. libpie satifies various
|
||||
function calls emitted by gcc. The kernel contains only one copy of libpie
|
||||
but whenever a PIE is loaded, a copy of libpie is copied along with the PIE
|
||||
code. The second piece is the PIE code and data marked with special PIE
|
||||
sections. At build time, libpie and the PIE sections are collected together
|
||||
into a single PIE executable:
|
||||
|
||||
+---------------------------------------+
|
||||
| __pie_common_start |
|
||||
| <libpie> |
|
||||
| __pie_common_end |
|
||||
+---------------------------------------+
|
||||
| __pie_overlay_start |
|
||||
| +-----------------------------+ |
|
||||
| | __pie_groupxyz_start | |
|
||||
| | <groupxyz functions/data> | |
|
||||
| | __pie_groupxyz_end | |
|
||||
| +-----------------------------+ |
|
||||
| | __pie_groupabc_start | |
|
||||
| | <groupabc functions/data> | |
|
||||
| | __pie_groupabc_end | |
|
||||
| +-----------------------------+ |
|
||||
| | __pie_groupijk_start | |
|
||||
| | <groupijk functions/data> | |
|
||||
| | __pie_groupijk_end | |
|
||||
| +-----------------------------+ |
|
||||
| __pie_overlay_end |
|
||||
+---------------------------------------+
|
||||
| <Architecture specific relocations> |
|
||||
+---------------------------------------+
|
||||
|
||||
The PIE executable is then embedded into the kernel. Symbols are exported
|
||||
from the PIE executable and passed back into the kernel at link time. When
|
||||
the PIE is loaded, the memory layout then looks like the following:
|
||||
|
||||
+---------------------------------------+
|
||||
| <libpie> |
|
||||
+---------------------------------------+
|
||||
| <groupabc_functions/data> |
|
||||
+---------------------------------------+
|
||||
| Tail (Arch specific data/relocations |
|
||||
+---------------------------------------+
|
||||
|
||||
The architecture specific code is responsible for reading the relocations
|
||||
and performing the necessary fixups.
|
||||
|
||||
Marking code/data
|
||||
=================
|
||||
|
||||
Marking code and data for inclusing into a PIE group is done with the PIE
|
||||
section markers, __pie(<group>) and __pie_data(<group>). Any symbols that
|
||||
will be used outside of the PIE must be exported with EXPORT_PIE_SYMBOL:
|
||||
|
||||
static struct ddr_timings xyz_timings __pie_data(platformxyz) = {
|
||||
[...]
|
||||
};
|
||||
|
||||
void __pie(platformxyz) xyz_ddr_on(void *addr)
|
||||
{
|
||||
[...]
|
||||
}
|
||||
EXPORT_PIE_SYMBOL(xyz_ddr_on);
|
||||
|
||||
Loading PIEs
|
||||
============
|
||||
|
||||
PIEs can be loaded into a genalloc pool (such as one backed by SRAM). The
|
||||
following functions are provided:
|
||||
|
||||
- pie_load_sections(pool, <group>)
|
||||
- pie_load_sections_phys(pool, <group>)
|
||||
- pie_free(chunk)
|
||||
|
||||
pie_load_sections/pie_load_sections_phys load a PIE section group into the
|
||||
given pool. Any necessary fixups are peformed and a chunk identifier is
|
||||
returned. The first variant performs fixups such that the code can be run
|
||||
with the current address layout. The second (phys) variant performs fixups
|
||||
such that the code can be executed with the MMU disabled.
|
||||
|
||||
The pie_free function unloads a PIE from a pool.
|
||||
|
||||
Utilizing PIEs
|
||||
==============
|
||||
|
||||
In order to translate between symbols and addresses within a loaded PIE, the
|
||||
following macros/functions are provided:
|
||||
|
||||
- kern_to_pie(chunk, sym)
|
||||
- fn_to_pie(chunk, fn)
|
||||
- pie_to_phys(chunk, addr)
|
||||
|
||||
All three take as the first argument the chunk returned by pie_load_sections.
|
||||
Data symbols can be translated with kern_to_pie. The macro is made so that
|
||||
the type returned is the type passed:
|
||||
|
||||
kern_to_pie(chunk, xyz_struct_ptr)->foo = 15;
|
||||
*kern_to_pie(chunk, &xyz_flags) = XYZ_DO_THE_THING;
|
||||
|
||||
Because certain architectures require special handling of function pointers,
|
||||
a special varaint is provided:
|
||||
|
||||
ret = fn_to_pie(chunk, &xyz_ddr_on)(addr);
|
||||
fnptr = fn_to_pie(chunk, &abc_fn);
|
||||
|
||||
In the case that a PIE has been configured to run with the MMU disabled,
|
||||
physical addresses can be translated with pie_to_phys. For instance, if
|
||||
the resume ROM jumps to a given physical address:
|
||||
|
||||
trampoline = fn_to_pie(chunk, resume_trampoline);
|
||||
writel(pie_to_phys(chunk, trampoline), XYZ_RESUME_ADDR_REG);
|
||||
|
||||
On the Fly Fixup
|
||||
================
|
||||
|
||||
The tail portion of the PIE can be used to store data necessary to perform
|
||||
on the fly fixups. This is necessary for code that needs to run from
|
||||
different address spaces at different times. Any on the fly fixup support
|
||||
is architecture specific.
|
||||
|
||||
Architecture Requirements
|
||||
=========================
|
||||
|
||||
Individual architectures must implement two functions:
|
||||
|
||||
pie_arch_fill_tail - This function examines the architecture specific
|
||||
relocation entries and copies the ones necessary for the given PIE.
|
||||
|
||||
pie_arch_fixup - This function performs fixups of the PIE code based
|
||||
on the tail data generated above.
|
||||
|
||||
pie.lds - A linker script for the PIE executable must be provided.
|
||||
include/asm-generic/pie.lds.S provides a template.
|
||||
|
||||
libpie.o - The architecture must also provide a library of functions that
|
||||
gcc may expect as a built-in, such as memcpy, memmove, etc. The list of
|
||||
functions is architecture specific.
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* arch/arm/include/asm/pie.h
|
||||
*
|
||||
* Copyright 2013 Texas Instruments, Inc
|
||||
* Russ Dill <russ.dill@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ASMARM_PIE_H
|
||||
#define _ASMARM_PIE_H
|
||||
|
||||
#include <linux/pie.h>
|
||||
|
||||
#ifdef CONFIG_PIE
|
||||
extern void __pie_relocate(void);
|
||||
extern void __pie___pie_relocate(void);
|
||||
|
||||
#define pie_relocate_from_pie() \
|
||||
__asm__ __volatile__("bl __pie_relocate\n" \
|
||||
: : : "cc", "memory", "lr", "r4", "r5", "r6", "r7", "r8", "r9");
|
||||
|
||||
static inline void pie_relocate_from_kern(struct pie_chunk *chunk)
|
||||
{
|
||||
void (*fn)(void) = fn_to_pie(chunk, &__pie___pie_relocate);
|
||||
__asm__ __volatile__("" : : : "cc", "memory", "r4", "r5", "r6",
|
||||
"r7", "r8", "r9");
|
||||
fn();
|
||||
}
|
||||
#else
|
||||
|
||||
#define pie_relocate_from_pie() do {} while(0)
|
||||
|
||||
static inline void pie_relocate_from_kern(struct pie_chunk *chunk)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 Texas Instruments, Inc.
|
||||
* Russ Dill <russ.dill@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pie.h>
|
||||
#include <linux/elf.h>
|
||||
|
||||
#include <asm/elf.h>
|
||||
#include <asm/pie.h>
|
||||
|
||||
extern char __pie_rel_dyn_start[];
|
||||
extern char __pie_rel_dyn_end[];
|
||||
extern char __pie_tail_offset[];
|
||||
extern char __pie_reloc_offset[];
|
||||
|
||||
struct arm_pie_tail {
|
||||
int count;
|
||||
uintptr_t offset[0];
|
||||
};
|
||||
|
||||
int pie_arch_fill_tail(void *tail, void *common_start, void *common_end,
|
||||
void *overlay_start, void *code_start, void *code_end,
|
||||
void *rel_start, void *rel_end)
|
||||
{
|
||||
Elf32_Rel *rel;
|
||||
int records;
|
||||
int i;
|
||||
struct arm_pie_tail *pie_tail = tail;
|
||||
int count;
|
||||
void *kern_off;
|
||||
|
||||
rel = (Elf32_Rel *) __pie_rel_dyn_start;
|
||||
records = (__pie_rel_dyn_end - __pie_rel_dyn_start) / sizeof(*rel);
|
||||
|
||||
count = 0;
|
||||
for (i = 0; i < records; i++, rel++) {
|
||||
if (ELF32_R_TYPE(rel->r_info) != R_ARM_RELATIVE)
|
||||
break;
|
||||
|
||||
/* Adjust offset to match area in kernel */
|
||||
kern_off = common_start + rel->r_offset;
|
||||
|
||||
if (kern_off >= common_start && kern_off < code_end) {
|
||||
if (tail)
|
||||
pie_tail->offset[count] = rel->r_offset;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
rel = (Elf32_Rel *) rel_start;
|
||||
records = (rel_end - rel_start) / sizeof(*rel);
|
||||
|
||||
for (i = 0; i < records; i++, rel++) {
|
||||
if (ELF32_R_TYPE(rel->r_info) != R_ARM_RELATIVE)
|
||||
break;
|
||||
|
||||
/* Adjust offset to match area in kernel */
|
||||
kern_off = common_start + rel->r_offset;
|
||||
|
||||
if (kern_off >= common_start && kern_off < code_end) {
|
||||
if (tail)
|
||||
pie_tail->offset[count] = rel->r_offset;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (tail)
|
||||
pie_tail->count = count;
|
||||
|
||||
return count * sizeof(uintptr_t) + sizeof(*pie_tail);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pie_arch_fill_tail);
|
||||
|
||||
/*
|
||||
* R_ARM_RELATIVE: B(S) + A
|
||||
* B(S) - Addressing origin of the output segment defining the symbol S.
|
||||
* A - Addend for the relocation.
|
||||
*/
|
||||
int pie_arch_fixup(struct pie_chunk *chunk, void *base, void *tail,
|
||||
unsigned long offset)
|
||||
{
|
||||
struct arm_pie_tail *pie_tail = tail;
|
||||
void *reloc;
|
||||
int i;
|
||||
|
||||
/* Perform relocation fixups for given offset */
|
||||
for (i = 0; i < pie_tail->count; i++)
|
||||
*((uintptr_t *) (pie_tail->offset[i] + base)) += offset;
|
||||
|
||||
/* Store the PIE offset to tail and recol func */
|
||||
*kern_to_pie(chunk, (uintptr_t *) __pie_tail_offset) = tail - base;
|
||||
reloc = kern_to_pie(chunk,
|
||||
(void *) fnptr_to_addr(&__pie___pie_relocate));
|
||||
*kern_to_pie(chunk, (uintptr_t *) __pie_reloc_offset) = reloc - base;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pie_arch_fixup);
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* ld script to make ARM PIEs
|
||||
* taken from the ARM vmlinux.lds.S version by Russ Dill <russ.dill@ti.com.
|
||||
*/
|
||||
|
||||
#include <asm-generic/pie.lds.h>
|
||||
|
||||
OUTPUT_ARCH(arm)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x0;
|
||||
|
||||
PIE_COMMON_START
|
||||
.got.plt : {
|
||||
*(.got)
|
||||
*(.got.plt)
|
||||
}
|
||||
.text : {
|
||||
PIE_TEXT_TEXT
|
||||
}
|
||||
PIE_COMMON_END
|
||||
|
||||
__pie_rel_dyn_start : {
|
||||
VMLINUX_SYMBOL(__pie_rel_dyn_start) = .;
|
||||
}
|
||||
.rel.dyn : {
|
||||
KEEP(*(.rel.pie.text))
|
||||
}
|
||||
__pie_rel_dyn_end : {
|
||||
VMLINUX_SYMBOL(__pie_rel_dyn_end) = .;
|
||||
}
|
||||
|
||||
PIE_OVERLAY_START
|
||||
OVERLAY : NOCROSSREFS {
|
||||
PIE_OVERLAY_SECTION(overlay)
|
||||
PIE_OVERLAY_SECTION(rk3288)
|
||||
PIE_OVERLAY_SECTION(rk3188)
|
||||
PIE_OVERLAY_SECTION(rk3036)
|
||||
PIE_OVERLAY_SECTION(rk312x)
|
||||
PIE_OVERLAY_SECTION(rk3126b)
|
||||
}
|
||||
PIE_OVERLAY_END
|
||||
|
||||
PIE_DISCARDS
|
||||
}
|
||||
3
arch/arm/libpie/.gitignore
vendored
3
arch/arm/libpie/.gitignore
vendored
|
|
@ -1,3 +0,0 @@
|
|||
lib1funcs.S
|
||||
ashldi3.S
|
||||
string.c
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
#
|
||||
# linux/arch/arm/libpie/Makefile
|
||||
#
|
||||
ccflags-y := -fpic -mno-single-pic-base -fno-builtin
|
||||
|
||||
obj-y := relocate.o empty.o
|
||||
obj-y += lib1funcs.o ashldi3.o string.o
|
||||
|
||||
# string library code (-Os is enforced to keep it much smaller)
|
||||
string = $(obj)/string.o
|
||||
CFLAGS_string.o := -Os
|
||||
|
||||
$(obj)/string.c: $(srctree)/arch/$(SRCARCH)/boot/compressed/string.c
|
||||
$(call cmd,shipped)
|
||||
|
||||
# For __aeabi_uidivmod
|
||||
lib1funcs = $(obj)/lib1funcs.o
|
||||
|
||||
$(obj)/lib1funcs.S: $(srctree)/arch/$(SRCARCH)/lib/lib1funcs.S
|
||||
$(call cmd,shipped)
|
||||
|
||||
# For __aeabi_llsl
|
||||
ashldi3 = $(obj)/ashldi3.o
|
||||
|
||||
$(obj)/ashldi3.S: $(srctree)/arch/$(SRCARCH)/lib/ashldi3.S
|
||||
$(call cmd,shipped)
|
||||
|
||||
$(obj)/libpie.o: $(string) $(lib1funcs) $(ashldi3) $(addprefix $(obj)/,$(OBJS))
|
||||
$(call if_changed,ld)
|
||||
|
||||
# Make sure files are removed during clean
|
||||
extra-y += string.c lib1funcs.S ashldi3.S
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
#include <linux/linkage.h>
|
||||
|
||||
ENTRY(__div0)
|
||||
ENTRY(__gnu_mcount_nc)
|
||||
ENTRY(__aeabi_unwind_cpp_pr0)
|
||||
ENTRY(__aeabi_unwind_cpp_pr1)
|
||||
ENTRY(__aeabi_unwind_cpp_pr2)
|
||||
mov pc, lr
|
||||
ENDPROC(__div0)
|
||||
ENDPROC(__gnu_mcount_nc)
|
||||
ENDPROC(__aeabi_unwind_cpp_pr0)
|
||||
ENDPROC(__aeabi_unwind_cpp_pr1)
|
||||
ENDPROC(__aeabi_unwind_cpp_pr2)
|
||||
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
/*
|
||||
* arch/arm/libpie/relocate.S - Relocation updating for PIEs
|
||||
*
|
||||
* Copyright 2013 Texas Instruments, Inc.
|
||||
* Russ Dill <russ.dill@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
|
||||
/*
|
||||
* Update relocations based on current pc
|
||||
*
|
||||
* On exit:
|
||||
* r4-r9 corrupted
|
||||
*/
|
||||
|
||||
ENTRY(__pie_relocate)
|
||||
/* Calculate offset of our code compared to existing relocations */
|
||||
ldr r4, pie_relocate_address
|
||||
adr r5, __pie_relocate
|
||||
subs r6, r5, r4
|
||||
moveq pc, lr /* 0 offset, no need to do anything */
|
||||
|
||||
/* Base of PIE group */
|
||||
ldr r7, reloc_offset
|
||||
sub r5, r5, r7
|
||||
|
||||
/* Calculate address of tail */
|
||||
ldr r7, tail_offset
|
||||
add r7, r7, r5
|
||||
|
||||
/* First byte of tail is number of entries */
|
||||
ldr r8, [r7], #4
|
||||
add r8, r7, r8, lsl #2
|
||||
|
||||
/*
|
||||
* r5 - current base address of PIE group
|
||||
* r6 - fixup offset needed for relocs
|
||||
* r7 - relocs start
|
||||
* r8 - relocs end
|
||||
*/
|
||||
|
||||
1:
|
||||
cmp r7, r8
|
||||
ldrne r4, [r7], #4 /* Load next reloc offset */
|
||||
|
||||
addne r4, r4, r5 /* Calculate address of reloc entry */
|
||||
ldrne r9, [r4]
|
||||
addne r9, r9, r6 /* Fixup reloc entry */
|
||||
strne r9, [r4]
|
||||
|
||||
bne 1b
|
||||
|
||||
mov pc, lr
|
||||
ENDPROC(__pie_relocate)
|
||||
|
||||
/*
|
||||
* This ends up in the .rel.dyn section and can be used to read the current
|
||||
* relocation offset
|
||||
*/
|
||||
pie_relocate_address:
|
||||
.long __pie_relocate
|
||||
|
||||
/* Offset from PIE section start to reloc function */
|
||||
.global reloc_offset
|
||||
reloc_offset:
|
||||
.space 4
|
||||
|
||||
/* Offset from PIE section start to tail */
|
||||
.globl tail_offset
|
||||
tail_offset:
|
||||
.space 4
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
* Helper macros to support writing architecture specific
|
||||
* pie linker scripts.
|
||||
*
|
||||
* A minimal linker scripts has following content:
|
||||
* [This is a sample, architectures may have special requiriements]
|
||||
*
|
||||
* OUTPUT_FORMAT(...)
|
||||
* OUTPUT_ARCH(...)
|
||||
* SECTIONS
|
||||
* {
|
||||
* . = 0x0;
|
||||
*
|
||||
* PIE_COMMON_START
|
||||
* .text {
|
||||
* PIE_TEXT_TEXT
|
||||
* }
|
||||
* PIE_COMMON_END
|
||||
*
|
||||
* PIE_OVERLAY_START
|
||||
* OVERLAY : NOCROSSREFS {
|
||||
* PIE_OVERLAY_SECTION(am33xx)
|
||||
* PIE_OVERLAY_SECTION(am347x)
|
||||
* [...]
|
||||
* }
|
||||
* PIE_OVERLAY_END
|
||||
*
|
||||
* PIE_DISCARDS // must be the last
|
||||
* }
|
||||
*/
|
||||
|
||||
#include <asm-generic/vmlinux.lds.h>
|
||||
|
||||
#define PIE_COMMON_START \
|
||||
__pie_common_start : { \
|
||||
VMLINUX_SYMBOL(__pie_common_start) = .; \
|
||||
}
|
||||
|
||||
#define PIE_COMMON_END \
|
||||
__pie_common_end : { \
|
||||
VMLINUX_SYMBOL(__pie_common_end) = .; \
|
||||
}
|
||||
|
||||
#define PIE_OVERLAY_START \
|
||||
__pie_overlay_start : { \
|
||||
VMLINUX_SYMBOL(__pie_overlay_start) = .; \
|
||||
}
|
||||
|
||||
#define PIE_OVERLAY_END \
|
||||
__pie_overlay_end : { \
|
||||
VMLINUX_SYMBOL(__pie_overlay_end) = .; \
|
||||
}
|
||||
|
||||
#define PIE_TEXT_TEXT \
|
||||
KEEP(*(.pie.text))
|
||||
|
||||
#define PIE_OVERLAY_SECTION(name) \
|
||||
.pie.##name { \
|
||||
KEEP(*(.pie.##name##.*)) \
|
||||
VMLINUX_SYMBOL(__pie_##name##_start) = \
|
||||
LOADADDR(.pie.##name##); \
|
||||
VMLINUX_SYMBOL(__pie_##name##_end) = \
|
||||
LOADADDR(.pie.##name##) + \
|
||||
SIZEOF(.pie.##name##); \
|
||||
} \
|
||||
.rel.##name { \
|
||||
KEEP(*(.rel.pie.##name##.*)) \
|
||||
VMLINUX_SYMBOL(__pie_rel_##name##_start) = \
|
||||
LOADADDR(.rel.##name##); \
|
||||
VMLINUX_SYMBOL(__pie_rel_##name##_end) = \
|
||||
LOADADDR(.rel.##name##) + \
|
||||
SIZEOF(.rel.##name##); \
|
||||
}
|
||||
|
||||
#define PIE_DISCARDS \
|
||||
/DISCARD/ : { \
|
||||
*(.dynsym) \
|
||||
*(.dynstr*) \
|
||||
*(.dynamic*) \
|
||||
*(.plt*) \
|
||||
*(.interp*) \
|
||||
*(.gnu*) \
|
||||
*(.hash) \
|
||||
*(.comment) \
|
||||
*(.bss*) \
|
||||
*(.data) \
|
||||
*(.discard) \
|
||||
*(.discard.*) \
|
||||
}
|
||||
|
||||
|
|
@ -1,201 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 Texas Instruments, Inc.
|
||||
* Russ Dill <russ.dill@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_PIE_H
|
||||
#define _LINUX_PIE_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <asm/fncpy.h>
|
||||
#include <asm/bug.h>
|
||||
|
||||
struct gen_pool;
|
||||
struct pie_chunk;
|
||||
|
||||
/**
|
||||
* pie_arch_fixup - arch specific fixups of copied PIE code
|
||||
* @chunk: identifier to be used with kern_to_pie/pie_to_phys
|
||||
* @base: virtual address of start of copied PIE section
|
||||
* @tail: virtual address of tail data in copied PIE
|
||||
* @offset: offset to apply to relocation entries.
|
||||
*
|
||||
* When this code is done executing, it should be possible to jump to code
|
||||
* so long as it is located at the given offset.
|
||||
*/
|
||||
extern int pie_arch_fixup(struct pie_chunk *chunk, void *base, void *tail,
|
||||
unsigned long offset);
|
||||
|
||||
/**
|
||||
* pie_arch_fill_tail - arch specific tail information for copied PIE
|
||||
* @tail: virtual address of tail data in copied PIE to be filled
|
||||
* @common_start: virtual address of common code within kernel data
|
||||
* @common_end: virtual end address of common code within kernel data
|
||||
* @overlay_start: virtual address of first overlay within kernel data
|
||||
* @code_start: virtual address of this overlay within kernel data
|
||||
* @code_end: virtual end address of this overlay within kernel data
|
||||
*
|
||||
* Fill tail data with data necessary to for pie_arch_fixup to perform
|
||||
* relocations. If tail is NULL, do not update data, but still calculate
|
||||
* the number of bytes required.
|
||||
*
|
||||
* Returns number of bytes required/used for tail on success, -EERROR otherwise.
|
||||
*/
|
||||
extern int pie_arch_fill_tail(void *tail, void *common_start, void *common_end,
|
||||
void *overlay_start, void *code_start, void *code_end,
|
||||
void *rel_start, void *rel_end);
|
||||
|
||||
#ifdef CONFIG_PIE
|
||||
|
||||
/**
|
||||
* __pie_load_data - load and fixup PIE code from kernel data
|
||||
* @pool: pool to allocate memory from and copy code into
|
||||
* @start: virtual start address in kernel of chunk specific code
|
||||
* @end: virtual end address in kernel of chunk specific code
|
||||
* @phys: %true to fixup to physical address of destination, %false to
|
||||
* fixup to virtual address of destination
|
||||
*
|
||||
* Returns 0 on success, -EERROR otherwise
|
||||
*/
|
||||
extern struct pie_chunk *__pie_load_data(struct gen_pool *pool, bool phys,
|
||||
void *start, void *end,
|
||||
void *rel_start, void *rel_end);
|
||||
|
||||
/**
|
||||
* pie_to_phys - translate a virtual PIE address into a physical one
|
||||
* @chunk: identifier returned by pie_load_sections
|
||||
* @addr: virtual address within pie chunk
|
||||
*
|
||||
* Returns physical address on success, -1 otherwise
|
||||
*/
|
||||
extern phys_addr_t pie_to_phys(struct pie_chunk *chunk, unsigned long addr);
|
||||
|
||||
extern void __iomem *__kern_to_pie(struct pie_chunk *chunk, void *ptr);
|
||||
|
||||
/**
|
||||
* pie_free - free the pool space used by an pie chunk
|
||||
* @chunk: identifier returned by pie_load_sections
|
||||
*/
|
||||
extern void pie_free(struct pie_chunk *chunk);
|
||||
|
||||
#define __pie_load_sections(pool, name, phys) ({ \
|
||||
extern char __pie_##name##_start[]; \
|
||||
extern char __pie_##name##_end[]; \
|
||||
extern char __pie_rel_##name##_start[]; \
|
||||
extern char __pie_rel_##name##_end[]; \
|
||||
\
|
||||
__pie_load_data(pool, phys, \
|
||||
__pie_##name##_start, __pie_##name##_end, \
|
||||
__pie_rel_##name##_start, __pie_rel_##name##_end); \
|
||||
})
|
||||
|
||||
/*
|
||||
* Required for any symbol within an PIE section that is referenced by the
|
||||
* kernel
|
||||
*/
|
||||
#define EXPORT_PIE_SYMBOL(sym) extern typeof(sym) sym __weak
|
||||
|
||||
/* For marking data and functions that should be part of a PIE */
|
||||
#define __pie(name) __attribute__ ((__section__(".pie." #name ".text")))
|
||||
#define __pie_data(name) __attribute__ ((__section__(".pie." #name ".data")))
|
||||
|
||||
#else
|
||||
|
||||
static inline struct pie_chunk *__pie_load_data(struct gen_pool *pool,
|
||||
void *start, void *end, bool phys)
|
||||
{
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
static inline phys_addr_t pie_to_phys(struct pie_chunk *chunk,
|
||||
unsigned long addr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline void __iomem *__kern_to_pie(struct pie_chunk *chunk, void *ptr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void pie_free(struct pie_chunk *chunk)
|
||||
{
|
||||
}
|
||||
|
||||
#define __pie_load_sections(pool, name, phys) ({ ERR_PTR(-EINVAL); })
|
||||
|
||||
#define EXPORT_PIE_SYMBOL(sym)
|
||||
|
||||
#define __pie(name)
|
||||
#define __pie_data(name)
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* pie_load_sections - load and fixup sections associated with the given name
|
||||
* @pool: pool to allocate memory from and copy code into
|
||||
* fixup to virtual address of destination
|
||||
* @name: the name given to __pie() and __pie_data() when marking
|
||||
* data and code
|
||||
*
|
||||
* Returns 0 on success, -EERROR otherwise
|
||||
*/
|
||||
#define pie_load_sections(pool, name) ({ \
|
||||
__pie_load_sections(pool, name, false); \
|
||||
})
|
||||
|
||||
/**
|
||||
* pie_load_sections_phys - load and fixup sections associated with the given
|
||||
* name for execution with the MMU off
|
||||
*
|
||||
* @pool: pool to allocate memory from and copy code into
|
||||
* fixup to virtual address of destination
|
||||
* @name: the name given to __pie() and __pie_data() when marking
|
||||
* data and code
|
||||
*
|
||||
* Returns 0 on success, -EERROR otherwise
|
||||
*/
|
||||
#define pie_load_sections_phys(pool, name) ({ \
|
||||
__pie_load_sections(pool, name, true); \
|
||||
})
|
||||
|
||||
/**
|
||||
* kern_to_pie - convert a kernel symbol to the virtual address of where
|
||||
* that symbol is loaded into the given PIE chunk.
|
||||
*
|
||||
* @chunk: identifier returned by pie_load_sections
|
||||
* @p: symbol to convert
|
||||
*
|
||||
* Return type is the same as type passed
|
||||
*/
|
||||
#define kern_to_pie(chunk, p) ({ \
|
||||
void *__ptr = (void *) (p); \
|
||||
typeof(p) __result = (typeof(p)) __kern_to_pie(chunk, __ptr); \
|
||||
__result; \
|
||||
})
|
||||
|
||||
/**
|
||||
* kern_to_fn - convert a kernel function symbol to the virtual address of where
|
||||
* that symbol is loaded into the given PIE chunk
|
||||
*
|
||||
* @chunk: identifier returned by pie_load_sections
|
||||
* @p: function to convert
|
||||
*
|
||||
* Return type is the same as type passed
|
||||
*/
|
||||
#define fn_to_pie(chunk, funcp) ({ \
|
||||
uintptr_t __kern_addr, __pie_addr; \
|
||||
\
|
||||
__kern_addr = fnptr_to_addr(funcp); \
|
||||
__pie_addr = kern_to_pie(chunk, __kern_addr); \
|
||||
\
|
||||
fnptr_translate(funcp, __pie_addr); \
|
||||
})
|
||||
|
||||
#endif
|
||||
142
lib/pie.c
142
lib/pie.c
|
|
@ -1,142 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 Texas Instruments, Inc.
|
||||
* Russ Dill <russ.dill@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/genalloc.h>
|
||||
#include <linux/pie.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
struct pie_chunk {
|
||||
struct gen_pool *pool;
|
||||
unsigned long addr;
|
||||
size_t sz;
|
||||
};
|
||||
|
||||
extern char __pie_common_start[];
|
||||
extern char __pie_common_end[];
|
||||
extern char __pie_overlay_start[];
|
||||
|
||||
int __weak pie_arch_fill_tail(void *tail, void *common_start, void *common_end,
|
||||
void *overlay_start, void *code_start, void *code_end,
|
||||
void *rel_start, void *rel_end)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __weak pie_arch_fixup(struct pie_chunk *chunk, void *base, void *tail,
|
||||
unsigned long offset)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct pie_chunk *__pie_load_data(struct gen_pool *pool, bool phys,
|
||||
void *code_start, void *code_end,
|
||||
void *rel_start, void *rel_end)
|
||||
{
|
||||
struct pie_chunk *chunk;
|
||||
unsigned long offset;
|
||||
int ret;
|
||||
char *tail;
|
||||
size_t common_sz;
|
||||
size_t code_sz;
|
||||
size_t tail_sz;
|
||||
|
||||
/* Calculate the tail size */
|
||||
ret = pie_arch_fill_tail(NULL, __pie_common_start, __pie_common_end,
|
||||
__pie_overlay_start, code_start, code_end,
|
||||
rel_start, rel_end);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
tail_sz = ret;
|
||||
|
||||
chunk = kzalloc(sizeof(*chunk), GFP_KERNEL);
|
||||
if (!chunk) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
common_sz = __pie_overlay_start - __pie_common_start;
|
||||
code_sz = code_end - code_start;
|
||||
|
||||
chunk->pool = pool;
|
||||
chunk->sz = common_sz + code_sz + tail_sz;
|
||||
|
||||
chunk->addr = gen_pool_alloc(pool, chunk->sz);
|
||||
if (!chunk->addr) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
/* Copy common code/data */
|
||||
tail = (char *) chunk->addr;
|
||||
memcpy(tail, __pie_common_start, common_sz);
|
||||
tail += common_sz;
|
||||
|
||||
/* Copy chunk specific code/data */
|
||||
memcpy(tail, code_start, code_sz);
|
||||
tail += code_sz;
|
||||
|
||||
/* Fill in tail data */
|
||||
ret = pie_arch_fill_tail(tail, __pie_common_start, __pie_common_end,
|
||||
__pie_overlay_start, code_start, code_end,
|
||||
rel_start, rel_end);
|
||||
if (ret < 0)
|
||||
goto err_alloc;
|
||||
|
||||
/* Calculate initial offset */
|
||||
if (phys)
|
||||
offset = gen_pool_virt_to_phys(pool, chunk->addr);
|
||||
else
|
||||
offset = chunk->addr;
|
||||
|
||||
/* Perform arch specific code fixups */
|
||||
ret = pie_arch_fixup(chunk, (void *) chunk->addr, tail, offset);
|
||||
if (ret < 0)
|
||||
goto err_alloc;
|
||||
|
||||
flush_icache_range(chunk->addr, chunk->addr + chunk->sz);
|
||||
|
||||
return chunk;
|
||||
|
||||
err_alloc:
|
||||
gen_pool_free(chunk->pool, chunk->addr, chunk->sz);
|
||||
|
||||
err_free:
|
||||
kfree(chunk);
|
||||
err:
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__pie_load_data);
|
||||
|
||||
phys_addr_t pie_to_phys(struct pie_chunk *chunk, unsigned long addr)
|
||||
{
|
||||
return gen_pool_virt_to_phys(chunk->pool, addr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pie_to_phys);
|
||||
|
||||
void __iomem *__kern_to_pie(struct pie_chunk *chunk, void *ptr)
|
||||
{
|
||||
uintptr_t offset = (uintptr_t) ptr;
|
||||
offset -= (uintptr_t) __pie_common_start;
|
||||
if (offset >= chunk->sz)
|
||||
return NULL;
|
||||
else
|
||||
return (void *) (chunk->addr + offset);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__kern_to_pie);
|
||||
|
||||
void pie_free(struct pie_chunk *chunk)
|
||||
{
|
||||
gen_pool_free(chunk->pool, chunk->addr, chunk->sz);
|
||||
kfree(chunk);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pie_free);
|
||||
3
pie/.gitignore
vendored
3
pie/.gitignore
vendored
|
|
@ -1,3 +0,0 @@
|
|||
*.syms
|
||||
pie.lds
|
||||
pie.lds.S
|
||||
93
pie/Makefile
93
pie/Makefile
|
|
@ -1,93 +0,0 @@
|
|||
#
|
||||
# linux/pie/Makefile
|
||||
#
|
||||
# Copyright 2013 Texas Instruments, Inc.
|
||||
# Russ Dill <russ.dill@ti.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms and conditions of the GNU General Public License,
|
||||
# version 2, as published by the Free Software Foundation.
|
||||
#
|
||||
|
||||
obj-y := pie.bin.o
|
||||
|
||||
# Report unresolved symbol references
|
||||
ldflags-y += --no-undefined
|
||||
# Delete all temporary local symbols
|
||||
ldflags-y += -X
|
||||
|
||||
# Reset objcopy flags, ARM puts "-O binary" here
|
||||
OBJCOPYFLAGS =
|
||||
|
||||
# Reference gcc builtins for use in PIE with __pie_
|
||||
$(obj)/pie_rename.syms: $(KBUILD_LIBPIE)
|
||||
@$(NM) $^ | awk '{if ($$3) print $$3,"__pie_"$$3}' > $@
|
||||
|
||||
# For weakening the links to the original gcc builtins
|
||||
$(obj)/pie_weaken.syms: $(KBUILD_LIBPIE)
|
||||
@$(NM) $^ | awk '{if ($$3) print "__pie_"$$3}' > $@
|
||||
|
||||
# For embedding address of the symbols copied from the PIE into the kernel
|
||||
$(obj)/pie.syms: $(obj)/pie.elf
|
||||
@$(NM) $^ | awk '{if ($$3 && $$2 == toupper($$2)) print $$3,"=","0x"$$1" + _binary_pie_pie_bin_start;"}' > $@
|
||||
|
||||
# Collect together the libpie objects
|
||||
LDFLAGS_libpie_stage1.o += -r
|
||||
|
||||
$(obj)/libpie_stage1.o: $(KBUILD_LIBPIE)
|
||||
$(call if_changed,ld)
|
||||
|
||||
# Rename the libpie gcc builtins with a __pie_ prefix
|
||||
OBJCOPYFLAGS_libpie_stage2.o += --redefine-syms=$(obj)/pie_rename.syms
|
||||
OBJCOPYFLAGS_libpie_stage2.o += --rename-section .text=.pie.text
|
||||
|
||||
$(obj)/libpie_stage2.o: $(obj)/libpie_stage1.o $(obj)/pie_rename.syms
|
||||
$(call if_changed,objcopy)
|
||||
|
||||
# Generate a version of vmlinux.o with weakened and rename references to gcc
|
||||
# builtins.
|
||||
OBJCOPYFLAGS_pie_stage1.o += --weaken-symbols=$(obj)/pie_weaken.syms
|
||||
OBJCOPYFLAGS_pie_stage1.o += --redefine-syms=$(obj)/pie_rename.syms
|
||||
|
||||
$(obj)/pie_stage1.o: $(obj)/../vmlinux.o $(obj)/pie_rename.syms $(obj)/pie_weaken.syms
|
||||
$(call if_changed,objcopy)
|
||||
|
||||
# Drop in the PIE versions instead
|
||||
LDFLAGS_pie_stage2.o += -r
|
||||
# Allow the _GLOBAL_OFFSET_TABLE to redefine
|
||||
LDFLAGS_pie_stage2.o += --defsym=_GLOBAL_OFFSET_TABLE_=_GLOBAL_OFFSET_TABLE_
|
||||
|
||||
$(obj)/pie_stage2.o: $(obj)/pie_stage1.o $(obj)/libpie_stage2.o
|
||||
$(call if_changed,ld)
|
||||
|
||||
# Drop everything but the pie sections
|
||||
OBJCOPYFLAGS_pie_stage3.o += -j ".pie.*"
|
||||
OBJCOPYFLAGS_pie_stage3.o += -j ".pie.text"
|
||||
OBJCOPYFLAGS_pie_stage3.o += -j ".pie.rk3036.text" -j ".pie.rk3036.data"
|
||||
OBJCOPYFLAGS_pie_stage3.o += -j ".pie.rk312x.text" -j ".pie.rk312x.data"
|
||||
OBJCOPYFLAGS_pie_stage3.o += -j ".pie.rk3126b.text" -j ".pie.rk3126b.data"
|
||||
OBJCOPYFLAGS_pie_stage3.o += -j ".pie.rk3188.text" -j ".pie.rk3188.data"
|
||||
OBJCOPYFLAGS_pie_stage3.o += -j ".pie.rk3288.text" -j ".pie.rk3288.data"
|
||||
|
||||
$(obj)/pie_stage3.o: $(obj)/pie_stage2.o
|
||||
$(call if_changed,objcopy)
|
||||
|
||||
# Create the position independant executable
|
||||
LDFLAGS_pie.elf += -T $(KBUILD_PIE_LDS) --pie --gc-sections
|
||||
|
||||
$(obj)/pie.elf: $(obj)/pie_stage3.o $(KBUILD_PIE_LDS)
|
||||
$(call if_changed,ld)
|
||||
|
||||
# Create binary data for the kernel
|
||||
OBJCOPYFLAGS_pie.bin += -O binary
|
||||
|
||||
$(obj)/pie.bin: $(obj)/pie.elf $(obj)/pie.syms
|
||||
$(call if_changed,objcopy)
|
||||
|
||||
# Import the data into the kernel
|
||||
OBJCOPYFLAGS_pie.bin.o += -B $(ARCH) -I binary -O $(OBJCOPY_OUTPUT_FORMAT)
|
||||
|
||||
$(obj)/pie.bin.o: $(obj)/pie.bin
|
||||
$(call if_changed,objcopy)
|
||||
|
||||
extra-y += pie_rename.syms pie_weaken.syms pie.syms pie.elf pie.bin
|
||||
Loading…
Add table
Add a link
Reference in a new issue