diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-24 15:48:04 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-24 15:48:04 -0400 |
commit | cdc63a059508b96cad1de793437ad2296d80ffe6 (patch) | |
tree | 634915208a439d85d61e4a06c645f3fab3a551a3 /arch/arm64 | |
parent | 83da00fbc0c57ce6f84455156a2e3cc057fe7344 (diff) | |
parent | 3dec0fe48a8936528aae2fc3f904c2c9a34ba368 (diff) |
Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
Pull arm64 fixes from Catalin Marinas:
- enable 48-bit VA space now that KVM has been fixed, together with a
couple of fixes for pgd allocation alignment and initial memblock
current_limit. There is still a dependency on !ARM_SMMU which needs
to be updated as it uses the page table manipulation macros of the
host kernel
- eBPF fixes following changes/conflicts during the merging window
- Compat types affecting compat_elf_prpsinfo
- Compilation error on UP builds
- ASLR fix when /proc/sys/kernel/randomize_va_space == 0
- DT definitions for CLCD support on ARMv8 model platform
* tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux:
arm64: Fix memblock current_limit with 64K pages and 48-bit VA
arm64: ASLR: Don't randomise text when randomise_va_space == 0
arm64: vexpress: Add CLCD support to the ARMv8 model platform
arm64: Fix compilation error on UP builds
Documentation/arm64/memory.txt: fix typo
net: bpf: arm64: minor fix of type in jited
arm64: bpf: add 'load 64-bit immediate' instruction
arm64: bpf: add 'shift by register' instructions
net: bpf: arm64: address randomize and write protect JIT code
arm64: mm: Correct fixmap pagetable types
arm64: compat: fix compat types affecting struct compat_elf_prpsinfo
arm64: Align less than PAGE_SIZE pgds naturally
arm64: Allow 48-bits VA space without ARM_SMMU
Diffstat (limited to 'arch/arm64')
-rw-r--r-- | arch/arm64/Kconfig | 3 | ||||
-rw-r--r-- | arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi | 35 | ||||
-rw-r--r-- | arch/arm64/configs/defconfig | 2 | ||||
-rw-r--r-- | arch/arm64/include/asm/compat.h | 4 | ||||
-rw-r--r-- | arch/arm64/include/asm/elf.h | 4 | ||||
-rw-r--r-- | arch/arm64/include/asm/irq_work.h | 11 | ||||
-rw-r--r-- | arch/arm64/kernel/process.c | 5 | ||||
-rw-r--r-- | arch/arm64/mm/ioremap.c | 4 | ||||
-rw-r--r-- | arch/arm64/mm/mmu.c | 12 | ||||
-rw-r--r-- | arch/arm64/mm/pgd.c | 18 | ||||
-rw-r--r-- | arch/arm64/net/bpf_jit.h | 8 | ||||
-rw-r--r-- | arch/arm64/net/bpf_jit_comp.c | 84 |
12 files changed, 159 insertions, 31 deletions
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index ac9afde76dea..9532f8d5857e 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig | |||
@@ -1,5 +1,6 @@ | |||
1 | config ARM64 | 1 | config ARM64 |
2 | def_bool y | 2 | def_bool y |
3 | select ARCH_BINFMT_ELF_RANDOMIZE_PIE | ||
3 | select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE | 4 | select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE |
4 | select ARCH_HAS_SG_CHAIN | 5 | select ARCH_HAS_SG_CHAIN |
5 | select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST | 6 | select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST |
@@ -232,7 +233,7 @@ config ARM64_VA_BITS_42 | |||
232 | 233 | ||
233 | config ARM64_VA_BITS_48 | 234 | config ARM64_VA_BITS_48 |
234 | bool "48-bit" | 235 | bool "48-bit" |
235 | depends on BROKEN | 236 | depends on !ARM_SMMU |
236 | 237 | ||
237 | endchoice | 238 | endchoice |
238 | 239 | ||
diff --git a/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi b/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi index ac2cb2418025..c46cbb29f3c6 100644 --- a/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi +++ b/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi | |||
@@ -22,7 +22,7 @@ | |||
22 | bank-width = <4>; | 22 | bank-width = <4>; |
23 | }; | 23 | }; |
24 | 24 | ||
25 | vram@2,00000000 { | 25 | v2m_video_ram: vram@2,00000000 { |
26 | compatible = "arm,vexpress-vram"; | 26 | compatible = "arm,vexpress-vram"; |
27 | reg = <2 0x00000000 0x00800000>; | 27 | reg = <2 0x00000000 0x00800000>; |
28 | }; | 28 | }; |
@@ -179,9 +179,42 @@ | |||
179 | clcd@1f0000 { | 179 | clcd@1f0000 { |
180 | compatible = "arm,pl111", "arm,primecell"; | 180 | compatible = "arm,pl111", "arm,primecell"; |
181 | reg = <0x1f0000 0x1000>; | 181 | reg = <0x1f0000 0x1000>; |
182 | interrupt-names = "combined"; | ||
182 | interrupts = <14>; | 183 | interrupts = <14>; |
183 | clocks = <&v2m_oscclk1>, <&v2m_clk24mhz>; | 184 | clocks = <&v2m_oscclk1>, <&v2m_clk24mhz>; |
184 | clock-names = "clcdclk", "apb_pclk"; | 185 | clock-names = "clcdclk", "apb_pclk"; |
186 | arm,pl11x,framebuffer = <0x18000000 0x00180000>; | ||
187 | memory-region = <&v2m_video_ram>; | ||
188 | max-memory-bandwidth = <130000000>; /* 16bpp @ 63.5MHz */ | ||
189 | |||
190 | port { | ||
191 | v2m_clcd_pads: endpoint { | ||
192 | remote-endpoint = <&v2m_clcd_panel>; | ||
193 | arm,pl11x,tft-r0g0b0-pads = <0 8 16>; | ||
194 | }; | ||
195 | }; | ||
196 | |||
197 | panel { | ||
198 | compatible = "panel-dpi"; | ||
199 | |||
200 | port { | ||
201 | v2m_clcd_panel: endpoint { | ||
202 | remote-endpoint = <&v2m_clcd_pads>; | ||
203 | }; | ||
204 | }; | ||
205 | |||
206 | panel-timing { | ||
207 | clock-frequency = <63500127>; | ||
208 | hactive = <1024>; | ||
209 | hback-porch = <152>; | ||
210 | hfront-porch = <48>; | ||
211 | hsync-len = <104>; | ||
212 | vactive = <768>; | ||
213 | vback-porch = <23>; | ||
214 | vfront-porch = <3>; | ||
215 | vsync-len = <4>; | ||
216 | }; | ||
217 | }; | ||
185 | }; | 218 | }; |
186 | 219 | ||
187 | virtio_block@0130000 { | 220 | virtio_block@0130000 { |
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 9cd37de9aa8d..4ce602c2c6de 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig | |||
@@ -78,6 +78,7 @@ CONFIG_NET_XGENE=y | |||
78 | # CONFIG_WLAN is not set | 78 | # CONFIG_WLAN is not set |
79 | CONFIG_INPUT_EVDEV=y | 79 | CONFIG_INPUT_EVDEV=y |
80 | # CONFIG_SERIO_SERPORT is not set | 80 | # CONFIG_SERIO_SERPORT is not set |
81 | CONFIG_SERIO_AMBAKMI=y | ||
81 | CONFIG_LEGACY_PTY_COUNT=16 | 82 | CONFIG_LEGACY_PTY_COUNT=16 |
82 | CONFIG_SERIAL_8250=y | 83 | CONFIG_SERIAL_8250=y |
83 | CONFIG_SERIAL_8250_CONSOLE=y | 84 | CONFIG_SERIAL_8250_CONSOLE=y |
@@ -90,6 +91,7 @@ CONFIG_VIRTIO_CONSOLE=y | |||
90 | CONFIG_REGULATOR=y | 91 | CONFIG_REGULATOR=y |
91 | CONFIG_REGULATOR_FIXED_VOLTAGE=y | 92 | CONFIG_REGULATOR_FIXED_VOLTAGE=y |
92 | CONFIG_FB=y | 93 | CONFIG_FB=y |
94 | CONFIG_FB_ARMCLCD=y | ||
93 | CONFIG_FRAMEBUFFER_CONSOLE=y | 95 | CONFIG_FRAMEBUFFER_CONSOLE=y |
94 | CONFIG_LOGO=y | 96 | CONFIG_LOGO=y |
95 | # CONFIG_LOGO_LINUX_MONO is not set | 97 | # CONFIG_LOGO_LINUX_MONO is not set |
diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h index 253e33bc94fb..56de5aadede2 100644 --- a/arch/arm64/include/asm/compat.h +++ b/arch/arm64/include/asm/compat.h | |||
@@ -37,8 +37,8 @@ typedef s32 compat_ssize_t; | |||
37 | typedef s32 compat_time_t; | 37 | typedef s32 compat_time_t; |
38 | typedef s32 compat_clock_t; | 38 | typedef s32 compat_clock_t; |
39 | typedef s32 compat_pid_t; | 39 | typedef s32 compat_pid_t; |
40 | typedef u32 __compat_uid_t; | 40 | typedef u16 __compat_uid_t; |
41 | typedef u32 __compat_gid_t; | 41 | typedef u16 __compat_gid_t; |
42 | typedef u16 __compat_uid16_t; | 42 | typedef u16 __compat_uid16_t; |
43 | typedef u16 __compat_gid16_t; | 43 | typedef u16 __compat_gid16_t; |
44 | typedef u32 __compat_uid32_t; | 44 | typedef u32 __compat_uid32_t; |
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h index 01d3aab64b79..1f65be393139 100644 --- a/arch/arm64/include/asm/elf.h +++ b/arch/arm64/include/asm/elf.h | |||
@@ -126,7 +126,7 @@ typedef struct user_fpsimd_state elf_fpregset_t; | |||
126 | * that it will "exec", and that there is sufficient room for the brk. | 126 | * that it will "exec", and that there is sufficient room for the brk. |
127 | */ | 127 | */ |
128 | extern unsigned long randomize_et_dyn(unsigned long base); | 128 | extern unsigned long randomize_et_dyn(unsigned long base); |
129 | #define ELF_ET_DYN_BASE (randomize_et_dyn(2 * TASK_SIZE_64 / 3)) | 129 | #define ELF_ET_DYN_BASE (2 * TASK_SIZE_64 / 3) |
130 | 130 | ||
131 | /* | 131 | /* |
132 | * When the program starts, a1 contains a pointer to a function to be | 132 | * When the program starts, a1 contains a pointer to a function to be |
@@ -169,7 +169,7 @@ extern unsigned long arch_randomize_brk(struct mm_struct *mm); | |||
169 | #define COMPAT_ELF_PLATFORM ("v8l") | 169 | #define COMPAT_ELF_PLATFORM ("v8l") |
170 | #endif | 170 | #endif |
171 | 171 | ||
172 | #define COMPAT_ELF_ET_DYN_BASE (randomize_et_dyn(2 * TASK_SIZE_32 / 3)) | 172 | #define COMPAT_ELF_ET_DYN_BASE (2 * TASK_SIZE_32 / 3) |
173 | 173 | ||
174 | /* AArch32 registers. */ | 174 | /* AArch32 registers. */ |
175 | #define COMPAT_ELF_NGREG 18 | 175 | #define COMPAT_ELF_NGREG 18 |
diff --git a/arch/arm64/include/asm/irq_work.h b/arch/arm64/include/asm/irq_work.h index 8e24ef3f7c82..b4f6b19a8a68 100644 --- a/arch/arm64/include/asm/irq_work.h +++ b/arch/arm64/include/asm/irq_work.h | |||
@@ -1,6 +1,8 @@ | |||
1 | #ifndef __ASM_IRQ_WORK_H | 1 | #ifndef __ASM_IRQ_WORK_H |
2 | #define __ASM_IRQ_WORK_H | 2 | #define __ASM_IRQ_WORK_H |
3 | 3 | ||
4 | #ifdef CONFIG_SMP | ||
5 | |||
4 | #include <asm/smp.h> | 6 | #include <asm/smp.h> |
5 | 7 | ||
6 | static inline bool arch_irq_work_has_interrupt(void) | 8 | static inline bool arch_irq_work_has_interrupt(void) |
@@ -8,4 +10,13 @@ static inline bool arch_irq_work_has_interrupt(void) | |||
8 | return !!__smp_cross_call; | 10 | return !!__smp_cross_call; |
9 | } | 11 | } |
10 | 12 | ||
13 | #else | ||
14 | |||
15 | static inline bool arch_irq_work_has_interrupt(void) | ||
16 | { | ||
17 | return false; | ||
18 | } | ||
19 | |||
20 | #endif | ||
21 | |||
11 | #endif /* __ASM_IRQ_WORK_H */ | 22 | #endif /* __ASM_IRQ_WORK_H */ |
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index c3065dbc4fa2..fde9923af859 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c | |||
@@ -378,8 +378,3 @@ unsigned long arch_randomize_brk(struct mm_struct *mm) | |||
378 | { | 378 | { |
379 | return randomize_base(mm->brk); | 379 | return randomize_base(mm->brk); |
380 | } | 380 | } |
381 | |||
382 | unsigned long randomize_et_dyn(unsigned long base) | ||
383 | { | ||
384 | return randomize_base(base); | ||
385 | } | ||
diff --git a/arch/arm64/mm/ioremap.c b/arch/arm64/mm/ioremap.c index fa324bd5a5c4..4a07630a6616 100644 --- a/arch/arm64/mm/ioremap.c +++ b/arch/arm64/mm/ioremap.c | |||
@@ -105,10 +105,10 @@ EXPORT_SYMBOL(ioremap_cache); | |||
105 | 105 | ||
106 | static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss; | 106 | static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss; |
107 | #if CONFIG_ARM64_PGTABLE_LEVELS > 2 | 107 | #if CONFIG_ARM64_PGTABLE_LEVELS > 2 |
108 | static pte_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss; | 108 | static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss; |
109 | #endif | 109 | #endif |
110 | #if CONFIG_ARM64_PGTABLE_LEVELS > 3 | 110 | #if CONFIG_ARM64_PGTABLE_LEVELS > 3 |
111 | static pte_t bm_pud[PTRS_PER_PUD] __page_aligned_bss; | 111 | static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss; |
112 | #endif | 112 | #endif |
113 | 113 | ||
114 | static inline pud_t * __init early_ioremap_pud(unsigned long addr) | 114 | static inline pud_t * __init early_ioremap_pud(unsigned long addr) |
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 6894ef3e6234..0bf90d26e745 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c | |||
@@ -297,11 +297,15 @@ static void __init map_mem(void) | |||
297 | * create_mapping requires puds, pmds and ptes to be allocated from | 297 | * create_mapping requires puds, pmds and ptes to be allocated from |
298 | * memory addressable from the initial direct kernel mapping. | 298 | * memory addressable from the initial direct kernel mapping. |
299 | * | 299 | * |
300 | * The initial direct kernel mapping, located at swapper_pg_dir, | 300 | * The initial direct kernel mapping, located at swapper_pg_dir, gives |
301 | * gives us PUD_SIZE memory starting from PHYS_OFFSET (which must be | 301 | * us PUD_SIZE (4K pages) or PMD_SIZE (64K pages) memory starting from |
302 | * aligned to 2MB as per Documentation/arm64/booting.txt). | 302 | * PHYS_OFFSET (which must be aligned to 2MB as per |
303 | * Documentation/arm64/booting.txt). | ||
303 | */ | 304 | */ |
304 | limit = PHYS_OFFSET + PUD_SIZE; | 305 | if (IS_ENABLED(CONFIG_ARM64_64K_PAGES)) |
306 | limit = PHYS_OFFSET + PMD_SIZE; | ||
307 | else | ||
308 | limit = PHYS_OFFSET + PUD_SIZE; | ||
305 | memblock_set_current_limit(limit); | 309 | memblock_set_current_limit(limit); |
306 | 310 | ||
307 | /* map all the memory banks */ | 311 | /* map all the memory banks */ |
diff --git a/arch/arm64/mm/pgd.c b/arch/arm64/mm/pgd.c index 62c6101df260..6682b361d3ac 100644 --- a/arch/arm64/mm/pgd.c +++ b/arch/arm64/mm/pgd.c | |||
@@ -30,12 +30,14 @@ | |||
30 | 30 | ||
31 | #define PGD_SIZE (PTRS_PER_PGD * sizeof(pgd_t)) | 31 | #define PGD_SIZE (PTRS_PER_PGD * sizeof(pgd_t)) |
32 | 32 | ||
33 | static struct kmem_cache *pgd_cache; | ||
34 | |||
33 | pgd_t *pgd_alloc(struct mm_struct *mm) | 35 | pgd_t *pgd_alloc(struct mm_struct *mm) |
34 | { | 36 | { |
35 | if (PGD_SIZE == PAGE_SIZE) | 37 | if (PGD_SIZE == PAGE_SIZE) |
36 | return (pgd_t *)get_zeroed_page(GFP_KERNEL); | 38 | return (pgd_t *)get_zeroed_page(GFP_KERNEL); |
37 | else | 39 | else |
38 | return kzalloc(PGD_SIZE, GFP_KERNEL); | 40 | return kmem_cache_zalloc(pgd_cache, GFP_KERNEL); |
39 | } | 41 | } |
40 | 42 | ||
41 | void pgd_free(struct mm_struct *mm, pgd_t *pgd) | 43 | void pgd_free(struct mm_struct *mm, pgd_t *pgd) |
@@ -43,5 +45,17 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd) | |||
43 | if (PGD_SIZE == PAGE_SIZE) | 45 | if (PGD_SIZE == PAGE_SIZE) |
44 | free_page((unsigned long)pgd); | 46 | free_page((unsigned long)pgd); |
45 | else | 47 | else |
46 | kfree(pgd); | 48 | kmem_cache_free(pgd_cache, pgd); |
49 | } | ||
50 | |||
51 | static int __init pgd_cache_init(void) | ||
52 | { | ||
53 | /* | ||
54 | * Naturally aligned pgds required by the architecture. | ||
55 | */ | ||
56 | if (PGD_SIZE != PAGE_SIZE) | ||
57 | pgd_cache = kmem_cache_create("pgd_cache", PGD_SIZE, PGD_SIZE, | ||
58 | SLAB_PANIC, NULL); | ||
59 | return 0; | ||
47 | } | 60 | } |
61 | core_initcall(pgd_cache_init); | ||
diff --git a/arch/arm64/net/bpf_jit.h b/arch/arm64/net/bpf_jit.h index 2134f7e6c288..de0a81a539a0 100644 --- a/arch/arm64/net/bpf_jit.h +++ b/arch/arm64/net/bpf_jit.h | |||
@@ -144,8 +144,12 @@ | |||
144 | 144 | ||
145 | /* Data-processing (2 source) */ | 145 | /* Data-processing (2 source) */ |
146 | /* Rd = Rn OP Rm */ | 146 | /* Rd = Rn OP Rm */ |
147 | #define A64_UDIV(sf, Rd, Rn, Rm) aarch64_insn_gen_data2(Rd, Rn, Rm, \ | 147 | #define A64_DATA2(sf, Rd, Rn, Rm, type) aarch64_insn_gen_data2(Rd, Rn, Rm, \ |
148 | A64_VARIANT(sf), AARCH64_INSN_DATA2_UDIV) | 148 | A64_VARIANT(sf), AARCH64_INSN_DATA2_##type) |
149 | #define A64_UDIV(sf, Rd, Rn, Rm) A64_DATA2(sf, Rd, Rn, Rm, UDIV) | ||
150 | #define A64_LSLV(sf, Rd, Rn, Rm) A64_DATA2(sf, Rd, Rn, Rm, LSLV) | ||
151 | #define A64_LSRV(sf, Rd, Rn, Rm) A64_DATA2(sf, Rd, Rn, Rm, LSRV) | ||
152 | #define A64_ASRV(sf, Rd, Rn, Rm) A64_DATA2(sf, Rd, Rn, Rm, ASRV) | ||
149 | 153 | ||
150 | /* Data-processing (3 source) */ | 154 | /* Data-processing (3 source) */ |
151 | /* Rd = Ra + Rn * Rm */ | 155 | /* Rd = Ra + Rn * Rm */ |
diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index 7ae33545535b..41f1e3e2ea24 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c | |||
@@ -19,12 +19,13 @@ | |||
19 | #define pr_fmt(fmt) "bpf_jit: " fmt | 19 | #define pr_fmt(fmt) "bpf_jit: " fmt |
20 | 20 | ||
21 | #include <linux/filter.h> | 21 | #include <linux/filter.h> |
22 | #include <linux/moduleloader.h> | ||
23 | #include <linux/printk.h> | 22 | #include <linux/printk.h> |
24 | #include <linux/skbuff.h> | 23 | #include <linux/skbuff.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | |||
26 | #include <asm/byteorder.h> | 26 | #include <asm/byteorder.h> |
27 | #include <asm/cacheflush.h> | 27 | #include <asm/cacheflush.h> |
28 | #include <asm/debug-monitors.h> | ||
28 | 29 | ||
29 | #include "bpf_jit.h" | 30 | #include "bpf_jit.h" |
30 | 31 | ||
@@ -119,6 +120,14 @@ static inline int bpf2a64_offset(int bpf_to, int bpf_from, | |||
119 | return to - from; | 120 | return to - from; |
120 | } | 121 | } |
121 | 122 | ||
123 | static void jit_fill_hole(void *area, unsigned int size) | ||
124 | { | ||
125 | u32 *ptr; | ||
126 | /* We are guaranteed to have aligned memory. */ | ||
127 | for (ptr = area; size >= sizeof(u32); size -= sizeof(u32)) | ||
128 | *ptr++ = cpu_to_le32(AARCH64_BREAK_FAULT); | ||
129 | } | ||
130 | |||
122 | static inline int epilogue_offset(const struct jit_ctx *ctx) | 131 | static inline int epilogue_offset(const struct jit_ctx *ctx) |
123 | { | 132 | { |
124 | int to = ctx->offset[ctx->prog->len - 1]; | 133 | int to = ctx->offset[ctx->prog->len - 1]; |
@@ -196,6 +205,12 @@ static void build_epilogue(struct jit_ctx *ctx) | |||
196 | emit(A64_RET(A64_LR), ctx); | 205 | emit(A64_RET(A64_LR), ctx); |
197 | } | 206 | } |
198 | 207 | ||
208 | /* JITs an eBPF instruction. | ||
209 | * Returns: | ||
210 | * 0 - successfully JITed an 8-byte eBPF instruction. | ||
211 | * >0 - successfully JITed a 16-byte eBPF instruction. | ||
212 | * <0 - failed to JIT. | ||
213 | */ | ||
199 | static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) | 214 | static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) |
200 | { | 215 | { |
201 | const u8 code = insn->code; | 216 | const u8 code = insn->code; |
@@ -252,6 +267,18 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) | |||
252 | emit(A64_MUL(is64, tmp, tmp, src), ctx); | 267 | emit(A64_MUL(is64, tmp, tmp, src), ctx); |
253 | emit(A64_SUB(is64, dst, dst, tmp), ctx); | 268 | emit(A64_SUB(is64, dst, dst, tmp), ctx); |
254 | break; | 269 | break; |
270 | case BPF_ALU | BPF_LSH | BPF_X: | ||
271 | case BPF_ALU64 | BPF_LSH | BPF_X: | ||
272 | emit(A64_LSLV(is64, dst, dst, src), ctx); | ||
273 | break; | ||
274 | case BPF_ALU | BPF_RSH | BPF_X: | ||
275 | case BPF_ALU64 | BPF_RSH | BPF_X: | ||
276 | emit(A64_LSRV(is64, dst, dst, src), ctx); | ||
277 | break; | ||
278 | case BPF_ALU | BPF_ARSH | BPF_X: | ||
279 | case BPF_ALU64 | BPF_ARSH | BPF_X: | ||
280 | emit(A64_ASRV(is64, dst, dst, src), ctx); | ||
281 | break; | ||
255 | /* dst = -dst */ | 282 | /* dst = -dst */ |
256 | case BPF_ALU | BPF_NEG: | 283 | case BPF_ALU | BPF_NEG: |
257 | case BPF_ALU64 | BPF_NEG: | 284 | case BPF_ALU64 | BPF_NEG: |
@@ -443,6 +470,27 @@ emit_cond_jmp: | |||
443 | emit(A64_B(jmp_offset), ctx); | 470 | emit(A64_B(jmp_offset), ctx); |
444 | break; | 471 | break; |
445 | 472 | ||
473 | /* dst = imm64 */ | ||
474 | case BPF_LD | BPF_IMM | BPF_DW: | ||
475 | { | ||
476 | const struct bpf_insn insn1 = insn[1]; | ||
477 | u64 imm64; | ||
478 | |||
479 | if (insn1.code != 0 || insn1.src_reg != 0 || | ||
480 | insn1.dst_reg != 0 || insn1.off != 0) { | ||
481 | /* Note: verifier in BPF core must catch invalid | ||
482 | * instructions. | ||
483 | */ | ||
484 | pr_err_once("Invalid BPF_LD_IMM64 instruction\n"); | ||
485 | return -EINVAL; | ||
486 | } | ||
487 | |||
488 | imm64 = (u64)insn1.imm << 32 | imm; | ||
489 | emit_a64_mov_i64(dst, imm64, ctx); | ||
490 | |||
491 | return 1; | ||
492 | } | ||
493 | |||
446 | /* LDX: dst = *(size *)(src + off) */ | 494 | /* LDX: dst = *(size *)(src + off) */ |
447 | case BPF_LDX | BPF_MEM | BPF_W: | 495 | case BPF_LDX | BPF_MEM | BPF_W: |
448 | case BPF_LDX | BPF_MEM | BPF_H: | 496 | case BPF_LDX | BPF_MEM | BPF_H: |
@@ -594,6 +642,10 @@ static int build_body(struct jit_ctx *ctx) | |||
594 | ctx->offset[i] = ctx->idx; | 642 | ctx->offset[i] = ctx->idx; |
595 | 643 | ||
596 | ret = build_insn(insn, ctx); | 644 | ret = build_insn(insn, ctx); |
645 | if (ret > 0) { | ||
646 | i++; | ||
647 | continue; | ||
648 | } | ||
597 | if (ret) | 649 | if (ret) |
598 | return ret; | 650 | return ret; |
599 | } | 651 | } |
@@ -613,8 +665,10 @@ void bpf_jit_compile(struct bpf_prog *prog) | |||
613 | 665 | ||
614 | void bpf_int_jit_compile(struct bpf_prog *prog) | 666 | void bpf_int_jit_compile(struct bpf_prog *prog) |
615 | { | 667 | { |
668 | struct bpf_binary_header *header; | ||
616 | struct jit_ctx ctx; | 669 | struct jit_ctx ctx; |
617 | int image_size; | 670 | int image_size; |
671 | u8 *image_ptr; | ||
618 | 672 | ||
619 | if (!bpf_jit_enable) | 673 | if (!bpf_jit_enable) |
620 | return; | 674 | return; |
@@ -636,23 +690,25 @@ void bpf_int_jit_compile(struct bpf_prog *prog) | |||
636 | goto out; | 690 | goto out; |
637 | 691 | ||
638 | build_prologue(&ctx); | 692 | build_prologue(&ctx); |
639 | |||
640 | build_epilogue(&ctx); | 693 | build_epilogue(&ctx); |
641 | 694 | ||
642 | /* Now we know the actual image size. */ | 695 | /* Now we know the actual image size. */ |
643 | image_size = sizeof(u32) * ctx.idx; | 696 | image_size = sizeof(u32) * ctx.idx; |
644 | ctx.image = module_alloc(image_size); | 697 | header = bpf_jit_binary_alloc(image_size, &image_ptr, |
645 | if (unlikely(ctx.image == NULL)) | 698 | sizeof(u32), jit_fill_hole); |
699 | if (header == NULL) | ||
646 | goto out; | 700 | goto out; |
647 | 701 | ||
648 | /* 2. Now, the actual pass. */ | 702 | /* 2. Now, the actual pass. */ |
649 | 703 | ||
704 | ctx.image = (u32 *)image_ptr; | ||
650 | ctx.idx = 0; | 705 | ctx.idx = 0; |
706 | |||
651 | build_prologue(&ctx); | 707 | build_prologue(&ctx); |
652 | 708 | ||
653 | ctx.body_offset = ctx.idx; | 709 | ctx.body_offset = ctx.idx; |
654 | if (build_body(&ctx)) { | 710 | if (build_body(&ctx)) { |
655 | module_free(NULL, ctx.image); | 711 | bpf_jit_binary_free(header); |
656 | goto out; | 712 | goto out; |
657 | } | 713 | } |
658 | 714 | ||
@@ -663,17 +719,25 @@ void bpf_int_jit_compile(struct bpf_prog *prog) | |||
663 | bpf_jit_dump(prog->len, image_size, 2, ctx.image); | 719 | bpf_jit_dump(prog->len, image_size, 2, ctx.image); |
664 | 720 | ||
665 | bpf_flush_icache(ctx.image, ctx.image + ctx.idx); | 721 | bpf_flush_icache(ctx.image, ctx.image + ctx.idx); |
666 | prog->bpf_func = (void *)ctx.image; | ||
667 | prog->jited = 1; | ||
668 | 722 | ||
723 | set_memory_ro((unsigned long)header, header->pages); | ||
724 | prog->bpf_func = (void *)ctx.image; | ||
725 | prog->jited = true; | ||
669 | out: | 726 | out: |
670 | kfree(ctx.offset); | 727 | kfree(ctx.offset); |
671 | } | 728 | } |
672 | 729 | ||
673 | void bpf_jit_free(struct bpf_prog *prog) | 730 | void bpf_jit_free(struct bpf_prog *prog) |
674 | { | 731 | { |
675 | if (prog->jited) | 732 | unsigned long addr = (unsigned long)prog->bpf_func & PAGE_MASK; |
676 | module_free(NULL, prog->bpf_func); | 733 | struct bpf_binary_header *header = (void *)addr; |
734 | |||
735 | if (!prog->jited) | ||
736 | goto free_filter; | ||
737 | |||
738 | set_memory_rw(addr, header->pages); | ||
739 | bpf_jit_binary_free(header); | ||
677 | 740 | ||
678 | kfree(prog); | 741 | free_filter: |
742 | bpf_prog_unlock_free(prog); | ||
679 | } | 743 | } |