mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-12 16:58:53 +00:00
arm64 fixes:
- 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 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJUSowhAAoJEGvWsS0AyF7x4A8QAK/KJj3aEhRoJCFKtkrKcQer WydkHEVpJtk8Y+o9zIBU/J9HXDDakQlIZi3bNcWA+TQda1yr7zqEgVRZwhfaQMIu oXLzSLnZtiqe2HU7TaccJfFG293K+gysjTPRPixdAwWO/9hvoPOqJHnBRWKTDNzh 8D04PTM9dcpKXvVjPcRHIxbk2oH04a/tjOBeTpi5uWaUdZLWjHt2dTjWwP/q0af4 XsDrF5pYQaYEzCI9MczSbcQLwFPkxhS36JH+V+OhmVoCFv0PT7mm5o29DiU1N/Rt UsAwtBQ4oQV8seZMQaT5sVDNBqqqyfrYDAACdY0ewIr81PF7z8tdm5+G1P4JfQ0t iVguz3s1rJ6V0yXy0t18XHgpPFLLqpoEDEO6obYXYrhe2nTquQulgJoLaIu2qXmO jlL8R1rHWKRAQ7xIyLATjhUmW5dc2aK6xO+/3Xuz1+JOunNeOZW67xexpPzRU4Vh sw9S8sKwJmL5wH+ojqxsbg73WvTUs5dd4WoK7Tci8FZ0qfG14pyaX4s9iRhUZArQ 4vx8lfF7FQma8nZ0ytXSY/666dAedL/bXZrmPhjVl/XYoEA4IFaW7uDIIqGbUMWr oNOe4QahxZu5jHI8CYncXHw51RXst+03oE5Uon30x7F3ZD71perLZe2dMTTaezKv 2MX9/BULRrjpgkA4gW5L =QssH -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
cdc63a0595
@ -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.
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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 u16 __compat_uid_t;
|
||||||
typedef u32 __compat_gid_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;
|
||||||
|
@ -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
|
||||||
|
@ -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 */
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
|
@ -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)
|
||||||
|
@ -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,
|
* The initial direct kernel mapping, located at swapper_pg_dir, gives
|
||||||
* gives us PUD_SIZE memory starting from PHYS_OFFSET (which must be
|
* us PUD_SIZE (4K pages) or PMD_SIZE (64K pages) memory starting from
|
||||||
* aligned to 2MB as per Documentation/arm64/booting.txt).
|
* 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 */
|
||||||
|
@ -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);
|
||||||
|
@ -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, \
|
#define A64_DATA2(sf, Rd, Rn, Rm, type) aarch64_insn_gen_data2(Rd, Rn, Rm, \
|
||||||
A64_VARIANT(sf), AARCH64_INSN_DATA2_UDIV)
|
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 */
|
||||||
|
@ -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);
|
header = bpf_jit_binary_alloc(image_size, &image_ptr,
|
||||||
if (unlikely(ctx.image == NULL))
|
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)
|
unsigned long addr = (unsigned long)prog->bpf_func & PAGE_MASK;
|
||||||
module_free(NULL, prog->bpf_func);
|
struct bpf_binary_header *header = (void *)addr;
|
||||||
|
|
||||||
kfree(prog);
|
if (!prog->jited)
|
||||||
|
goto free_filter;
|
||||||
|
|
||||||
|
set_memory_rw(addr, header->pages);
|
||||||
|
bpf_jit_binary_free(header);
|
||||||
|
|
||||||
|
free_filter:
|
||||||
|
bpf_prog_unlock_free(prog);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user