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)
34 int __weak pie_arch_fixup(struct pie_chunk *chunk, void *base, void *tail,
40 struct pie_chunk *__pie_load_data(struct gen_pool *pool, void *code_start,
41 void *code_end, bool phys)
43 struct pie_chunk *chunk;
51 /* Calculate the tail size */
52 ret = pie_arch_fill_tail(NULL, __pie_common_start, __pie_common_end,
53 __pie_overlay_start, code_start, code_end);
58 chunk = kzalloc(sizeof(*chunk), GFP_KERNEL);
64 common_sz = __pie_overlay_start - __pie_common_start;
65 code_sz = code_end - code_start;
68 chunk->sz = common_sz + code_sz + tail_sz;
70 chunk->addr = gen_pool_alloc(pool, chunk->sz);
76 /* Copy common code/data */
77 tail = (char *) chunk->addr;
78 memcpy(tail, __pie_common_start, common_sz);
81 /* Copy chunk specific code/data */
82 memcpy(tail, code_start, code_sz);
85 /* Fill in tail data */
86 ret = pie_arch_fill_tail(tail, __pie_common_start, __pie_common_end,
87 __pie_overlay_start, code_start, code_end);
91 /* Calculate initial offset */
93 offset = gen_pool_virt_to_phys(pool, chunk->addr);
97 /* Perform arch specific code fixups */
98 ret = pie_arch_fixup(chunk, (void *) chunk->addr, tail, offset);
102 flush_icache_range(chunk->addr, chunk->addr + chunk->sz);
107 gen_pool_free(chunk->pool, chunk->addr, chunk->sz);
114 EXPORT_SYMBOL_GPL(__pie_load_data);
116 phys_addr_t pie_to_phys(struct pie_chunk *chunk, unsigned long addr)
118 return gen_pool_virt_to_phys(chunk->pool, addr);
120 EXPORT_SYMBOL_GPL(pie_to_phys);
122 void __iomem *__kern_to_pie(struct pie_chunk *chunk, void *ptr)
124 uintptr_t offset = (uintptr_t) ptr;
125 offset -= (uintptr_t) __pie_common_start;
126 if (offset >= chunk->sz)
129 return (void *) (chunk->addr + offset);
131 EXPORT_SYMBOL_GPL(__kern_to_pie);
133 void pie_free(struct pie_chunk *chunk)
135 gen_pool_free(chunk->pool, chunk->addr, chunk->sz);
138 EXPORT_SYMBOL_GPL(pie_free);