Răsfoiți Sursa

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
Linus Torvalds 10 ani în urmă
părinte
comite
cdc63a0595

+ 1 - 1
Documentation/arm64/memory.txt

@@ -17,7 +17,7 @@ User addresses have bits 63:48 set to 0 while the kernel addresses have
 the same bits set to 1. TTBRx selection is given by bit 63 of the
 the same bits set to 1. TTBRx selection is given by bit 63 of the
 virtual address. The swapper_pg_dir contains only kernel (global)
 virtual address. The swapper_pg_dir contains only kernel (global)
 mappings while the user pgd contains only user (non-global) mappings.
 mappings while the user pgd contains only user (non-global) mappings.
-The swapper_pgd_dir address is written to TTBR1 and never written to
+The swapper_pg_dir address is written to TTBR1 and never written to
 TTBR0.
 TTBR0.
 
 
 
 

+ 2 - 1
arch/arm64/Kconfig

@@ -1,5 +1,6 @@
 config ARM64
 config ARM64
 	def_bool y
 	def_bool y
+	select ARCH_BINFMT_ELF_RANDOMIZE_PIE
 	select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
 	select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
 	select ARCH_HAS_SG_CHAIN
 	select ARCH_HAS_SG_CHAIN
 	select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
 	select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
@@ -232,7 +233,7 @@ config ARM64_VA_BITS_42
 
 
 config ARM64_VA_BITS_48
 config ARM64_VA_BITS_48
 	bool "48-bit"
 	bool "48-bit"
-	depends on BROKEN
+	depends on !ARM_SMMU
 
 
 endchoice
 endchoice
 
 

+ 34 - 1
arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi

@@ -22,7 +22,7 @@
 			bank-width = <4>;
 			bank-width = <4>;
 		};
 		};
 
 
-		vram@2,00000000 {
+		v2m_video_ram: vram@2,00000000 {
 			compatible = "arm,vexpress-vram";
 			compatible = "arm,vexpress-vram";
 			reg = <2 0x00000000 0x00800000>;
 			reg = <2 0x00000000 0x00800000>;
 		};
 		};
@@ -179,9 +179,42 @@
 			clcd@1f0000 {
 			clcd@1f0000 {
 				compatible = "arm,pl111", "arm,primecell";
 				compatible = "arm,pl111", "arm,primecell";
 				reg = <0x1f0000 0x1000>;
 				reg = <0x1f0000 0x1000>;
+				interrupt-names = "combined";
 				interrupts = <14>;
 				interrupts = <14>;
 				clocks = <&v2m_oscclk1>, <&v2m_clk24mhz>;
 				clocks = <&v2m_oscclk1>, <&v2m_clk24mhz>;
 				clock-names = "clcdclk", "apb_pclk";
 				clock-names = "clcdclk", "apb_pclk";
+				arm,pl11x,framebuffer = <0x18000000 0x00180000>;
+				memory-region = <&v2m_video_ram>;
+				max-memory-bandwidth = <130000000>; /* 16bpp @ 63.5MHz */
+
+				port {
+					v2m_clcd_pads: endpoint {
+						remote-endpoint = <&v2m_clcd_panel>;
+						arm,pl11x,tft-r0g0b0-pads = <0 8 16>;
+					};
+				};
+
+				panel {
+					compatible = "panel-dpi";
+
+					port {
+						v2m_clcd_panel: endpoint {
+							remote-endpoint = <&v2m_clcd_pads>;
+						};
+					};
+
+					panel-timing {
+						clock-frequency = <63500127>;
+						hactive = <1024>;
+						hback-porch = <152>;
+						hfront-porch = <48>;
+						hsync-len = <104>;
+						vactive = <768>;
+						vback-porch = <23>;
+						vfront-porch = <3>;
+						vsync-len = <4>;
+					};
+				};
 			};
 			};
 
 
 			virtio_block@0130000 {
 			virtio_block@0130000 {

+ 2 - 0
arch/arm64/configs/defconfig

@@ -78,6 +78,7 @@ CONFIG_NET_XGENE=y
 # CONFIG_WLAN is not set
 # CONFIG_WLAN is not set
 CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_EVDEV=y
 # CONFIG_SERIO_SERPORT is not set
 # CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIO_AMBAKMI=y
 CONFIG_LEGACY_PTY_COUNT=16
 CONFIG_LEGACY_PTY_COUNT=16
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_CONSOLE=y
@@ -90,6 +91,7 @@ CONFIG_VIRTIO_CONSOLE=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_FB=y
 CONFIG_FB=y
+CONFIG_FB_ARMCLCD=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
 CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_MONO is not set
 # CONFIG_LOGO_LINUX_MONO is not set

+ 2 - 2
arch/arm64/include/asm/compat.h

@@ -37,8 +37,8 @@ typedef s32		compat_ssize_t;
 typedef s32		compat_time_t;
 typedef s32		compat_time_t;
 typedef s32		compat_clock_t;
 typedef s32		compat_clock_t;
 typedef s32		compat_pid_t;
 typedef s32		compat_pid_t;
-typedef u32		__compat_uid_t;
-typedef u32		__compat_gid_t;
+typedef u16		__compat_uid_t;
+typedef u16		__compat_gid_t;
 typedef u16		__compat_uid16_t;
 typedef u16		__compat_uid16_t;
 typedef u16		__compat_gid16_t;
 typedef u16		__compat_gid16_t;
 typedef u32		__compat_uid32_t;
 typedef u32		__compat_uid32_t;

+ 2 - 2
arch/arm64/include/asm/elf.h

@@ -126,7 +126,7 @@ typedef struct user_fpsimd_state elf_fpregset_t;
  * that it will "exec", and that there is sufficient room for the brk.
  * that it will "exec", and that there is sufficient room for the brk.
  */
  */
 extern unsigned long randomize_et_dyn(unsigned long base);
 extern unsigned long randomize_et_dyn(unsigned long base);
-#define ELF_ET_DYN_BASE	(randomize_et_dyn(2 * TASK_SIZE_64 / 3))
+#define ELF_ET_DYN_BASE	(2 * TASK_SIZE_64 / 3)
 
 
 /*
 /*
  * When the program starts, a1 contains a pointer to a function to be
  * 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);
 #define COMPAT_ELF_PLATFORM		("v8l")
 #define COMPAT_ELF_PLATFORM		("v8l")
 #endif
 #endif
 
 
-#define COMPAT_ELF_ET_DYN_BASE		(randomize_et_dyn(2 * TASK_SIZE_32 / 3))
+#define COMPAT_ELF_ET_DYN_BASE		(2 * TASK_SIZE_32 / 3)
 
 
 /* AArch32 registers. */
 /* AArch32 registers. */
 #define COMPAT_ELF_NGREG		18
 #define COMPAT_ELF_NGREG		18

+ 11 - 0
arch/arm64/include/asm/irq_work.h

@@ -1,6 +1,8 @@
 #ifndef __ASM_IRQ_WORK_H
 #ifndef __ASM_IRQ_WORK_H
 #define __ASM_IRQ_WORK_H
 #define __ASM_IRQ_WORK_H
 
 
+#ifdef CONFIG_SMP
+
 #include <asm/smp.h>
 #include <asm/smp.h>
 
 
 static inline bool arch_irq_work_has_interrupt(void)
 static inline bool arch_irq_work_has_interrupt(void)
@@ -8,4 +10,13 @@ static inline bool arch_irq_work_has_interrupt(void)
 	return !!__smp_cross_call;
 	return !!__smp_cross_call;
 }
 }
 
 
+#else
+
+static inline bool arch_irq_work_has_interrupt(void)
+{
+	return false;
+}
+
+#endif
+
 #endif /* __ASM_IRQ_WORK_H */
 #endif /* __ASM_IRQ_WORK_H */

+ 0 - 5
arch/arm64/kernel/process.c

@@ -378,8 +378,3 @@ unsigned long arch_randomize_brk(struct mm_struct *mm)
 {
 {
 	return randomize_base(mm->brk);
 	return randomize_base(mm->brk);
 }
 }
-
-unsigned long randomize_et_dyn(unsigned long base)
-{
-	return randomize_base(base);
-}

+ 2 - 2
arch/arm64/mm/ioremap.c

@@ -105,10 +105,10 @@ EXPORT_SYMBOL(ioremap_cache);
 
 
 static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss;
 static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss;
 #if CONFIG_ARM64_PGTABLE_LEVELS > 2
 #if CONFIG_ARM64_PGTABLE_LEVELS > 2
-static pte_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss;
+static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss;
 #endif
 #endif
 #if CONFIG_ARM64_PGTABLE_LEVELS > 3
 #if CONFIG_ARM64_PGTABLE_LEVELS > 3
-static pte_t bm_pud[PTRS_PER_PUD] __page_aligned_bss;
+static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss;
 #endif
 #endif
 
 
 static inline pud_t * __init early_ioremap_pud(unsigned long addr)
 static inline pud_t * __init early_ioremap_pud(unsigned long addr)

+ 8 - 4
arch/arm64/mm/mmu.c

@@ -297,11 +297,15 @@ static void __init map_mem(void)
 	 * create_mapping requires puds, pmds and ptes to be allocated from
 	 * create_mapping requires puds, pmds and ptes to be allocated from
 	 * memory addressable from the initial direct kernel mapping.
 	 * memory addressable from the initial direct kernel mapping.
 	 *
 	 *
-	 * The initial direct kernel mapping, located at swapper_pg_dir,
-	 * gives us PUD_SIZE memory starting from PHYS_OFFSET (which must be
-	 * aligned to 2MB as per Documentation/arm64/booting.txt).
+	 * The initial direct kernel mapping, located at swapper_pg_dir, gives
+	 * us PUD_SIZE (4K pages) or PMD_SIZE (64K pages) memory starting from
+	 * PHYS_OFFSET (which must be aligned to 2MB as per
+	 * Documentation/arm64/booting.txt).
 	 */
 	 */
-	limit = PHYS_OFFSET + PUD_SIZE;
+	if (IS_ENABLED(CONFIG_ARM64_64K_PAGES))
+		limit = PHYS_OFFSET + PMD_SIZE;
+	else
+		limit = PHYS_OFFSET + PUD_SIZE;
 	memblock_set_current_limit(limit);
 	memblock_set_current_limit(limit);
 
 
 	/* map all the memory banks */
 	/* map all the memory banks */

+ 16 - 2
arch/arm64/mm/pgd.c

@@ -30,12 +30,14 @@
 
 
 #define PGD_SIZE	(PTRS_PER_PGD * sizeof(pgd_t))
 #define PGD_SIZE	(PTRS_PER_PGD * sizeof(pgd_t))
 
 
+static struct kmem_cache *pgd_cache;
+
 pgd_t *pgd_alloc(struct mm_struct *mm)
 pgd_t *pgd_alloc(struct mm_struct *mm)
 {
 {
 	if (PGD_SIZE == PAGE_SIZE)
 	if (PGD_SIZE == PAGE_SIZE)
 		return (pgd_t *)get_zeroed_page(GFP_KERNEL);
 		return (pgd_t *)get_zeroed_page(GFP_KERNEL);
 	else
 	else
-		return kzalloc(PGD_SIZE, GFP_KERNEL);
+		return kmem_cache_zalloc(pgd_cache, GFP_KERNEL);
 }
 }
 
 
 void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 void pgd_free(struct mm_struct *mm, pgd_t *pgd)
@@ -43,5 +45,17 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 	if (PGD_SIZE == PAGE_SIZE)
 	if (PGD_SIZE == PAGE_SIZE)
 		free_page((unsigned long)pgd);
 		free_page((unsigned long)pgd);
 	else
 	else
-		kfree(pgd);
+		kmem_cache_free(pgd_cache, pgd);
+}
+
+static int __init pgd_cache_init(void)
+{
+	/*
+	 * Naturally aligned pgds required by the architecture.
+	 */
+	if (PGD_SIZE != PAGE_SIZE)
+		pgd_cache = kmem_cache_create("pgd_cache", PGD_SIZE, PGD_SIZE,
+					      SLAB_PANIC, NULL);
+	return 0;
 }
 }
+core_initcall(pgd_cache_init);

+ 6 - 2
arch/arm64/net/bpf_jit.h

@@ -144,8 +144,12 @@
 
 
 /* Data-processing (2 source) */
 /* Data-processing (2 source) */
 /* Rd = Rn OP Rm */
 /* Rd = Rn OP Rm */
-#define A64_UDIV(sf, Rd, Rn, Rm) aarch64_insn_gen_data2(Rd, Rn, Rm, \
-	A64_VARIANT(sf), AARCH64_INSN_DATA2_UDIV)
+#define A64_DATA2(sf, Rd, Rn, Rm, type) aarch64_insn_gen_data2(Rd, Rn, Rm, \
+	A64_VARIANT(sf), AARCH64_INSN_DATA2_##type)
+#define A64_UDIV(sf, Rd, Rn, Rm) A64_DATA2(sf, Rd, Rn, Rm, UDIV)
+#define A64_LSLV(sf, Rd, Rn, Rm) A64_DATA2(sf, Rd, Rn, Rm, LSLV)
+#define A64_LSRV(sf, Rd, Rn, Rm) A64_DATA2(sf, Rd, Rn, Rm, LSRV)
+#define A64_ASRV(sf, Rd, Rn, Rm) A64_DATA2(sf, Rd, Rn, Rm, ASRV)
 
 
 /* Data-processing (3 source) */
 /* Data-processing (3 source) */
 /* Rd = Ra + Rn * Rm */
 /* Rd = Ra + Rn * Rm */

+ 74 - 10
arch/arm64/net/bpf_jit_comp.c

@@ -19,12 +19,13 @@
 #define pr_fmt(fmt) "bpf_jit: " fmt
 #define pr_fmt(fmt) "bpf_jit: " fmt
 
 
 #include <linux/filter.h>
 #include <linux/filter.h>
-#include <linux/moduleloader.h>
 #include <linux/printk.h>
 #include <linux/printk.h>
 #include <linux/skbuff.h>
 #include <linux/skbuff.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
+
 #include <asm/byteorder.h>
 #include <asm/byteorder.h>
 #include <asm/cacheflush.h>
 #include <asm/cacheflush.h>
+#include <asm/debug-monitors.h>
 
 
 #include "bpf_jit.h"
 #include "bpf_jit.h"
 
 
@@ -119,6 +120,14 @@ static inline int bpf2a64_offset(int bpf_to, int bpf_from,
 	return to - from;
 	return to - from;
 }
 }
 
 
+static void jit_fill_hole(void *area, unsigned int size)
+{
+	u32 *ptr;
+	/* We are guaranteed to have aligned memory. */
+	for (ptr = area; size >= sizeof(u32); size -= sizeof(u32))
+		*ptr++ = cpu_to_le32(AARCH64_BREAK_FAULT);
+}
+
 static inline int epilogue_offset(const struct jit_ctx *ctx)
 static inline int epilogue_offset(const struct jit_ctx *ctx)
 {
 {
 	int to = ctx->offset[ctx->prog->len - 1];
 	int to = ctx->offset[ctx->prog->len - 1];
@@ -196,6 +205,12 @@ static void build_epilogue(struct jit_ctx *ctx)
 	emit(A64_RET(A64_LR), ctx);
 	emit(A64_RET(A64_LR), ctx);
 }
 }
 
 
+/* JITs an eBPF instruction.
+ * Returns:
+ * 0  - successfully JITed an 8-byte eBPF instruction.
+ * >0 - successfully JITed a 16-byte eBPF instruction.
+ * <0 - failed to JIT.
+ */
 static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
 static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
 {
 {
 	const u8 code = insn->code;
 	const u8 code = insn->code;
@@ -252,6 +267,18 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
 		emit(A64_MUL(is64, tmp, tmp, src), ctx);
 		emit(A64_MUL(is64, tmp, tmp, src), ctx);
 		emit(A64_SUB(is64, dst, dst, tmp), ctx);
 		emit(A64_SUB(is64, dst, dst, tmp), ctx);
 		break;
 		break;
+	case BPF_ALU | BPF_LSH | BPF_X:
+	case BPF_ALU64 | BPF_LSH | BPF_X:
+		emit(A64_LSLV(is64, dst, dst, src), ctx);
+		break;
+	case BPF_ALU | BPF_RSH | BPF_X:
+	case BPF_ALU64 | BPF_RSH | BPF_X:
+		emit(A64_LSRV(is64, dst, dst, src), ctx);
+		break;
+	case BPF_ALU | BPF_ARSH | BPF_X:
+	case BPF_ALU64 | BPF_ARSH | BPF_X:
+		emit(A64_ASRV(is64, dst, dst, src), ctx);
+		break;
 	/* dst = -dst */
 	/* dst = -dst */
 	case BPF_ALU | BPF_NEG:
 	case BPF_ALU | BPF_NEG:
 	case BPF_ALU64 | BPF_NEG:
 	case BPF_ALU64 | BPF_NEG:
@@ -443,6 +470,27 @@ emit_cond_jmp:
 		emit(A64_B(jmp_offset), ctx);
 		emit(A64_B(jmp_offset), ctx);
 		break;
 		break;
 
 
+	/* dst = imm64 */
+	case BPF_LD | BPF_IMM | BPF_DW:
+	{
+		const struct bpf_insn insn1 = insn[1];
+		u64 imm64;
+
+		if (insn1.code != 0 || insn1.src_reg != 0 ||
+		    insn1.dst_reg != 0 || insn1.off != 0) {
+			/* Note: verifier in BPF core must catch invalid
+			 * instructions.
+			 */
+			pr_err_once("Invalid BPF_LD_IMM64 instruction\n");
+			return -EINVAL;
+		}
+
+		imm64 = (u64)insn1.imm << 32 | imm;
+		emit_a64_mov_i64(dst, imm64, ctx);
+
+		return 1;
+	}
+
 	/* LDX: dst = *(size *)(src + off) */
 	/* LDX: dst = *(size *)(src + off) */
 	case BPF_LDX | BPF_MEM | BPF_W:
 	case BPF_LDX | BPF_MEM | BPF_W:
 	case BPF_LDX | BPF_MEM | BPF_H:
 	case BPF_LDX | BPF_MEM | BPF_H:
@@ -594,6 +642,10 @@ static int build_body(struct jit_ctx *ctx)
 			ctx->offset[i] = ctx->idx;
 			ctx->offset[i] = ctx->idx;
 
 
 		ret = build_insn(insn, ctx);
 		ret = build_insn(insn, ctx);
+		if (ret > 0) {
+			i++;
+			continue;
+		}
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;
 	}
 	}
@@ -613,8 +665,10 @@ void bpf_jit_compile(struct bpf_prog *prog)
 
 
 void bpf_int_jit_compile(struct bpf_prog *prog)
 void bpf_int_jit_compile(struct bpf_prog *prog)
 {
 {
+	struct bpf_binary_header *header;
 	struct jit_ctx ctx;
 	struct jit_ctx ctx;
 	int image_size;
 	int image_size;
+	u8 *image_ptr;
 
 
 	if (!bpf_jit_enable)
 	if (!bpf_jit_enable)
 		return;
 		return;
@@ -636,23 +690,25 @@ void bpf_int_jit_compile(struct bpf_prog *prog)
 		goto out;
 		goto out;
 
 
 	build_prologue(&ctx);
 	build_prologue(&ctx);
-
 	build_epilogue(&ctx);
 	build_epilogue(&ctx);
 
 
 	/* Now we know the actual image size. */
 	/* Now we know the actual image size. */
 	image_size = sizeof(u32) * ctx.idx;
 	image_size = sizeof(u32) * ctx.idx;
-	ctx.image = module_alloc(image_size);
-	if (unlikely(ctx.image == NULL))
+	header = bpf_jit_binary_alloc(image_size, &image_ptr,
+				      sizeof(u32), jit_fill_hole);
+	if (header == NULL)
 		goto out;
 		goto out;
 
 
 	/* 2. Now, the actual pass. */
 	/* 2. Now, the actual pass. */
 
 
+	ctx.image = (u32 *)image_ptr;
 	ctx.idx = 0;
 	ctx.idx = 0;
+
 	build_prologue(&ctx);
 	build_prologue(&ctx);
 
 
 	ctx.body_offset = ctx.idx;
 	ctx.body_offset = ctx.idx;
 	if (build_body(&ctx)) {
 	if (build_body(&ctx)) {
-		module_free(NULL, ctx.image);
+		bpf_jit_binary_free(header);
 		goto out;
 		goto out;
 	}
 	}
 
 
@@ -663,17 +719,25 @@ void bpf_int_jit_compile(struct bpf_prog *prog)
 		bpf_jit_dump(prog->len, image_size, 2, ctx.image);
 		bpf_jit_dump(prog->len, image_size, 2, ctx.image);
 
 
 	bpf_flush_icache(ctx.image, ctx.image + ctx.idx);
 	bpf_flush_icache(ctx.image, ctx.image + ctx.idx);
-	prog->bpf_func = (void *)ctx.image;
-	prog->jited = 1;
 
 
+	set_memory_ro((unsigned long)header, header->pages);
+	prog->bpf_func = (void *)ctx.image;
+	prog->jited = true;
 out:
 out:
 	kfree(ctx.offset);
 	kfree(ctx.offset);
 }
 }
 
 
 void bpf_jit_free(struct bpf_prog *prog)
 void bpf_jit_free(struct bpf_prog *prog)
 {
 {
-	if (prog->jited)
-		module_free(NULL, prog->bpf_func);
+	unsigned long addr = (unsigned long)prog->bpf_func & PAGE_MASK;
+	struct bpf_binary_header *header = (void *)addr;
+
+	if (!prog->jited)
+		goto free_filter;
+
+	set_memory_rw(addr, header->pages);
+	bpf_jit_binary_free(header);
 
 
-	kfree(prog);
+free_filter:
+	bpf_prog_unlock_free(prog);
 }
 }