diff options
| -rw-r--r-- | Documentation/arm64/memory.txt | 2 | ||||
| -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 |
13 files changed, 160 insertions, 32 deletions
diff --git a/Documentation/arm64/memory.txt b/Documentation/arm64/memory.txt index 344e85cc7323..d7273a5f6456 100644 --- a/Documentation/arm64/memory.txt +++ b/Documentation/arm64/memory.txt | |||
| @@ -17,7 +17,7 @@ User addresses have bits 63:48 set to 0 while the kernel addresses have | |||
| 17 | the same bits set to 1. TTBRx selection is given by bit 63 of the | 17 | the same bits set to 1. TTBRx selection is given by bit 63 of the |
| 18 | virtual address. The swapper_pg_dir contains only kernel (global) | 18 | virtual address. The swapper_pg_dir contains only kernel (global) |
| 19 | mappings while the user pgd contains only user (non-global) mappings. | 19 | mappings while the user pgd contains only user (non-global) mappings. |
| 20 | The swapper_pgd_dir address is written to TTBR1 and never written to | 20 | The swapper_pg_dir address is written to TTBR1 and never written to |
| 21 | TTBR0. | 21 | TTBR0. |
| 22 | 22 | ||
| 23 | 23 | ||
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 | } |
