2 * Copyright 2013 Texas Instruments, Inc.
3 * Russ Dill <russ.dill@ti.com>
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
10 #include <linux/kernel.h>
11 #include <linux/slab.h>
12 #include <linux/err.h>
14 #include <linux/genalloc.h>
15 #include <linux/pie.h>
16 #include <asm/cacheflush.h>
19 struct gen_pool *pool;
24 extern char __pie_common_start[];
25 extern char __pie_common_end[];
26 extern char __pie_overlay_start[];
28 int __weak pie_arch_fill_tail(void *tail, void *common_start, void *common_end,
29 void *overlay_start, void *code_start, void *code_end,
30 void *rel_start, void *rel_end)
35 int __weak pie_arch_fixup(struct pie_chunk *chunk, void *base, void *tail,
41 struct pie_chunk *__pie_load_data(struct gen_pool *pool, bool phys,
42 void *code_start, void *code_end,
43 void *rel_start, void *rel_end)
45 struct pie_chunk *chunk;
53 /* Calculate the tail size */
54 ret = pie_arch_fill_tail(NULL, __pie_common_start, __pie_common_end,
55 __pie_overlay_start, code_start, code_end,
61 chunk = kzalloc(sizeof(*chunk), GFP_KERNEL);
67 common_sz = __pie_overlay_start - __pie_common_start;
68 code_sz = code_end - code_start;
71 chunk->sz = common_sz + code_sz + tail_sz;
73 chunk->addr = gen_pool_alloc(pool, chunk->sz);
79 /* Copy common code/data */
80 tail = (char *) chunk->addr;
81 memcpy(tail, __pie_common_start, common_sz);
84 /* Copy chunk specific code/data */
85 memcpy(tail, code_start, code_sz);
88 /* Fill in tail data */
89 ret = pie_arch_fill_tail(tail, __pie_common_start, __pie_common_end,
90 __pie_overlay_start, code_start, code_end,
95 /* Calculate initial offset */
97 offset = gen_pool_virt_to_phys(pool, chunk->addr);
101 /* Perform arch specific code fixups */
102 ret = pie_arch_fixup(chunk, (void *) chunk->addr, tail, offset);
106 flush_icache_range(chunk->addr, chunk->addr + chunk->sz);
111 gen_pool_free(chunk->pool, chunk->addr, chunk->sz);
118 EXPORT_SYMBOL_GPL(__pie_load_data);
120 phys_addr_t pie_to_phys(struct pie_chunk *chunk, unsigned long addr)
122 return gen_pool_virt_to_phys(chunk->pool, addr);
124 EXPORT_SYMBOL_GPL(pie_to_phys);
126 void __iomem *__kern_to_pie(struct pie_chunk *chunk, void *ptr)
128 uintptr_t offset = (uintptr_t) ptr;
129 offset -= (uintptr_t) __pie_common_start;
130 if (offset >= chunk->sz)
133 return (void *) (chunk->addr + offset);
135 EXPORT_SYMBOL_GPL(__kern_to_pie);
137 void pie_free(struct pie_chunk *chunk)
139 gen_pool_free(chunk->pool, chunk->addr, chunk->sz);
142 EXPORT_SYMBOL_GPL(pie_free);