* Re: [net-next 00/13][pull request] 40GbE Intel Wired LAN Driver Updates 2017-04-30
From: David Miller @ 2017-04-30 15:36 UTC (permalink / raw)
To: jeffrey.t.kirsher; +Cc: netdev, nhorman, sassmann, jogreene
In-Reply-To: <20170430132451.68494-1-jeffrey.t.kirsher@intel.com>
From: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Date: Sun, 30 Apr 2017 06:24:38 -0700
> This series contains updates to i40e and i40evf only.
...
> The following are changes since commit c08bac03d2894113bdb114e66e6ada009defb120:
> Merge branch '10GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue
> and are available in the git repository at:
> git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue 40GbE
Also pulled, thanks Jeff.
^ permalink raw reply
* Re: [PATCH v3 binutils] Add BPF support to binutils...
From: David Miller @ 2017-04-30 15:40 UTC (permalink / raw)
To: ast; +Cc: daniel, aconole, netdev, xdp-newbies
In-Reply-To: <76ed19a7-add3-0642-4298-9402c7ff0be8@fb.com>
From: Alexei Starovoitov <ast@fb.com>
Date: Sat, 29 Apr 2017 23:44:59 -0700
> On 4/29/17 7:37 PM, David Miller wrote:
>> BTW, should I just remove tailcall from the opcode table altogether?
>
> yeah. tailcall is not a special opcode from user space point of view.
> Only after normal call with func_id=bpf_tail_call passes verifier
> then verifier will change insn->code into CALL|X
> It's done only to have two 'case' statement in the interpreter,
> so that normal calls and tailcalls don't interfere.
> From user space pov CALL|X opcode is reserved and we can use it
> for something in the future. Just need to change interpeter and JITs.
Ok, I've removed it from my tree.
Thanks.
^ permalink raw reply
* Re: [PATCH 0/4] TI Bluetooth serdev support
From: Sebastian Reichel @ 2017-04-30 16:04 UTC (permalink / raw)
To: Adam Ford
Cc: Mark Rutland, Rob Herring, Johan Hedberg, devicetree,
Gustavo Padovan, Marcel Holtmann, Wei Xu, linux-bluetooth,
Eyal Reizer, netdev, Satish Patel, linux-arm-kernel
In-Reply-To: <CAHCN7xJUxZm1qKAxT0kaK6qoDg+HWOJK7sTH-q9za4HJuUwe8Q@mail.gmail.com>
[-- Attachment #1.1: Type: text/plain, Size: 1160 bytes --]
Hi,
On Sun, Apr 30, 2017 at 10:14:20AM -0500, Adam Ford wrote:
> On Wed, Apr 5, 2017 at 1:30 PM, Rob Herring <robh@kernel.org> wrote:
> > This series adds serdev support to the HCI LL protocol used on TI BT
> > modules and enables support on HiKey board with with the WL1835 module.
> > With this the custom TI UIM daemon and btattach are no longer needed.
>
> Without UIM daemon, what instruction do you use to load the BT firmware?
>
> I was thinking 'hciattach' but I was having trouble. I was hoping you
> might have some insight.
>
> hciattach -t 30 -s 115200 /dev/ttymxc1 texas 3000000 flow Just
> returns a timeout.
>
> I modified my i.MX6 device tree per the binding documentation and
> setup the regulators and enable GPIO pins.
If you configured everything correctly no userspace interaction is
required. The driver should request the firmware automatically once
you power up the bluetooth device.
Apart from DT changes make sure, that the following options are
enabled and check dmesg for any hints.
CONFIG_SERIAL_DEV_BUS
CONFIG_SERIAL_DEV_CTRL_TTYPORT
CONFIG_BT_HCIUART
CONFIG_BT_HCIUART_LL
-- Sebastian
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
[-- Attachment #2: Type: text/plain, Size: 176 bytes --]
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v4 binutils] Add BPF support to binutils...
From: David Miller @ 2017-04-30 16:07 UTC (permalink / raw)
To: ast; +Cc: daniel, netdev, xdp-newbies
This is mainly a synchronization point, I still need to look
more deeply into Alexei's -g issue.
New in this version from v3:
- Remove tailcall from opcode table
- Rearrange relocations so that numbers match with LLVM ones
- Emit relocs properly so that dwarf2 debug info tests pass
- Handle negative load/store offsets properly, add tests
Signed-off-by: David S. Miller <davem@davemloft.net>
---
bfd/Makefile.am | 2 +
bfd/Makefile.in | 3 +
bfd/archures.c | 3 +
bfd/bfd-in2.h | 8 +
bfd/config.bfd | 6 +
bfd/configure | 2 +
bfd/configure.ac | 2 +
bfd/cpu-bpf.c | 41 +++
bfd/elf64-bpf.c | 159 ++++++++++
bfd/elf64-bpf.h | 24 ++
bfd/libbfd.h | 4 +
bfd/reloc.c | 11 +
bfd/targets.c | 5 +
binutils/readelf.c | 11 +
config.sub | 5 +-
gas/Makefile.am | 2 +
gas/Makefile.in | 17 ++
gas/config/tc-bpf.c | 639 ++++++++++++++++++++++++++++++++++++++++
gas/config/tc-bpf.h | 45 +++
gas/configure.tgt | 3 +
gas/testsuite/gas/bpf/arith.d | 61 ++++
gas/testsuite/gas/bpf/arith.s | 53 ++++
gas/testsuite/gas/bpf/atomics.d | 12 +
gas/testsuite/gas/bpf/atomics.s | 4 +
gas/testsuite/gas/bpf/bpf.exp | 28 ++
gas/testsuite/gas/bpf/call.d | 14 +
gas/testsuite/gas/bpf/call.s | 6 +
gas/testsuite/gas/bpf/imm64.d | 30 ++
gas/testsuite/gas/bpf/imm64.s | 12 +
gas/testsuite/gas/bpf/jump.d | 43 +++
gas/testsuite/gas/bpf/jump.s | 35 +++
gas/testsuite/gas/bpf/loads.d | 27 ++
gas/testsuite/gas/bpf/loads.s | 19 ++
gas/testsuite/gas/bpf/move.d | 19 ++
gas/testsuite/gas/bpf/move.s | 11 +
gas/testsuite/gas/bpf/stores.d | 21 ++
gas/testsuite/gas/bpf/stores.s | 13 +
gdb/bpf-tdep.c | 229 ++++++++++++++
gdb/bpf-tdep.h | 40 +++
gdb/configure.tgt | 4 +
include/dis-asm.h | 1 +
include/elf/bpf.h | 39 +++
include/opcode/bpf.h | 16 +
ld/Makefile.am | 4 +
ld/Makefile.in | 5 +
ld/configure.tgt | 2 +
ld/emulparams/elf64_bpf.sh | 8 +
opcodes/Makefile.am | 2 +
opcodes/bpf-dis.c | 161 ++++++++++
opcodes/bpf-opc.c | 147 +++++++++
opcodes/configure | 1 +
opcodes/configure.ac | 1 +
opcodes/disassemble.c | 6 +
sim/configure.tgt | 3 +
54 files changed, 2067 insertions(+), 2 deletions(-)
create mode 100644 bfd/cpu-bpf.c
create mode 100644 bfd/elf64-bpf.c
create mode 100644 bfd/elf64-bpf.h
create mode 100644 gas/config/tc-bpf.c
create mode 100644 gas/config/tc-bpf.h
create mode 100644 gas/testsuite/gas/bpf/arith.d
create mode 100644 gas/testsuite/gas/bpf/arith.s
create mode 100644 gas/testsuite/gas/bpf/atomics.d
create mode 100644 gas/testsuite/gas/bpf/atomics.s
create mode 100644 gas/testsuite/gas/bpf/bpf.exp
create mode 100644 gas/testsuite/gas/bpf/call.d
create mode 100644 gas/testsuite/gas/bpf/call.s
create mode 100644 gas/testsuite/gas/bpf/imm64.d
create mode 100644 gas/testsuite/gas/bpf/imm64.s
create mode 100644 gas/testsuite/gas/bpf/jump.d
create mode 100644 gas/testsuite/gas/bpf/jump.s
create mode 100644 gas/testsuite/gas/bpf/loads.d
create mode 100644 gas/testsuite/gas/bpf/loads.s
create mode 100644 gas/testsuite/gas/bpf/move.d
create mode 100644 gas/testsuite/gas/bpf/move.s
create mode 100644 gas/testsuite/gas/bpf/stores.d
create mode 100644 gas/testsuite/gas/bpf/stores.s
create mode 100644 gdb/bpf-tdep.c
create mode 100644 gdb/bpf-tdep.h
create mode 100644 include/elf/bpf.h
create mode 100644 include/opcode/bpf.h
create mode 100644 ld/emulparams/elf64_bpf.sh
create mode 100644 opcodes/bpf-dis.c
create mode 100644 opcodes/bpf-opc.c
diff --git a/bfd/Makefile.am b/bfd/Makefile.am
index 97b608c..911655a 100644
--- a/bfd/Makefile.am
+++ b/bfd/Makefile.am
@@ -95,6 +95,7 @@ ALL_MACHINES = \
cpu-arm.lo \
cpu-avr.lo \
cpu-bfin.lo \
+ cpu-bpf.lo \
cpu-cr16.lo \
cpu-cr16c.lo \
cpu-cris.lo \
@@ -185,6 +186,7 @@ ALL_MACHINES_CFILES = \
cpu-arm.c \
cpu-avr.c \
cpu-bfin.c \
+ cpu-bpf.c \
cpu-cr16.c \
cpu-cr16c.c \
cpu-cris.c \
diff --git a/bfd/Makefile.in b/bfd/Makefile.in
index e48abaf..930aa09 100644
--- a/bfd/Makefile.in
+++ b/bfd/Makefile.in
@@ -428,6 +428,7 @@ ALL_MACHINES = \
cpu-arm.lo \
cpu-avr.lo \
cpu-bfin.lo \
+ cpu-bpf.lo \
cpu-cr16.lo \
cpu-cr16c.lo \
cpu-cris.lo \
@@ -518,6 +519,7 @@ ALL_MACHINES_CFILES = \
cpu-arm.c \
cpu-avr.c \
cpu-bfin.c \
+ cpu-bpf.c \
cpu-cr16.c \
cpu-cr16c.c \
cpu-cris.c \
@@ -1380,6 +1382,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-arm.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-avr.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-bfin.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-bpf.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-cr16.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-cr16c.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-cris.Plo@am__quote@
diff --git a/bfd/archures.c b/bfd/archures.c
index c6e7152..f096d73 100644
--- a/bfd/archures.c
+++ b/bfd/archures.c
@@ -447,6 +447,8 @@ DESCRIPTION
.#define bfd_mach_avrxmega7 107
. bfd_arch_bfin, {* ADI Blackfin *}
.#define bfd_mach_bfin 1
+. bfd_arch_bpf, {* eBPF *}
+.#define bfd_mach_bpf 1
. bfd_arch_cr16, {* National Semiconductor CompactRISC (ie CR16). *}
.#define bfd_mach_cr16 1
. bfd_arch_cr16c, {* National Semiconductor CompactRISC. *}
@@ -582,6 +584,7 @@ extern const bfd_arch_info_type bfd_arc_arch;
extern const bfd_arch_info_type bfd_arm_arch;
extern const bfd_arch_info_type bfd_avr_arch;
extern const bfd_arch_info_type bfd_bfin_arch;
+extern const bfd_arch_info_type bfd_bpf_arch;
extern const bfd_arch_info_type bfd_cr16_arch;
extern const bfd_arch_info_type bfd_cr16c_arch;
extern const bfd_arch_info_type bfd_cris_arch;
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 17a35c0..6d44534 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -2304,6 +2304,8 @@ enum bfd_architecture
#define bfd_mach_avrxmega7 107
bfd_arch_bfin, /* ADI Blackfin */
#define bfd_mach_bfin 1
+ bfd_arch_bpf, /* eBPF */
+#define bfd_mach_bpf 1
bfd_arch_cr16, /* National Semiconductor CompactRISC (ie CR16). */
#define bfd_mach_cr16 1
bfd_arch_cr16c, /* National Semiconductor CompactRISC. */
@@ -3910,6 +3912,12 @@ pc-relative or some form of GOT-indirect relocation. */
/* ADI Blackfin arithmetic relocation. */
BFD_ARELOC_BFIN_ADDR,
+/* BPF relocations */
+ BFD_RELOC_BPF_16,
+ BFD_RELOC_BPF_32,
+ BFD_RELOC_BPF_64,
+ BFD_RELOC_BPF_WDISP16,
+
/* Mitsubishi D10V relocs.
This is a 10-bit reloc with the right 2 bits
assumed to be 0. */
diff --git a/bfd/config.bfd b/bfd/config.bfd
index 151de95..f6d90cd 100644
--- a/bfd/config.bfd
+++ b/bfd/config.bfd
@@ -161,6 +161,7 @@ am33_2.0*) targ_archs=bfd_mn10300_arch ;;
arc*) targ_archs=bfd_arc_arch ;;
arm*) targ_archs=bfd_arm_arch ;;
bfin*) targ_archs=bfd_bfin_arch ;;
+bpf*) targ_archs=bfd_bpf_arch ;;
c30*) targ_archs=bfd_tic30_arch ;;
c4x*) targ_archs=bfd_tic4x_arch ;;
c54x*) targ_archs=bfd_tic54x_arch ;;
@@ -471,6 +472,11 @@ case "${targ}" in
targ_underscore=yes
;;
+ bpf-*-*)
+ targ_defvec=bpf_elf64_be_vec
+ targ_selvecs=bpf_elf64_le_vec
+ ;;
+
c30-*-*aout* | tic30-*-*aout*)
targ_defvec=tic30_aout_vec
;;
diff --git a/bfd/configure b/bfd/configure
index 24e3e2f..2a5ba40 100755
--- a/bfd/configure
+++ b/bfd/configure
@@ -14298,6 +14298,8 @@ do
avr_elf32_vec) tb="$tb elf32-avr.lo elf32.lo $elf" ;;
bfin_elf32_vec) tb="$tb elf32-bfin.lo elf32.lo $elf" ;;
bfin_elf32_fdpic_vec) tb="$tb elf32-bfin.lo elf32.lo $elf" ;;
+ bpf_elf64_le_vec) tb="$tb elf64-bpf.lo elf64.lo $elf" ;;
+ bpf_elf64_be_vec) tb="$tb elf64-bpf.lo elf64.lo $elf" ;;
bout_be_vec) tb="$tb bout.lo aout32.lo" ;;
bout_le_vec) tb="$tb bout.lo aout32.lo" ;;
cr16_elf32_vec) tb="$tb elf32-cr16.lo elf32.lo $elf" ;;
diff --git a/bfd/configure.ac b/bfd/configure.ac
index e568847..0dd7139 100644
--- a/bfd/configure.ac
+++ b/bfd/configure.ac
@@ -429,6 +429,8 @@ do
avr_elf32_vec) tb="$tb elf32-avr.lo elf32.lo $elf" ;;
bfin_elf32_vec) tb="$tb elf32-bfin.lo elf32.lo $elf" ;;
bfin_elf32_fdpic_vec) tb="$tb elf32-bfin.lo elf32.lo $elf" ;;
+ bpf_elf64_le_vec) tb="$tb elf64-bpf.lo elf64.lo $elf" ;;
+ bpf_elf64_be_vec) tb="$tb elf64-bpf.lo elf64.lo $elf" ;;
bout_be_vec) tb="$tb bout.lo aout32.lo" ;;
bout_le_vec) tb="$tb bout.lo aout32.lo" ;;
cr16_elf32_vec) tb="$tb elf32-cr16.lo elf32.lo $elf" ;;
diff --git a/bfd/cpu-bpf.c b/bfd/cpu-bpf.c
new file mode 100644
index 0000000..551e42e
--- /dev/null
+++ b/bfd/cpu-bpf.c
@@ -0,0 +1,41 @@
+/* BFD Support for the eBPF.
+
+ Copyright (C) 2017 Free Software Foundation, Inc.
+
+ This file is part of BFD, the Binary File Descriptor library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "libbfd.h"
+
+const bfd_arch_info_type bfd_bpf_arch =
+ {
+ 64, /* Bits in a word. */
+ 64, /* Bits in an address. */
+ 8, /* Bits in a byte. */
+ bfd_arch_bpf,
+ 0, /* Only one machine. */
+ "bpf", /* Arch name. */
+ "bpf", /* Arch printable name. */
+ 3, /* Section align power. */
+ TRUE, /* The one and only. */
+ bfd_default_compatible,
+ bfd_default_scan,
+ bfd_arch_default_fill,
+ 0,
+ };
diff --git a/bfd/elf64-bpf.c b/bfd/elf64-bpf.c
new file mode 100644
index 0000000..a42f768
--- /dev/null
+++ b/bfd/elf64-bpf.c
@@ -0,0 +1,159 @@
+#include "sysdep.h"
+#include "bfd.h"
+#include "bfdlink.h"
+#include "libbfd.h"
+#include "libiberty.h"
+#include "elf-bfd.h"
+#include "elf/bpf.h"
+#include "opcode/bpf.h"
+#include "objalloc.h"
+#include "elf64-bpf.h"
+
+/* In case we're on a 32-bit machine, construct a 64-bit "-1" value. */
+#define MINUS_ONE (~ (bfd_vma) 0)
+
+static reloc_howto_type _bfd_bpf_elf_howto_table[] =
+{
+ HOWTO(R_BPF_NONE, 0,3, 0,FALSE,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_BPF_NONE", FALSE,0,0x00000000,TRUE),
+
+ /* XXX these are wrong XXX */
+ HOWTO(R_BPF_INSN_64, 0,4,64,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_BPF_INSN_64", FALSE,0,MINUS_ONE,TRUE),
+ HOWTO(R_BPF_INSN_32, 0,2,32,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_BPF_INSN_32", FALSE,0,0xffffffff,TRUE),
+ HOWTO(R_BPF_INSN_16, 0,1,16,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_BPF_INSN_16", FALSE,0,0x0000ffff,TRUE),
+ HOWTO(R_BPF_WDISP16, 0,1,16,TRUE, 0,complain_overflow_signed, bfd_elf_generic_reloc, "R_BPF_WDISP16", FALSE,0,0x0000ffff,TRUE),
+
+ EMPTY_HOWTO(5),
+ EMPTY_HOWTO(6),
+ EMPTY_HOWTO(7),
+ HOWTO(R_BPF_DATA_8, 0,0, 8,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_BPF_DATA_8", FALSE,0,0x000000ff,TRUE),
+ HOWTO(R_BPF_DATA_16, 0,1,16,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_BPF_DATA_16", FALSE,0,0x0000ffff,TRUE),
+ HOWTO(R_BPF_DATA_32, 0,2,32,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_BPF_DATA_32", FALSE,0,0xffffffff,TRUE),
+ HOWTO(R_BPF_DATA_64, 0,4,64,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_BPF_DATA_64", FALSE,0,MINUS_ONE,TRUE),
+};
+
+reloc_howto_type *
+_bfd_bpf_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+ bfd_reloc_code_real_type code)
+{
+ switch (code)
+ {
+ case BFD_RELOC_NONE:
+ return &_bfd_bpf_elf_howto_table[R_BPF_NONE];
+
+ case BFD_RELOC_BPF_WDISP16:
+ return &_bfd_bpf_elf_howto_table[R_BPF_WDISP16];
+
+ case BFD_RELOC_BPF_16:
+ return &_bfd_bpf_elf_howto_table[R_BPF_INSN_16];
+
+ case BFD_RELOC_BPF_32:
+ return &_bfd_bpf_elf_howto_table[R_BPF_INSN_32];
+
+ case BFD_RELOC_BPF_64:
+ return &_bfd_bpf_elf_howto_table[R_BPF_INSN_64];
+
+ case BFD_RELOC_8:
+ return &_bfd_bpf_elf_howto_table[R_BPF_DATA_8];
+
+ case BFD_RELOC_16:
+ return &_bfd_bpf_elf_howto_table[R_BPF_DATA_16];
+
+ case BFD_RELOC_32:
+ return &_bfd_bpf_elf_howto_table[R_BPF_DATA_32];
+
+ case BFD_RELOC_64:
+ return &_bfd_bpf_elf_howto_table[R_BPF_DATA_64];
+
+ default:
+ break;
+ }
+ bfd_set_error (bfd_error_bad_value);
+ return NULL;
+}
+
+reloc_howto_type *
+_bfd_bpf_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+ const char *r_name)
+{
+ unsigned int i;
+
+ for (i = 0;
+ i < (sizeof (_bfd_bpf_elf_howto_table)
+ / sizeof (_bfd_bpf_elf_howto_table[0]));
+ i++)
+ if (_bfd_bpf_elf_howto_table[i].name != NULL
+ && strcasecmp (_bfd_bpf_elf_howto_table[i].name, r_name) == 0)
+ return &_bfd_bpf_elf_howto_table[i];
+
+ return NULL;
+}
+
+static void
+check_for_relocs (bfd * abfd, asection * o, void * failed)
+{
+ if ((o->flags & SEC_RELOC) != 0)
+ {
+ Elf_Internal_Ehdr *ehdrp;
+
+ ehdrp = elf_elfheader (abfd);
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%B: Relocations in generic ELF (EM: %d)"),
+ abfd, ehdrp->e_machine);
+
+ bfd_set_error (bfd_error_wrong_format);
+ * (bfd_boolean *) failed = TRUE;
+ }
+}
+
+static bfd_boolean
+elf64_generic_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
+{
+ bfd_boolean failed = FALSE;
+
+ /* Check if there are any relocations. */
+ bfd_map_over_sections (abfd, check_for_relocs, & failed);
+
+ if (failed)
+ return FALSE;
+ return bfd_elf_link_add_symbols (abfd, info);
+}
+
+static reloc_howto_type *
+elf_bpf_rtype_to_howto (unsigned int r_type)
+{
+ if (r_type >= (unsigned int) R_BPF_max)
+ {
+ _bfd_error_handler (_("invalid relocation type %d"), (int) r_type);
+ r_type = R_BPF_NONE;
+ }
+ return &_bfd_bpf_elf_howto_table[r_type];
+}
+
+/* Given a bpf ELF reloc type, fill in an arelent structure. */
+
+static void
+elf_bpf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr,
+ Elf_Internal_Rela *dst)
+{
+ unsigned r_type;
+
+ r_type = ELF64_R_TYPE (dst->r_info);
+ cache_ptr->howto = elf_bpf_rtype_to_howto (r_type);
+ BFD_ASSERT (r_type == cache_ptr->howto->type);
+}
+
+#define TARGET_LITTLE_SYM bpf_elf64_le_vec
+#define TARGET_LITTLE_NAME "elf64-bpfle"
+#define TARGET_BIG_SYM bpf_elf64_be_vec
+#define TARGET_BIG_NAME "elf64-bpfbe"
+#define ELF_ARCH bfd_arch_bpf
+#define ELF_MAXPAGESIZE 0x100000
+#define ELF_MACHINE_CODE EM_BPF
+
+#define elf_info_to_howto elf_bpf_info_to_howto
+
+#define bfd_elf64_bfd_reloc_type_lookup _bfd_bpf_elf_reloc_type_lookup
+#define bfd_elf64_bfd_reloc_name_lookup _bfd_bpf_elf_reloc_name_lookup
+#define bfd_elf64_bfd_link_add_symbols elf64_generic_link_add_symbols
+
+#include "elf64-target.h"
diff --git a/bfd/elf64-bpf.h b/bfd/elf64-bpf.h
new file mode 100644
index 0000000..f435e2e
--- /dev/null
+++ b/bfd/elf64-bpf.h
@@ -0,0 +1,24 @@
+/* BPF ELF specific backend routines.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+
+ This file is part of BFD, the Binary File Descriptor library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+extern reloc_howto_type *_bfd_bpf_elf_reloc_type_lookup
+ (bfd *, bfd_reloc_code_real_type);
+extern reloc_howto_type *_bfd_bpf_elf_reloc_name_lookup
+ (bfd *, const char *);
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 8bac650..1a3001d 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -1794,6 +1794,10 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_ARELOC_BFIN_PAGE",
"BFD_ARELOC_BFIN_HWPAGE",
"BFD_ARELOC_BFIN_ADDR",
+ "BFD_RELOC_BPF_16",
+ "BFD_RELOC_BPF_32",
+ "BFD_RELOC_BPF_64",
+ "BFD_RELOC_BPF_WDISP16",
"BFD_RELOC_D10V_10_PCREL_R",
"BFD_RELOC_D10V_10_PCREL_L",
"BFD_RELOC_D10V_18",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 9a04022..4100caf 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -3854,6 +3854,17 @@ ENUMDOC
ADI Blackfin arithmetic relocation.
ENUM
+ BFD_RELOC_BPF_16
+ENUMX
+ BFD_RELOC_BPF_32
+ENUMX
+ BFD_RELOC_BPF_64
+ENUMX
+ BFD_RELOC_BPF_WDISP16
+ENUMDOC
+ BPF relocations
+
+ENUM
BFD_RELOC_D10V_10_PCREL_R
ENUMDOC
Mitsubishi D10V relocs.
diff --git a/bfd/targets.c b/bfd/targets.c
index 5841e8d..c38c4fb 100644
--- a/bfd/targets.c
+++ b/bfd/targets.c
@@ -619,6 +619,8 @@ extern const bfd_target arm_pei_wince_le_vec;
extern const bfd_target avr_elf32_vec;
extern const bfd_target bfin_elf32_vec;
extern const bfd_target bfin_elf32_fdpic_vec;
+extern const bfd_target bpf_elf64_le_vec;
+extern const bfd_target bpf_elf64_be_vec;
extern const bfd_target bout_be_vec;
extern const bfd_target bout_le_vec;
extern const bfd_target cr16_elf32_vec;
@@ -1029,6 +1031,9 @@ static const bfd_target * const _bfd_target_vector[] =
&bfin_elf32_vec,
&bfin_elf32_fdpic_vec,
+ &bpf_elf64_le_vec,
+ &bpf_elf64_be_vec,
+
&bout_be_vec,
&bout_le_vec,
diff --git a/binutils/readelf.c b/binutils/readelf.c
index b57e1e0..b4013fb 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -95,6 +95,7 @@
#include "elf/arm.h"
#include "elf/avr.h"
#include "elf/bfin.h"
+#include "elf/bpf.h"
#include "elf/cr16.h"
#include "elf/cris.h"
#include "elf/crx.h"
@@ -746,6 +747,7 @@ guess_is_rela (unsigned int e_machine)
case EM_AVR:
case EM_AVR_OLD:
case EM_BLACKFIN:
+ case EM_BPF:
case EM_CR16:
case EM_CRIS:
case EM_CRX:
@@ -1458,6 +1460,10 @@ dump_relocations (FILE * file,
rtype = elf_bfin_reloc_type (type);
break;
+ case EM_BPF:
+ rtype = elf_bpf_reloc_type (type);
+ break;
+
case EM_CYGNUS_MEP:
rtype = elf_mep_reloc_type (type);
break;
@@ -12006,6 +12012,8 @@ is_32bit_abs_reloc (unsigned int reloc_type)
return reloc_type == 1;
case EM_BLACKFIN:
return reloc_type == 0x12; /* R_byte4_data. */
+ case EM_BPF:
+ return reloc_type == 10; /* R_BPF_DATA_32 */
case EM_CRIS:
return reloc_type == 3; /* R_CRIS_32. */
case EM_CR16:
@@ -12245,6 +12253,8 @@ is_64bit_abs_reloc (unsigned int reloc_type)
return reloc_type == 257; /* R_AARCH64_ABS64. */
case EM_ALPHA:
return reloc_type == 2; /* R_ALPHA_REFQUAD. */
+ case EM_BPF:
+ return reloc_type == 11; /* R_BPF_DATA_64 */
case EM_IA_64:
return reloc_type == 0x27; /* R_IA64_DIR64LSB. */
case EM_PARISC:
@@ -12411,6 +12421,7 @@ is_none_reloc (unsigned int reloc_type)
case EM_ARC_COMPACT2: /* R_ARC_NONE. */
case EM_ARC_COMPACT: /* R_ARC_NONE. */
case EM_ARM: /* R_ARM_NONE. */
+ case EM_BPF: /* R_BPF_NONE. */
case EM_C166: /* R_XC16X_NONE. */
case EM_CRIS: /* R_CRIS_NONE. */
case EM_FT32: /* R_FT32_NONE. */
diff --git a/config.sub b/config.sub
index 40ea5df..942989e 100755
--- a/config.sub
+++ b/config.sub
@@ -2,7 +2,7 @@
# Configuration validation subroutine script.
# Copyright 1992-2017 Free Software Foundation, Inc.
-timestamp='2017-04-02'
+timestamp='2017-04-25'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -257,6 +257,7 @@ case $basic_machine in
| ba \
| be32 | be64 \
| bfin \
+ | bpf \
| c4x | c8051 | clipper \
| d10v | d30v | dlx | dsp16xx \
| e2k | epiphany \
@@ -380,7 +381,7 @@ case $basic_machine in
| avr-* | avr32-* \
| ba-* \
| be32-* | be64-* \
- | bfin-* | bs2000-* \
+ | bfin-* | bpf-* | bs2000-* \
| c[123]* | c30-* | [cjt]90-* | c4x-* \
| c8051-* | clipper-* | craynv-* | cydra-* \
| d10v-* | d30v-* | dlx-* \
diff --git a/gas/Makefile.am b/gas/Makefile.am
index c9f9de0..bfd6ed9 100644
--- a/gas/Makefile.am
+++ b/gas/Makefile.am
@@ -135,6 +135,7 @@ TARGET_CPU_CFILES = \
config/tc-arm.c \
config/tc-avr.c \
config/tc-bfin.c \
+ config/tc-bpf.c \
config/tc-cr16.c \
config/tc-cris.c \
config/tc-crx.c \
@@ -212,6 +213,7 @@ TARGET_CPU_HFILES = \
config/tc-arm.h \
config/tc-avr.h \
config/tc-bfin.h \
+ config/tc-bpf.h \
config/tc-cr16.h \
config/tc-cris.h \
config/tc-crx.h \
diff --git a/gas/Makefile.in b/gas/Makefile.in
index 1927de5..ee62f1a 100644
--- a/gas/Makefile.in
+++ b/gas/Makefile.in
@@ -431,6 +431,7 @@ TARGET_CPU_CFILES = \
config/tc-arm.c \
config/tc-avr.c \
config/tc-bfin.c \
+ config/tc-bpf.c \
config/tc-cr16.c \
config/tc-cris.c \
config/tc-crx.c \
@@ -508,6 +509,7 @@ TARGET_CPU_HFILES = \
config/tc-arm.h \
config/tc-avr.h \
config/tc-bfin.h \
+ config/tc-bpf.h \
config/tc-cr16.h \
config/tc-cris.h \
config/tc-crx.h \
@@ -868,6 +870,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-arm.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-avr.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-bfin.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-bpf.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-cr16.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-cris.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-crx.Po@am__quote@
@@ -1045,6 +1048,20 @@ tc-bfin.obj: config/tc-bfin.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tc-bfin.obj `if test -f 'config/tc-bfin.c'; then $(CYGPATH_W) 'config/tc-bfin.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-bfin.c'; fi`
+tc-bpf.o: config/tc-bpf.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-bpf.o -MD -MP -MF $(DEPDIR)/tc-bpf.Tpo -c -o tc-bpf.o `test -f 'config/tc-bpf.c' || echo '$(srcdir)/'`config/tc-bpf.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tc-bpf.Tpo $(DEPDIR)/tc-bpf.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/tc-bpf.c' object='tc-bpf.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tc-bpf.o `test -f 'config/tc-bpf.c' || echo '$(srcdir)/'`config/tc-bpf.c
+
+tc-bpf.obj: config/tc-bpf.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-bpf.obj -MD -MP -MF $(DEPDIR)/tc-bpf.Tpo -c -o tc-bpf.obj `if test -f 'config/tc-bpf.c'; then $(CYGPATH_W) 'config/tc-bpf.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-bpf.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tc-bpf.Tpo $(DEPDIR)/tc-bpf.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/tc-bpf.c' object='tc-bpf.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tc-bpf.obj `if test -f 'config/tc-bpf.c'; then $(CYGPATH_W) 'config/tc-bpf.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-bpf.c'; fi`
+
tc-cr16.o: config/tc-cr16.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-cr16.o -MD -MP -MF $(DEPDIR)/tc-cr16.Tpo -c -o tc-cr16.o `test -f 'config/tc-cr16.c' || echo '$(srcdir)/'`config/tc-cr16.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tc-cr16.Tpo $(DEPDIR)/tc-cr16.Po
diff --git a/gas/config/tc-bpf.c b/gas/config/tc-bpf.c
new file mode 100644
index 0000000..36393b7
--- /dev/null
+++ b/gas/config/tc-bpf.c
@@ -0,0 +1,639 @@
+/* tc-bpf.c -- Assemble for the SPARC
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with GAS; see the file COPYING. If not, write
+ to the Free Software Foundation, 51 Franklin Street - Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+#include "as.h"
+#include "safe-ctype.h"
+#include "subsegs.h"
+#include "opcode/bpf.h"
+#ifdef OBJ_ELF
+#include "elf/bpf.h"
+#include "dwarf2dbg.h"
+#endif
+
+const pseudo_typeS md_pseudo_table[] =
+{
+ {"align", s_align_bytes, 0}, /* Defaulting is invalid (0). */
+ {"global", s_globl, 0},
+ {"half", cons, 2},
+ {"skip", s_space, 0},
+ {"word", cons, 4},
+ {"xword", cons, 8},
+ {NULL, 0, 0},
+};
+
+const char comment_chars[] = "!";
+const char line_comment_chars[] = "#";
+const char line_separator_chars[] = ";";
+const char EXP_CHARS[] = "eE";
+const char FLT_CHARS[] = "rRsSfFdDxXpP";
+
+const char *md_shortopts = "V";
+struct option md_longopts[] =
+{
+#define OPTION_LITTLE_ENDIAN (OPTION_MD_BASE + 8)
+ {"EL", no_argument, NULL, OPTION_LITTLE_ENDIAN},
+#define OPTION_BIG_ENDIAN (OPTION_MD_BASE + 9)
+ {"EB", no_argument, NULL, OPTION_BIG_ENDIAN},
+ { NULL, no_argument, NULL, 0 },
+};
+size_t md_longopts_size = sizeof (md_longopts);
+
+/* Whether or not, we've set target_big_endian. */
+static int set_target_endian = 0;
+
+int
+md_parse_option (int c ATTRIBUTE_UNUSED, const char *arg ATTRIBUTE_UNUSED)
+{
+ switch (c)
+ {
+ case OPTION_LITTLE_ENDIAN:
+ target_big_endian = 0;
+ set_target_endian = 1;
+ break;
+ case OPTION_BIG_ENDIAN:
+ target_big_endian = 1;
+ set_target_endian = 1;
+ break;
+ case 'V':
+ print_version_id ();
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+void
+md_show_usage (FILE *stream)
+{
+ fprintf (stream, _("BPF options:\n"));
+}
+
+/* Handle of the OPCODE hash table. */
+static struct hash_control *op_hash;
+
+void
+md_begin (void)
+{
+ const char *retval = NULL;
+ unsigned int i = 0;
+ int lose = 0;
+
+ op_hash = hash_new ();
+ while (i < (unsigned int) bpf_num_opcodes)
+ {
+ const char *name = bpf_opcodes[i].name;
+ retval = hash_insert (op_hash, name, (void *) &bpf_opcodes[i]);
+ if (retval != NULL)
+ {
+ as_bad (_("Internal error: can't hash `%s': %s\n"),
+ bpf_opcodes[i].name, retval);
+ lose = 1;
+ }
+ do
+ {
+ ++i;
+ }
+ while (i < (unsigned int) bpf_num_opcodes
+ && !strcmp (bpf_opcodes[i].name, name));
+ }
+ if (lose)
+ as_fatal (_("Broken assembler. No assembly attempted."));
+
+ if (!set_target_endian)
+ {
+ /* Default to host endianness. */
+#ifdef WORDS_BIGENDIAN
+ target_big_endian = 1;
+#else
+ target_big_endian = 0;
+#endif
+ set_target_endian = 1;
+ }
+}
+
+const char *
+bpf_target_format (void)
+{
+ return target_big_endian ? "elf64-bpfbe" : "elf64-bpfle";
+}
+
+struct bpf_it
+ {
+ const char *error;
+ valueT opcode;
+ valueT high64;
+ expressionS exp;
+ int pcrel;
+ int imm64;
+ bfd_reloc_code_real_type reloc;
+ };
+
+/* Subroutine of md_assemble to output one insn. */
+
+static void
+output_insn (struct bpf_it *theinsn)
+{
+ valueT opc = theinsn->opcode;
+ char *toP = frag_more (theinsn->imm64 ? 16 : 8);
+ char code, regs;
+
+ code = opc >> (64 - 8);
+ regs = opc >> (64 - (8 + 8));
+
+ toP[0] = code;
+ toP[1] = regs;
+
+ /* Put out the opcode. */
+ if (target_big_endian)
+ {
+ number_to_chars_bigendian (toP + 2, opc >> 32, 2);
+ number_to_chars_bigendian (toP + 4, opc, 4);
+ }
+ else
+ {
+ number_to_chars_littleendian (toP + 2, opc >> 32, 2);
+ number_to_chars_littleendian (toP + 4, opc, 4);
+ }
+
+ if (theinsn->imm64)
+ {
+ toP[8] = 0;
+ toP[9] = 0;
+ toP[10] = 0;
+ toP[11] = 0;
+ if (target_big_endian)
+ {
+ number_to_chars_bigendian (toP + 12, theinsn->high64, 4);
+ }
+ else
+ {
+ number_to_chars_littleendian (toP + 12, theinsn->high64, 4);
+ }
+ }
+
+ /* Put out the symbol-dependent stuff. */
+ if (theinsn->reloc != BFD_RELOC_NONE)
+ {
+ fixS *fixP = fix_new_exp (frag_now, /* Which frag. */
+ (toP - frag_now->fr_literal), /* Where. */
+ 4, /* Size. */
+ &theinsn->exp,
+ theinsn->pcrel,
+ theinsn->reloc);
+ /* Turn off overflow checking in fixup_segment. We'll do our
+ own overflow checking in md_apply_fix. This is necessary because
+ the insn size is 4 and fixup_segment will signal an overflow for
+ large 8 byte quantities. */
+ fixP->fx_no_overflow = 1;
+ }
+
+#ifdef OBJ_ELF
+ dwarf2_emit_insn (8);
+#endif
+}
+
+static struct bpf_it the_insn;
+static char *expr_end;
+
+static int
+get_expression (char *str, expressionS *exp)
+{
+ char *save_in;
+ segT seg;
+
+ save_in = input_line_pointer;
+ input_line_pointer = str;
+ seg = expression (exp);
+ if (seg != absolute_section
+ && seg != text_section
+ && seg != data_section
+ && seg != bss_section
+ && seg != undefined_section)
+ {
+ the_insn.error = _("bad segment");
+ expr_end = input_line_pointer;
+ input_line_pointer = save_in;
+ return 1;
+ }
+ expr_end = input_line_pointer;
+ input_line_pointer = save_in;
+ return 0;
+}
+
+void
+md_assemble (char *str ATTRIBUTE_UNUSED)
+{
+ const struct bpf_opcode *insn;
+ const char *args;
+ char *argsStart;
+ int match = 0;
+ valueT mask;
+ char *s, c;
+
+ s = str;
+ if (ISLOWER (*s))
+ {
+ do
+ ++s;
+ while (ISLOWER (*s) || ISDIGIT (*s) || *s == '_');
+ }
+
+ switch (*s)
+ {
+ case '\0':
+ break;
+
+ case ' ':
+ *s++ = '\0';
+ break;
+
+ default:
+ as_bad (_("Unknown opcode: `%s'"), str);
+ return;
+ }
+ insn = (struct bpf_opcode *) hash_find (op_hash, str);
+
+ if (insn == NULL)
+ {
+ as_bad (_("Unknown opcode: `%s'"), str);
+ return;
+ }
+
+ argsStart = s;
+ for (;;)
+ {
+ memset (&the_insn, '\0', sizeof (the_insn));
+ the_insn.reloc = BFD_RELOC_NONE;
+ the_insn.opcode = ((valueT)insn->code << 56);
+
+ for (args = insn->args;; args++)
+ {
+ switch (*args)
+ {
+ case '+':
+ if (*s == '+')
+ {
+ ++s;
+ continue;
+ }
+ if (*s == '-')
+ continue;
+ break;
+ case ',':
+ case '[':
+ case ']':
+ if (*s++ == *args)
+ continue;
+ break;
+ case '1':
+ if (*s++ == 'r')
+ {
+ if (!ISDIGIT ((c = *s++)))
+ {
+ goto error;
+ }
+ c -= '0';
+ mask = c;
+ if (ISDIGIT (*s))
+ {
+ c = *s++;
+ if (c != '0' || mask != 1)
+ goto error;
+ mask = 10;
+ }
+ the_insn.opcode |= (mask << 52);
+ continue;
+ }
+ break;
+ case '2':
+ if (*s++ == 'r')
+ {
+ if (!ISDIGIT ((c = *s++)))
+ {
+ goto error;
+ }
+ c -= '0';
+ mask = c;
+ if (ISDIGIT (*s))
+ {
+ c = *s++;
+ if (c != '0' || mask != 1)
+ goto error;
+ mask = 10;
+ }
+ the_insn.opcode |= (mask << 48);
+ continue;
+ }
+ break;
+ case 'i':
+ case 'C':
+ the_insn.reloc = BFD_RELOC_BPF_32;
+ if (*s == ' ')
+ s++;
+ get_expression (s, &the_insn.exp);
+ s = expr_end;
+ if (the_insn.exp.X_op == O_constant
+ && the_insn.exp.X_add_symbol == 0
+ && the_insn.exp.X_op_symbol == 0)
+ {
+ valueT val = the_insn.exp.X_add_number;
+
+ the_insn.reloc = BFD_RELOC_NONE;
+ val &= 0xffffffff;
+ the_insn.opcode |= val;
+ }
+ continue;
+ case 'O':
+ the_insn.reloc = BFD_RELOC_BPF_16;
+ if (*s == ' ')
+ s++;
+ get_expression (s, &the_insn.exp);
+ s = expr_end;
+ if (the_insn.exp.X_op == O_constant
+ && the_insn.exp.X_add_symbol == 0
+ && the_insn.exp.X_op_symbol == 0)
+ {
+ valueT val = the_insn.exp.X_add_number;
+
+ the_insn.reloc = BFD_RELOC_NONE;
+ val &= 0xffff;
+ the_insn.opcode |= val << 32;
+ }
+ continue;
+ case 'L':
+ the_insn.reloc = BFD_RELOC_BPF_WDISP16;
+ the_insn.pcrel = 1;
+ if (*s == ' ')
+ s++;
+ get_expression (s, &the_insn.exp);
+ s = expr_end;
+ if (the_insn.exp.X_op == O_constant
+ && the_insn.exp.X_add_symbol == 0
+ && the_insn.exp.X_op_symbol == 0)
+ {
+ valueT val = the_insn.exp.X_add_number;
+
+ the_insn.reloc = BFD_RELOC_NONE;
+ val &= 0xffff;
+ the_insn.opcode |= val << 32;
+ }
+ continue;
+ case 'D':
+ the_insn.reloc = BFD_RELOC_BPF_64;
+ the_insn.imm64 = 1;
+ if (*s == ' ')
+ s++;
+ get_expression (s, &the_insn.exp);
+ s = expr_end;
+ if (the_insn.exp.X_op == O_constant
+ && the_insn.exp.X_add_symbol == 0
+ && the_insn.exp.X_op_symbol == 0)
+ {
+ valueT val = the_insn.exp.X_add_number;
+
+ the_insn.reloc = BFD_RELOC_NONE;
+ the_insn.opcode |= (val & 0xffffffff);
+ the_insn.high64 = ((val >> 32) & 0xffffffff);
+ }
+ continue;
+ case '\0': /* End of args. */
+ match = 1;
+ break;
+ default:
+ as_fatal (_("failed sanity check."));
+ }
+
+ /* Break out of for() loop. */
+ break;
+ }
+ error:
+ if (match == 0)
+ {
+ /* Args don't match. */
+ if (&insn[1] - bpf_opcodes < bpf_num_opcodes
+ && (insn->name == insn[1].name
+ || !strcmp (insn->name, insn[1].name)))
+ {
+ ++insn;
+ s = argsStart;
+ continue;
+ }
+ else
+ {
+ as_bad (_("Illegal operands%s"), "");
+ return;
+ }
+ }
+ break;
+ }
+
+ output_insn (&the_insn);
+}
+
+void
+md_number_to_chars (char *buf, valueT val, int n)
+{
+ if (target_big_endian)
+ number_to_chars_bigendian (buf, val, n);
+ else
+ number_to_chars_littleendian (buf, val, n);
+}
+
+static void
+md_apply_u16 (offsetT val, char *buf)
+{
+ long off;
+
+ if (target_big_endian)
+ off = bfd_getb16 ((unsigned char *) buf + 2);
+ else
+ off = bfd_getl16 ((unsigned char *) buf + 2);
+ off |= val;
+ if (target_big_endian)
+ bfd_putb16 (off, (unsigned char *) buf + 2);
+ else
+ bfd_putl16 (off, (unsigned char *) buf + 2);
+}
+
+static void
+md_apply_u32 (offsetT val, char *buf)
+{
+ long imm;
+
+ if (target_big_endian)
+ imm = bfd_getb32 ((unsigned char *) buf + 4);
+ else
+ imm = bfd_getl32 ((unsigned char *) buf + 4);
+ imm |= val;
+ if (target_big_endian)
+ bfd_putb32 (imm, (unsigned char *) buf + 4);
+ else
+ bfd_putl32 (imm, (unsigned char *) buf + 4);
+}
+
+static void
+md_apply_u64 (offsetT val, char *buf)
+{
+ md_apply_u32(val & 0xffffffff, buf);
+ md_apply_u32((val >> 32) & 0xffffffff, buf + 12);
+}
+
+void
+md_apply_fix (fixS *fixP, valueT *valP ATTRIBUTE_UNUSED, segT segment ATTRIBUTE_UNUSED)
+{
+ char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+ offsetT val = * (offsetT *) valP;
+
+ gas_assert (fixP->fx_r_type < BFD_RELOC_UNUSED);
+
+ fixP->fx_addnumber = val; /* Remember value for emit_reloc. */
+
+ /* If this is a data relocation, just output VAL. */
+
+ if (fixP->fx_r_type == BFD_RELOC_8)
+ {
+ md_number_to_chars (buf, val, 1);
+ }
+ else if (fixP->fx_r_type == BFD_RELOC_16)
+ {
+ md_number_to_chars (buf, val, 2);
+ }
+ else if (fixP->fx_r_type == BFD_RELOC_32)
+ {
+ md_number_to_chars (buf, val, 4);
+ }
+ else if (fixP->fx_r_type == BFD_RELOC_64)
+ {
+ md_number_to_chars (buf, val, 8);
+ }
+ else if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+ || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+ {
+ fixP->fx_done = 0;
+ return;
+ }
+ else
+ {
+ /* It's a relocation against an instruction. */
+
+ switch (fixP->fx_r_type)
+ {
+ case BFD_RELOC_BPF_WDISP16:
+ val = val >> 3;
+ md_apply_u16((val + 1) & 0xffff, buf);
+ break;
+ case BFD_RELOC_BPF_16:
+ md_apply_u16(val & 0xffff, buf);
+ break;
+ case BFD_RELOC_BPF_32:
+ md_apply_u32(val & 0xffffffff, buf);
+ break;
+ case BFD_RELOC_BPF_64:
+ md_apply_u64(val, buf);
+ break;
+ case BFD_RELOC_NONE:
+ default:
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("bad or unhandled relocation type: 0x%02x"),
+ fixP->fx_r_type);
+ break;
+ }
+
+ }
+ if (fixP->fx_addsy == NULL)
+ fixP->fx_done = 1;
+}
+
+arelent *
+tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp ATTRIBUTE_UNUSED)
+{
+ bfd_reloc_code_real_type code;
+ arelent *reloc;
+
+ reloc = XNEW (arelent);
+ reloc->sym_ptr_ptr = XNEW (asymbol *);
+ *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+ reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+
+ switch (fixp->fx_r_type)
+ {
+ case BFD_RELOC_BPF_WDISP16:
+ case BFD_RELOC_BPF_16:
+ case BFD_RELOC_BPF_32:
+ case BFD_RELOC_BPF_64:
+ case BFD_RELOC_8:
+ case BFD_RELOC_16:
+ case BFD_RELOC_32:
+ case BFD_RELOC_64:
+ code = fixp->fx_r_type;
+ break;
+ default:
+ abort ();
+ return NULL;
+ }
+
+ reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
+ if (reloc->howto == 0)
+ {
+ as_bad_where (fixp->fx_file, fixp->fx_line,
+ _("internal error: can't export reloc type %d (`%s')"),
+ fixp->fx_r_type, bfd_get_reloc_code_name (code));
+ xfree (reloc);
+ return NULL;
+ }
+ if (code != BFD_RELOC_BPF_WDISP16)
+ reloc->addend = fixp->fx_addnumber;
+ else if (symbol_section_p (fixp->fx_addsy))
+ reloc->addend = (section->vma
+ + fixp->fx_addnumber
+ + md_pcrel_from (fixp));
+ else
+ reloc->addend = fixp->fx_offset;
+
+ return reloc;
+}
+
+symbolS *
+md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+valueT
+md_section_align (segT segment ATTRIBUTE_UNUSED, valueT size)
+{
+ return size;
+}
+
+long
+md_pcrel_from (fixS *fixP)
+{
+ long ret;
+
+ ret = fixP->fx_where + fixP->fx_frag->fr_address;
+ /* XXX */
+ return ret;
+}
+
+const char *
+md_atof (int type, char *litP, int *sizeP)
+{
+ return ieee_md_atof (type, litP, sizeP, target_big_endian);
+}
diff --git a/gas/config/tc-bpf.h b/gas/config/tc-bpf.h
new file mode 100644
index 0000000..45ab5d2
--- /dev/null
+++ b/gas/config/tc-bpf.h
@@ -0,0 +1,45 @@
+/* tc-bpf.h - Macros and type defines for the bpf.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3,
+ or (at your option) any later version.
+
+ GAS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with GAS; see the file COPYING. If not, write
+ to the Free Software Foundation, 51 Franklin Street - Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+#ifndef TC_BPF
+#define TC_BPF 1
+
+#define TARGET_ARCH bfd_arch_bpf
+
+#ifdef WORDS_BIGENDIAN
+#define TARGET_BYTES_BIG_ENDIAN 1
+#else
+#define TARGET_BYTES_BIG_ENDIAN 0
+#endif
+
+#define TARGET_FORMAT (bpf_target_format ())
+extern const char *bpf_target_format (void);
+
+#define md_convert_frag(b,s,f) \
+ as_fatal (_("bpf convert_frag\n"))
+#define md_estimate_size_before_relax(f,s) \
+ (as_fatal (_("estimate_size_before_relax called")), 1)
+#define md_operand(x)
+
+#define LISTING_HEADER "BPF GAS "
+
+#define WORKING_DOT_WORD
+
+#endif
diff --git a/gas/configure.tgt b/gas/configure.tgt
index ca58b69..fa959c3 100644
--- a/gas/configure.tgt
+++ b/gas/configure.tgt
@@ -54,6 +54,7 @@ case ${cpu} in
arm*be|arm*b) cpu_type=arm endian=big ;;
arm*) cpu_type=arm endian=little ;;
bfin*) cpu_type=bfin endian=little ;;
+ bpf*) cpu_type=bpf ;;
c4x*) cpu_type=tic4x ;;
cr16*) cpu_type=cr16 endian=little ;;
crisv32) cpu_type=cris arch=crisv32 ;;
@@ -171,6 +172,8 @@ case ${generic_target} in
bfin-*-uclinux*) fmt=elf em=linux ;;
bfin-*elf) fmt=elf ;;
+ bpf-*elf) fmt=elf ;;
+
cr16-*-elf*) fmt=elf ;;
cris-*-linux-* | crisv32-*-linux-*)
diff --git a/gas/testsuite/gas/bpf/arith.d b/gas/testsuite/gas/bpf/arith.d
new file mode 100644
index 0000000..d63de38
--- /dev/null
+++ b/gas/testsuite/gas/bpf/arith.d
@@ -0,0 +1,61 @@
+#as: -EL
+#objdump: -dr
+#name: arith
+
+.*: +file format elf64-bpfle
+
+Disassembly of section .text:
+
+0000000000000000 <.text>:
+ 0: 0f 12 00 00 00 00 00 00 add r1, r2
+ 8: 07 10 00 00 05 00 00 00 add r1, 5
+ 10: 0c 12 00 00 00 00 00 00 add32 r1, r2
+ 18: 04 10 00 00 05 00 00 00 add32 r1, 5
+ 20: 1f 12 00 00 00 00 00 00 sub r1, r2
+ 28: 17 10 00 00 05 00 00 00 sub r1, 5
+ 30: 1c 12 00 00 00 00 00 00 sub32 r1, r2
+ 38: 14 10 00 00 05 00 00 00 sub32 r1, 5
+ 40: 5f 12 00 00 00 00 00 00 and r1, r2
+ 48: 57 10 00 00 ff 00 00 00 and r1, 255
+ 50: 5c 12 00 00 00 00 00 00 and32 r1, r2
+ 58: 54 10 00 00 ff 00 00 00 and32 r1, 255
+ 60: 4f 12 00 00 00 00 00 00 or r1, r2
+ 68: a7 10 00 00 80 00 00 00 or r1, 128
+ 70: 4c 12 00 00 00 00 00 00 or32 r1, r2
+ 78: a4 10 00 00 80 00 00 00 or32 r1, 128
+ 80: af 12 00 00 00 00 00 00 xor r1, r2
+ 88: 47 10 00 00 1f 00 00 00 xor r1, 31
+ 90: ac 12 00 00 00 00 00 00 xor32 r1, r2
+ 98: 44 10 00 00 1f 00 00 00 xor32 r1, 31
+ a0: 2f 12 00 00 00 00 00 00 mul r1, r2
+ a8: 27 10 00 00 05 00 00 00 mul r1, 5
+ b0: 2c 12 00 00 00 00 00 00 mul32 r1, r2
+ b8: 24 10 00 00 05 00 00 00 mul32 r1, 5
+ c0: 3f 12 00 00 00 00 00 00 div r1, r2
+ c8: 37 10 00 00 02 00 00 00 div r1, 2
+ d0: 3c 12 00 00 00 00 00 00 div32 r1, r2
+ d8: 34 10 00 00 02 00 00 00 div32 r1, 2
+ e0: 9f 12 00 00 00 00 00 00 mod r1, r2
+ e8: 97 10 00 00 03 00 00 00 mod r1, 3
+ f0: 9c 12 00 00 00 00 00 00 mod32 r1, r2
+ f8: 94 10 00 00 03 00 00 00 mod32 r1, 3
+ 100: 6f 12 00 00 00 00 00 00 lsh r1, r2
+ 108: 67 10 00 00 01 00 00 00 lsh r1, 1
+ 110: 6c 12 00 00 00 00 00 00 lsh32 r1, r2
+ 118: 64 10 00 00 01 00 00 00 lsh32 r1, 1
+ 120: 7f 12 00 00 00 00 00 00 rsh r1, r2
+ 128: 77 10 00 00 01 00 00 00 rsh r1, 1
+ 130: 7c 12 00 00 00 00 00 00 rsh32 r1, r2
+ 138: 74 10 00 00 01 00 00 00 rsh32 r1, 1
+ 140: cf 12 00 00 00 00 00 00 arsh r1, r2
+ 148: c7 10 00 00 04 00 00 00 arsh r1, 4
+ 150: cc 12 00 00 00 00 00 00 arsh32 r1, r2
+ 158: c4 10 00 00 04 00 00 00 arsh32 r1, 4
+ 160: 8f 10 00 00 00 00 00 00 neg r1
+ 168: 8c 10 00 00 00 00 00 00 neg32 r1
+ 170: dc 10 00 00 10 00 00 00 endbe r1, 16
+ 178: dc 10 00 00 20 00 00 00 endbe r1, 32
+ 180: dc 10 00 00 40 00 00 00 endbe r1, 64
+ 188: d4 10 00 00 10 00 00 00 endle r1, 16
+ 190: d4 10 00 00 20 00 00 00 endle r1, 32
+ 198: d4 10 00 00 40 00 00 00 endle r1, 64
diff --git a/gas/testsuite/gas/bpf/arith.s b/gas/testsuite/gas/bpf/arith.s
new file mode 100644
index 0000000..58bf2a5
--- /dev/null
+++ b/gas/testsuite/gas/bpf/arith.s
@@ -0,0 +1,53 @@
+ .text
+ add r1, r2
+ add r1, 5
+ add32 r1, r2
+ add32 r1, 5
+ sub r1, r2
+ sub r1, 5
+ sub32 r1, r2
+ sub32 r1, 5
+ and r1, r2
+ and r1, 0xff
+ and32 r1, r2
+ and32 r1, 0xff
+ or r1, r2
+ or r1, 0x80
+ or32 r1, r2
+ or32 r1, 0x80
+ xor r1, r2
+ xor r1, 0x1f
+ xor32 r1, r2
+ xor32 r1, 0x1f
+ mul r1, r2
+ mul r1, 5
+ mul32 r1, r2
+ mul32 r1, 5
+ div r1, r2
+ div r1, 2
+ div32 r1, r2
+ div32 r1, 2
+ mod r1, r2
+ mod r1, 3
+ mod32 r1, r2
+ mod32 r1, 3
+ lsh r1, r2
+ lsh r1, 1
+ lsh32 r1, r2
+ lsh32 r1, 1
+ rsh r1, r2
+ rsh r1, 1
+ rsh32 r1, r2
+ rsh32 r1, 1
+ arsh r1, r2
+ arsh r1, 4
+ arsh32 r1, r2
+ arsh32 r1, 4
+ neg r1
+ neg32 r1
+ endbe r1, 16
+ endbe r1, 32
+ endbe r1, 64
+ endle r1, 16
+ endle r1, 32
+ endle r1, 64
diff --git a/gas/testsuite/gas/bpf/atomics.d b/gas/testsuite/gas/bpf/atomics.d
new file mode 100644
index 0000000..fc710d6
--- /dev/null
+++ b/gas/testsuite/gas/bpf/atomics.d
@@ -0,0 +1,12 @@
+#as: -EL
+#objdump: -dr
+#name: atomics
+
+.*: +file format elf64-bpfle
+
+Disassembly of section .text:
+
+0000000000000000 <.text>:
+ 0: b7 20 00 00 06 00 00 00 mov r2, 6
+ 8: db 12 00 00 00 00 00 00 xadddw \[r1\+0\], r2
+ 10: c3 12 08 00 00 00 00 00 xaddw \[r1\+8\], r2
diff --git a/gas/testsuite/gas/bpf/atomics.s b/gas/testsuite/gas/bpf/atomics.s
new file mode 100644
index 0000000..6552ef3
--- /dev/null
+++ b/gas/testsuite/gas/bpf/atomics.s
@@ -0,0 +1,4 @@
+ .text
+ mov r2, 6
+ xadddw [r1+0], r2
+ xaddw [r1+8], r2
diff --git a/gas/testsuite/gas/bpf/bpf.exp b/gas/testsuite/gas/bpf/bpf.exp
new file mode 100644
index 0000000..363fd2c
--- /dev/null
+++ b/gas/testsuite/gas/bpf/bpf.exp
@@ -0,0 +1,28 @@
+# Copyright (C) 2017 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+
+# BPF assembler testsuite
+
+if [istarget bpf*-*-*] {
+ run_dump_test "arith"
+ run_dump_test "jump"
+ run_dump_test "move"
+ run_dump_test "loads"
+ run_dump_test "stores"
+ run_dump_test "atomics"
+ run_dump_test "call"
+ run_dump_test "imm64"
+}
diff --git a/gas/testsuite/gas/bpf/call.d b/gas/testsuite/gas/bpf/call.d
new file mode 100644
index 0000000..8521f25
--- /dev/null
+++ b/gas/testsuite/gas/bpf/call.d
@@ -0,0 +1,14 @@
+#as: -EL
+#objdump: -dr
+#name: call
+
+.*: +file format elf64-bpfle
+
+Disassembly of section .text:
+
+0000000000000000 <.text>:
+ 0: 85 00 00 00 01 00 00 00 call 0x1
+ 8: 85 00 00 00 02 00 00 00 call 0x2
+ 10: 85 00 00 00 03 00 00 00 call 0x3
+ 18: 85 00 00 00 04 00 00 00 call 0x4
+ 20: 95 00 00 00 00 00 00 00 exit
diff --git a/gas/testsuite/gas/bpf/call.s b/gas/testsuite/gas/bpf/call.s
new file mode 100644
index 0000000..e31980d
--- /dev/null
+++ b/gas/testsuite/gas/bpf/call.s
@@ -0,0 +1,6 @@
+ .text
+ call 1
+ call 2
+ call 3
+ call 4
+ exit
diff --git a/gas/testsuite/gas/bpf/imm64.d b/gas/testsuite/gas/bpf/imm64.d
new file mode 100644
index 0000000..4dcaf7b
--- /dev/null
+++ b/gas/testsuite/gas/bpf/imm64.d
@@ -0,0 +1,30 @@
+#as: -EL
+#objdump: -dr
+#name: imm64a
+
+.*: +file format elf64-bpfle
+
+Disassembly of section .text:
+
+0000000000000000 <.text>:
+ 0: 18 10 00 00 01 00 00 00 ldimm64 r1, 1
+ 8: 00 00 00 00 00 00 00 00
+ 10: 18 10 00 00 02 00 00 00 ldimm64 r1, 2
+ 18: 00 00 00 00 00 00 00 00
+ 20: 18 10 00 00 00 00 01 00 ldimm64 r1, 65536
+ 28: 00 00 00 00 00 00 00 00
+ 30: 18 10 00 00 ff ff ff ff ldimm64 r1, 4294967295
+ 38: 00 00 00 00 00 00 00 00
+ 40: 18 10 00 00 01 00 00 00 ldimm64 r1, -4294967295
+ 48: 00 00 00 00 ff ff ff ff
+ 50: 18 10 00 00 ff ff ff ff ldimm64 r1, -1
+ 58: 00 00 00 00 ff ff ff ff
+ 60: 18 20 00 00 00 ff ff ff ldimm64 r2, -256
+ 68: 00 00 00 00 ff ff ff ff
+ 70: 18 30 00 00 00 00 ff ff ldimm64 r3, -65536
+ 78: 00 00 00 00 ff ff ff ff
+ 80: 18 40 00 00 00 00 00 00 ldimm64 r4, 4294967296
+ 88: 00 00 00 00 01 00 00 00
+ 90: 18 50 00 00 00 00 00 00 ldimm64 r5, -9223372036854775808
+ 98: 00 00 00 00 00 00 00 80
+ a0: 95 00 00 00 00 00 00 00 exit
diff --git a/gas/testsuite/gas/bpf/imm64.s b/gas/testsuite/gas/bpf/imm64.s
new file mode 100644
index 0000000..929e357
--- /dev/null
+++ b/gas/testsuite/gas/bpf/imm64.s
@@ -0,0 +1,12 @@
+ .text
+ ldimm64 r1, 1
+ ldimm64 r1, 2
+ ldimm64 r1, 65536
+ ldimm64 r1, 4294967295
+ ldimm64 r1, -4294967295
+ ldimm64 r1, -1
+ ldimm64 r2, -256
+ ldimm64 r3, -65536
+ ldimm64 r4, 4294967296
+ ldimm64 r5, -9223372036854775808
+ exit
diff --git a/gas/testsuite/gas/bpf/jump.d b/gas/testsuite/gas/bpf/jump.d
new file mode 100644
index 0000000..fc1e6bd
--- /dev/null
+++ b/gas/testsuite/gas/bpf/jump.d
@@ -0,0 +1,43 @@
+#as: -EL
+#objdump: -dr
+#name: jump
+
+.*: +file format elf64-bpfle
+
+Disassembly of section .text:
+
+0000000000000000 <.text>:
+ 0: 05 00 03 00 00 00 00 00 ja 0x10
+ 8: bf 11 00 00 00 00 00 00 mov r1, r1
+ 10: b7 20 00 00 03 00 00 00 mov r2, 3
+ 18: 25 20 06 00 02 00 00 00 jgt r2, 2, 0x40
+ 20: bf 11 00 00 00 00 00 00 mov r1, r1
+ 28: b7 30 00 00 03 00 00 00 mov r3, 3
+ 30: 15 30 03 00 03 00 00 00 jeq r3, 3, 0x40
+ 38: bf 11 00 00 00 00 00 00 mov r1, r1
+ 40: 1d 32 03 00 00 00 00 00 jeq r3, r2, 0x50
+ 48: bf 11 00 00 00 00 00 00 mov r1, r1
+ 50: b7 40 00 00 04 00 00 00 mov r4, 4
+ 58: 2d 43 03 00 00 00 00 00 jgt r4, r3, 0x68
+ 60: bf 11 00 00 00 00 00 00 mov r1, r1
+ 68: 3d 43 03 00 00 00 00 00 jge r4, r3, 0x78
+ 70: bf 11 00 00 00 00 00 00 mov r1, r1
+ 78: 35 30 03 00 03 00 00 00 jge r3, 3, 0x88
+ 80: bf 11 00 00 00 00 00 00 mov r1, r1
+ 88: 5d 43 03 00 00 00 00 00 jne r4, r3, 0x98
+ 90: bf 11 00 00 00 00 00 00 mov r1, r1
+ 98: 55 30 03 00 03 00 00 00 jne r3, 3, 0xa8
+ a0: bf 11 00 00 00 00 00 00 mov r1, r1
+ a8: 6d 43 03 00 00 00 00 00 jsgt r4, r3, 0xb8
+ b0: bf 11 00 00 00 00 00 00 mov r1, r1
+ b8: 65 30 03 00 03 00 00 00 jsgt r3, 3, 0xc8
+ c0: bf 11 00 00 00 00 00 00 mov r1, r1
+ c8: 7d 43 03 00 00 00 00 00 jsge r4, r3, 0xd8
+ d0: bf 11 00 00 00 00 00 00 mov r1, r1
+ d8: 75 30 03 00 03 00 00 00 jsge r3, 3, 0xe8
+ e0: bf 11 00 00 00 00 00 00 mov r1, r1
+ e8: 4d 43 03 00 00 00 00 00 jset r4, r3, 0xf8
+ f0: bf 11 00 00 00 00 00 00 mov r1, r1
+ f8: 45 30 03 00 03 00 00 00 jset r3, 3, 0x108
+ 100: bf 11 00 00 00 00 00 00 mov r1, r1
+ 108: 95 00 00 00 00 00 00 00 exit
diff --git a/gas/testsuite/gas/bpf/jump.s b/gas/testsuite/gas/bpf/jump.s
new file mode 100644
index 0000000..4e084b4
--- /dev/null
+++ b/gas/testsuite/gas/bpf/jump.s
@@ -0,0 +1,35 @@
+ .text
+ ja 1f
+ mov r1, r1
+1: mov r2, 3
+ jgt r2, 2, 1f
+ mov r1, r1
+ mov r3, 3
+ jeq r3, 3, 1f
+ mov r1, r1
+1: jeq r3, r2, 1f
+ mov r1, r1
+1: mov r4, 4
+ jgt r4, r3, 1f
+ mov r1, r1
+1: jge r4, r3, 1f
+ mov r1, r1
+1: jge r3, 3, 1f
+ mov r1, r1
+1: jne r4, r3, 1f
+ mov r1, r1
+1: jne r3, 3, 1f
+ mov r1, r1
+1: jsgt r4, r3, 1f
+ mov r1, r1
+1: jsgt r3, 3, 1f
+ mov r1, r1
+1: jsge r4, r3, 1f
+ mov r1, r1
+1: jsge r3, 3, 1f
+ mov r1, r1
+1: jset r4, r3, 1f
+ mov r1, r1
+1: jset r3, 3, 1f
+ mov r1, r1
+1: exit
diff --git a/gas/testsuite/gas/bpf/loads.d b/gas/testsuite/gas/bpf/loads.d
new file mode 100644
index 0000000..542e895
--- /dev/null
+++ b/gas/testsuite/gas/bpf/loads.d
@@ -0,0 +1,27 @@
+#as: -EL
+#objdump: -dr
+#name: loads
+
+.*: +file format elf64-bpfle
+
+Disassembly of section .text:
+
+0000000000000000 <.text>:
+ 0: 71 12 03 00 00 00 00 00 ldb r1, \[r2\+3\]
+ 8: 69 12 02 00 00 00 00 00 ldh r1, \[r2\+2\]
+ 10: 61 12 04 00 00 00 00 00 ldw r1, \[r2\+4\]
+ 18: 79 12 08 00 00 00 00 00 lddw r1, \[r2\+8\]
+ 20: 61 34 04 00 00 00 00 00 ldw r3, \[r4\+4\]
+ 28: 61 44 08 00 00 00 00 00 ldw r4, \[r4\+8\]
+ 30: 61 54 00 00 00 00 00 00 ldw r5, \[r4\+0\]
+ 38: 69 33 02 00 00 00 00 00 ldh r3, \[r3\+2\]
+ 40: 69 43 04 00 00 00 00 00 ldh r4, \[r3\+4\]
+ 48: 69 53 00 00 00 00 00 00 ldh r5, \[r3\+0\]
+ 50: 71 33 01 00 00 00 00 00 ldb r3, \[r3\+1\]
+ 58: 71 43 02 00 00 00 00 00 ldb r4, \[r3\+2\]
+ 60: 71 53 03 00 00 00 00 00 ldb r5, \[r3\+3\]
+ 68: 71 63 00 00 00 00 00 00 ldb r6, \[r3\+0\]
+ 70: 71 1a f8 ff 00 00 00 00 ldb r1, \[r10\+-8\]
+ 78: 69 2a f6 ff 00 00 00 00 ldh r2, \[r10\+-10\]
+ 80: 61 3a f4 ff 00 00 00 00 ldw r3, \[r10\+-12\]
+ 88: 79 4a f0 ff 00 00 00 00 lddw r4, \[r10\+-16\]
diff --git a/gas/testsuite/gas/bpf/loads.s b/gas/testsuite/gas/bpf/loads.s
new file mode 100644
index 0000000..1aa8f88
--- /dev/null
+++ b/gas/testsuite/gas/bpf/loads.s
@@ -0,0 +1,19 @@
+ .text
+ ldb r1, [r2+3]
+ ldh r1, [r2+2]
+ ldw r1, [r2+4]
+ lddw r1, [r2+8]
+ ldw r3, [r4+4]
+ ldw r4, [r4+8]
+ ldw r5, [r4+0]
+ ldh r3, [r3+2]
+ ldh r4, [r3+4]
+ ldh r5, [r3+0]
+ ldb r3, [r3+1]
+ ldb r4, [r3+2]
+ ldb r5, [r3+3]
+ ldb r6, [r3+0]
+ ldb r1, [r10-8]
+ ldh r2, [r10-10]
+ ldw r3, [r10-12]
+ lddw r4, [r10-16]
diff --git a/gas/testsuite/gas/bpf/move.d b/gas/testsuite/gas/bpf/move.d
new file mode 100644
index 0000000..f15ad23
--- /dev/null
+++ b/gas/testsuite/gas/bpf/move.d
@@ -0,0 +1,19 @@
+#as: -EL
+#objdump: -dr
+#name: move
+
+.*: +file format elf64-bpfle
+
+Disassembly of section .text:
+
+0000000000000000 <.text>:
+ 0: bf 12 00 00 00 00 00 00 mov r1, r2
+ 8: b7 10 00 00 ef 00 00 00 mov r1, 239
+ 10: bc 12 00 00 00 00 00 00 mov32 r1, r2
+ 18: b4 10 00 00 ef 00 00 00 mov32 r1, 239
+ 20: bf 36 00 00 00 00 00 00 mov r3, r6
+ 28: bf 63 00 00 00 00 00 00 mov r6, r3
+ 30: bf 89 00 00 00 00 00 00 mov r8, r9
+ 38: bf a1 00 00 00 00 00 00 mov r10, r1
+ 40: bf 73 00 00 00 00 00 00 mov r7, r3
+ 48: b7 50 00 00 02 00 00 00 mov r5, 2
diff --git a/gas/testsuite/gas/bpf/move.s b/gas/testsuite/gas/bpf/move.s
new file mode 100644
index 0000000..36797b3
--- /dev/null
+++ b/gas/testsuite/gas/bpf/move.s
@@ -0,0 +1,11 @@
+ .text
+ mov r1, r2
+ mov r1, 0xef
+ mov32 r1, r2
+ mov32 r1, 0xef
+ mov r3, r6
+ mov r6, r3
+ mov r8, r9
+ mov r10, r1
+ mov r7, r3
+ mov r5, 2
diff --git a/gas/testsuite/gas/bpf/stores.d b/gas/testsuite/gas/bpf/stores.d
new file mode 100644
index 0000000..6033d43
--- /dev/null
+++ b/gas/testsuite/gas/bpf/stores.d
@@ -0,0 +1,21 @@
+#as: -EL
+#objdump: -dr
+#name: stores
+
+.*: +file format elf64-bpfle
+
+Disassembly of section .text:
+
+0000000000000000 <.text>:
+ 0: 63 12 00 00 00 00 00 00 stw \[r1\+0\], r2
+ 8: 62 10 04 00 00 00 00 00 stw \[r1\+4\], 0
+ 10: 6b 13 00 00 00 00 00 00 sth \[r1\+0\], r3
+ 18: 6a 10 02 00 01 00 00 00 sth \[r1\+2\], 1
+ 20: 73 14 00 00 00 00 00 00 stb \[r1\+0\], r4
+ 28: 72 10 02 00 02 00 00 00 stb \[r1\+2\], 2
+ 30: 7b 15 08 00 00 00 00 00 stdw \[r1\+8\], r5
+ 38: 7a 10 10 00 10 00 00 00 stdw \[r1\+16\], 16
+ 40: 73 a1 f8 ff 00 00 00 00 stb \[r10\+-8\], r1
+ 48: 6b a2 f6 ff 00 00 00 00 sth \[r10\+-10\], r2
+ 50: 63 a3 f4 ff 00 00 00 00 stw \[r10\+-12\], r3
+ 58: 7b a4 f0 ff 00 00 00 00 stdw \[r10\+-16\], r4
diff --git a/gas/testsuite/gas/bpf/stores.s b/gas/testsuite/gas/bpf/stores.s
new file mode 100644
index 0000000..eb7c6e6
--- /dev/null
+++ b/gas/testsuite/gas/bpf/stores.s
@@ -0,0 +1,13 @@
+ .text
+ stw [r1+0], r2
+ stw [r1+4], 0
+ sth [r1+0], r3
+ sth [r1+2], 1
+ stb [r1+0], r4
+ stb [r1+2], 2
+ stdw [r1+8], r5
+ stdw [r1+16], 16
+ stb [r10-8], r1
+ sth [r10-10], r2
+ stw [r10-12], r3
+ stdw [r10-16], r4
diff --git a/gdb/bpf-tdep.c b/gdb/bpf-tdep.c
new file mode 100644
index 0000000..6629f73
--- /dev/null
+++ b/gdb/bpf-tdep.c
@@ -0,0 +1,229 @@
+/* Target-dependent code for eBPF, for GDB.
+
+ Copyright (C) 2017 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "inferior.h"
+#include "gdbcore.h"
+#include "arch-utils.h"
+#include "regcache.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "trad-frame.h"
+#include "dis-asm.h"
+#include "dwarf2-frame.h"
+#include "symtab.h"
+#include "elf-bfd.h"
+#include "osabi.h"
+#include "infcall.h"
+#include "bpf-tdep.h"
+
+static const char * const bpf_register_name_strings[] =
+{
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "pc",
+};
+
+#define NUM_BPF_REGNAMES ARRAY_SIZE (bpf_register_name_strings)
+
+/* Return the BPF register name corresponding to register I. */
+
+static const char *
+bpf_register_name (struct gdbarch *gdbarch, int i)
+{
+ return bpf_register_name_strings[i];
+}
+
+/* Return the GDB type object for the "standard" data type of data in
+ register N. */
+
+static struct type *
+bpf_register_type (struct gdbarch *gdbarch, int regnum)
+{
+ if (regnum == BPF_R10_REGNUM)
+ return builtin_type (gdbarch)->builtin_data_ptr;
+
+ if (regnum == BPF_PC_REGNUM)
+ return builtin_type (gdbarch)->builtin_func_ptr;
+
+ return builtin_type (gdbarch)->builtin_int32;
+}
+
+/* Convert DWARF2 register number REG to the appropriate register number
+ used by GDB. */
+
+static int
+bpf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
+{
+ if (reg < 0 || reg >= BPF_NUM_REGS)
+ return -1;
+
+ return reg;
+}
+
+static struct frame_id
+bpf_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+ CORE_ADDR sp;
+
+ sp = get_frame_register_unsigned (this_frame, BPF_R10_REGNUM);
+
+ return frame_id_build (sp, get_frame_pc (this_frame));
+}
+
+static CORE_ADDR
+bpf_push_dummy_call (struct gdbarch *gdbarch,
+ struct value *function,
+ struct regcache *regcache,
+ CORE_ADDR bp_addr,
+ int nargs,
+ struct value **args,
+ CORE_ADDR sp,
+ int struct_return,
+ CORE_ADDR struct_addr)
+{
+ return sp; /* XXX */
+}
+
+/* Extract a function return value of TYPE from REGCACHE, and copy
+ that into VALBUF. */
+
+static void
+bpf_extract_return_value (struct type *type, struct regcache *regcache,
+ gdb_byte *valbuf)
+{
+ int len = TYPE_LENGTH (type);
+ gdb_byte buf[8];
+
+ regcache_cooked_read (regcache, BPF_R0_REGNUM, buf);
+ memcpy (valbuf, buf + 8 - len, len);
+}
+
+/* Store the function return value of type TYPE from VALBUF into
+ REGCACHE. */
+
+static void
+bpf_store_return_value (struct type *type, struct regcache *regcache,
+ const gdb_byte *valbuf)
+{
+ int len = TYPE_LENGTH (type);
+ gdb_byte buf[8];
+
+ memcpy (buf + 8 - len, valbuf, len);
+ regcache_cooked_write (regcache, BPF_R0_REGNUM, buf);
+}
+
+/* Determine, for architecture GDBARCH, how a return value of TYPE
+ should be returned. If it is supposed to be returned in registers,
+ and READBUF is nonzero, read the appropriate value from REGCACHE,
+ and copy it into READBUF. If WRITEBUF is nonzero, write the value
+ from WRITEBUF into REGCACHE. */
+
+static enum return_value_convention
+bpf_return_value (struct gdbarch *gdbarch,
+ struct value *function,
+ struct type *type,
+ struct regcache *regcache,
+ gdb_byte *readbuf,
+ const gdb_byte *writebuf)
+{
+ if (TYPE_LENGTH (type) > 8)
+ return RETURN_VALUE_STRUCT_CONVENTION;
+
+ if (readbuf)
+ bpf_extract_return_value (type, regcache, readbuf);
+
+ if (writebuf)
+ bpf_store_return_value (type, regcache, writebuf);
+
+ return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+static CORE_ADDR
+bpf_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_unwind_register_unsigned (next_frame, BPF_PC_REGNUM);
+}
+
+/* Skip all the insns that appear in generated function prologues. */
+
+static CORE_ADDR
+bpf_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ return pc;
+}
+
+/* Implement the breakpoint_kind_from_pc gdbarch method. */
+
+static int
+bpf_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr)
+{
+ return 8;
+}
+
+/* Initialize the current architecture based on INFO. If possible,
+ re-use an architecture from ARCHES, which is a list of
+ architectures already created during this debugging session.
+
+ Called e.g. at program startup, when reading a core file, and when
+ reading a binary file. */
+
+static struct gdbarch *
+bpf_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ struct gdbarch_tdep *tdep;
+ struct gdbarch *gdbarch;
+
+ tdep = XNEW (struct gdbarch_tdep);
+ gdbarch = gdbarch_alloc (&info, tdep);
+
+ tdep->xxx = 0;
+
+ set_gdbarch_num_regs (gdbarch, BPF_NUM_REGS);
+ set_gdbarch_sp_regnum (gdbarch, BPF_R10_REGNUM);
+ set_gdbarch_pc_regnum (gdbarch, BPF_PC_REGNUM);
+ set_gdbarch_dwarf2_reg_to_regnum (gdbarch, bpf_reg_to_regnum);
+ set_gdbarch_register_name (gdbarch, bpf_register_name);
+ set_gdbarch_register_type (gdbarch, bpf_register_type);
+ set_gdbarch_dummy_id (gdbarch, bpf_dummy_id);
+ set_gdbarch_push_dummy_call (gdbarch, bpf_push_dummy_call);
+ set_gdbarch_return_value (gdbarch, bpf_return_value);
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+ set_gdbarch_frame_args_skip (gdbarch, 8);
+ set_gdbarch_unwind_pc (gdbarch, bpf_unwind_pc);
+ set_gdbarch_print_insn (gdbarch, print_insn_bpf);
+
+ set_gdbarch_skip_prologue (gdbarch, bpf_skip_prologue);
+ set_gdbarch_breakpoint_kind_from_pc (gdbarch, bpf_breakpoint_kind_from_pc);
+
+ /* Hook in ABI-specific overrides, if they have been registered. */
+ gdbarch_init_osabi (info, gdbarch);
+
+ dwarf2_append_unwinders (gdbarch);
+ return gdbarch;
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_bpf_tdep;
+
+void
+_initialize_bpf_tdep (void)
+{
+ register_gdbarch_init (bfd_arch_bpf, bpf_gdbarch_init);
+}
diff --git a/gdb/bpf-tdep.h b/gdb/bpf-tdep.h
new file mode 100644
index 0000000..52cae6d
--- /dev/null
+++ b/gdb/bpf-tdep.h
@@ -0,0 +1,40 @@
+/* Target-dependent code for eBPF, for GDB.
+
+ Copyright (C) 2017 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+enum gdb_regnum {
+ BPF_R0_REGNUM = 0,
+ BPF_R1_REGNUM,
+ BPF_R2_REGNUM,
+ BPF_R3_REGNUM,
+ BPF_R4_REGNUM,
+ BPF_R5_REGNUM,
+ BPF_R6_REGNUM,
+ BPF_R7_REGNUM,
+ BPF_R8_REGNUM,
+ BPF_R9_REGNUM,
+ BPF_R10_REGNUM,
+ BPF_PC_REGNUM,
+};
+
+#define BPF_NUM_REGS (BPF_PC_REGNUM + 1)
+
+struct gdbarch_tdep
+{
+ int xxx;
+};
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index fdcb7b1..e8d5fb4 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -142,6 +142,10 @@ bfin-*-*)
gdb_sim=../sim/bfin/libsim.a
;;
+bpf*)
+ # Target: eBPF
+ gdb_target_obs="bpf-tdep.o"
+ ;;
cris*)
# Target: CRIS
gdb_target_obs="cris-tdep.o cris-linux-tdep.o linux-tdep.o solib-svr4.o"
diff --git a/include/dis-asm.h b/include/dis-asm.h
index 6f1801d..cbfebc8 100644
--- a/include/dis-asm.h
+++ b/include/dis-asm.h
@@ -241,6 +241,7 @@ extern int print_insn_aarch64 (bfd_vma, disassemble_info *);
extern int print_insn_alpha (bfd_vma, disassemble_info *);
extern int print_insn_avr (bfd_vma, disassemble_info *);
extern int print_insn_bfin (bfd_vma, disassemble_info *);
+extern int print_insn_bpf (bfd_vma, disassemble_info *);
extern int print_insn_big_arm (bfd_vma, disassemble_info *);
extern int print_insn_big_mips (bfd_vma, disassemble_info *);
extern int print_insn_big_nios2 (bfd_vma, disassemble_info *);
diff --git a/include/elf/bpf.h b/include/elf/bpf.h
new file mode 100644
index 0000000..4aa38cc
--- /dev/null
+++ b/include/elf/bpf.h
@@ -0,0 +1,39 @@
+/* BPF ELF support for BFD.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+
+ This file is part of BFD, the Binary File Descriptor library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#ifndef _ELF_BPF_H
+#define _ELF_BPF_H
+
+#include "elf/reloc-macros.h"
+
+/* Relocation types. */
+START_RELOC_NUMBERS (elf_bpf_reloc_type)
+ RELOC_NUMBER (R_BPF_NONE, 0)
+ RELOC_NUMBER (R_BPF_INSN_64, 1)
+ RELOC_NUMBER (R_BPF_INSN_32, 2)
+ RELOC_NUMBER (R_BPF_INSN_16, 3)
+ RELOC_NUMBER (R_BPF_WDISP16, 4)
+ RELOC_NUMBER (R_BPF_DATA_8, 8)
+ RELOC_NUMBER (R_BPF_DATA_16, 9)
+ RELOC_NUMBER (R_BPF_DATA_32, 10)
+ RELOC_NUMBER (R_BPF_DATA_64, 11)
+END_RELOC_NUMBERS (R_BPF_max)
+
+#endif /* _ELF_BPF_H */
diff --git a/include/opcode/bpf.h b/include/opcode/bpf.h
new file mode 100644
index 0000000..298ed1b
--- /dev/null
+++ b/include/opcode/bpf.h
@@ -0,0 +1,16 @@
+#ifndef OPCODE_BPF_H
+#define OPCODE_BPF_H
+
+/* Structure of an opcode table entry. */
+
+typedef struct bpf_opcode
+{
+ const char *name;
+ unsigned char code;
+ const char *args;
+} bpf_opcode;
+
+extern const struct bpf_opcode bpf_opcodes[];
+extern const int bpf_num_opcodes;
+
+#endif /* OPCODE_BPF_H */
diff --git a/ld/Makefile.am b/ld/Makefile.am
index 3aa7e80..d840bed 100644
--- a/ld/Makefile.am
+++ b/ld/Makefile.am
@@ -477,6 +477,7 @@ ALL_64_EMULATION_SOURCES = \
eelf32ltsmipn32_fbsd.c \
eelf32mipswindiss.c \
eelf64_aix.c \
+ eelf64_bpf.c \
eelf64_ia64.c \
eelf64_ia64_fbsd.c \
eelf64_ia64_vms.c \
@@ -1920,6 +1921,9 @@ eelf32_x86_64_nacl.c: $(srcdir)/emulparams/elf32_x86_64_nacl.sh \
eelf64_aix.c: $(srcdir)/emulparams/elf64_aix.sh \
$(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+eelf64_bpf.c: $(srcdir)/emulparams/elf64_bpf.sh \
+ $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+
eelf64_ia64.c: $(srcdir)/emulparams/elf64_ia64.sh \
$(ELF_DEPS) $(srcdir)/emultempl/ia64elf.em \
$(srcdir)/emultempl/needrelax.em \
diff --git a/ld/Makefile.in b/ld/Makefile.in
index f485f4f..706a889 100644
--- a/ld/Makefile.in
+++ b/ld/Makefile.in
@@ -845,6 +845,7 @@ ALL_64_EMULATION_SOURCES = \
eelf32ltsmipn32_fbsd.c \
eelf32mipswindiss.c \
eelf64_aix.c \
+ eelf64_bpf.c \
eelf64_ia64.c \
eelf64_ia64_fbsd.c \
eelf64_ia64_vms.c \
@@ -1292,6 +1293,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32xstormy16.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32xtensa.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64_aix.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64_bpf.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64_ia64.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64_ia64_fbsd.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64_ia64_vms.Po@am__quote@
@@ -3484,6 +3486,9 @@ eelf32_x86_64_nacl.c: $(srcdir)/emulparams/elf32_x86_64_nacl.sh \
eelf64_aix.c: $(srcdir)/emulparams/elf64_aix.sh \
$(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+eelf64_bpf.c: $(srcdir)/emulparams/elf64_bpf.sh \
+ $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+
eelf64_ia64.c: $(srcdir)/emulparams/elf64_ia64.sh \
$(ELF_DEPS) $(srcdir)/emultempl/ia64elf.em \
$(srcdir)/emultempl/needrelax.em \
diff --git a/ld/configure.tgt b/ld/configure.tgt
index 895f0fb..13645f5 100644
--- a/ld/configure.tgt
+++ b/ld/configure.tgt
@@ -177,6 +177,8 @@ bfin-*-linux-uclibc*) targ_emul=elf32bfinfd;
targ_extra_emuls="elf32bfin"
targ_extra_libpath=$targ_extra_emuls
;;
+bpf-*-elf) targ_emul=elf64_bpf
+ ;;
cr16-*-elf*) targ_emul=elf32cr16 ;;
cr16c-*-elf*) targ_emul=elf32cr16c
;;
diff --git a/ld/emulparams/elf64_bpf.sh b/ld/emulparams/elf64_bpf.sh
new file mode 100644
index 0000000..0e1e549
--- /dev/null
+++ b/ld/emulparams/elf64_bpf.sh
@@ -0,0 +1,8 @@
+# See genscripts.sh and ../scripttempl/elf.sc for the meaning of these.
+SCRIPT_NAME=elf
+ELFSIZE=64
+TEMPLATE_NAME=elf32
+OUTPUT_FORMAT="elf64-bpf"
+TARGET_PAGE_SIZE=0x1000
+ARCH=bpf
+MACHINE=
diff --git a/opcodes/Makefile.am b/opcodes/Makefile.am
index 1ac6bb1..ccc9453 100644
--- a/opcodes/Makefile.am
+++ b/opcodes/Makefile.am
@@ -105,6 +105,8 @@ TARGET_LIBOPCODES_CFILES = \
arm-dis.c \
avr-dis.c \
bfin-dis.c \
+ bpf-dis.c \
+ bpf-opc.c \
cgen-asm.c \
cgen-bitset.c \
cgen-dis.c \
diff --git a/opcodes/bpf-dis.c b/opcodes/bpf-dis.c
new file mode 100644
index 0000000..39656bf
--- /dev/null
+++ b/opcodes/bpf-dis.c
@@ -0,0 +1,161 @@
+#include "sysdep.h"
+#include <stdio.h>
+#include "opcode/bpf.h"
+#include "dis-asm.h"
+#include "libiberty.h"
+
+#define HASH_SIZE 256
+#define HASH_INSN(CODE) (CODE)
+
+typedef struct bpf_opcode_hash
+{
+ struct bpf_opcode_hash *next;
+ const bpf_opcode *opcode;
+} bpf_opcode_hash;
+
+static bpf_opcode_hash *opcode_hash_table[HASH_SIZE];
+
+static void
+build_hash_table (const bpf_opcode *opcode_table,
+ bpf_opcode_hash **hash_table,
+ int num_opcodes)
+{
+ static bpf_opcode_hash *hash_buf = NULL;
+ int i;
+
+ memset (hash_table, 0, HASH_SIZE * sizeof (hash_table[0]));
+ if (hash_buf != NULL)
+ free (hash_buf);
+ hash_buf = xmalloc (sizeof (* hash_buf) * num_opcodes);
+ for (i = num_opcodes - 1; i >= 0; --i)
+ {
+ int hash = HASH_INSN (opcode_table[i].code);
+ bpf_opcode_hash *h = &hash_buf[i];
+
+ h->next = hash_table[hash];
+ h->opcode = &opcode_table[i];
+ hash_table[hash] = h;
+ }
+}
+
+int
+print_insn_bpf (bfd_vma memaddr, disassemble_info *info)
+{
+ static unsigned long current_mach = 0;
+ static int opcodes_initialized = 0;
+ bfd_vma (*getword) (const void *);
+ bfd_vma (*gethalf) (const void *);
+ FILE *stream = info->stream;
+ bpf_opcode_hash *op;
+ int code, dest, src;
+ bfd_byte buffer[8];
+ signed short off;
+ int status, ret;
+ signed int imm;
+
+ if (!opcodes_initialized
+ || info->mach != current_mach)
+ {
+ build_hash_table (bpf_opcodes, opcode_hash_table, bpf_num_opcodes);
+ current_mach = info->mach;
+ opcodes_initialized = 1;
+ }
+
+ info->bytes_per_line = 8;
+
+ status = (*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info);
+ if (status != 0)
+ {
+ (*info->memory_error_func) (status, memaddr, info);
+ return -1;
+ }
+
+ if (info->endian == BFD_ENDIAN_BIG)
+ {
+ getword = bfd_getb32;
+ gethalf = bfd_getb16;
+ }
+ else
+ {
+ getword = bfd_getl32;
+ gethalf = bfd_getl16;
+ }
+
+ code = buffer[0];
+ dest = (buffer[1] & 0xf0) >> 4;
+ src = buffer[1] & 0x0f;
+ off = gethalf(&buffer[2]);
+ imm = getword(&buffer[4]);
+
+ ret = sizeof (buffer);
+ for (op = opcode_hash_table[HASH_INSN (code)]; op; op = op->next)
+ {
+ const bpf_opcode *opcode = op->opcode;
+ BFD_HOST_U_64_BIT value;
+ signed int imm2;
+ const char *s;
+
+ if (opcode->code != code)
+ continue;
+
+ if (!strcmp (opcode->name, "mov")
+ && !strcmp (opcode->args, "1,2")
+ && src == 0 && dest == 0)
+ {
+ (*info->fprintf_func) (stream, "%s\t", opcode->name);
+ break;
+ }
+
+ (*info->fprintf_func) (stream, "%s\t", opcode->name);
+ for (s = opcode->args; *s != '\0'; s++)
+ {
+ switch (*s)
+ {
+ case '+':
+ default:
+ (*info->fprintf_func) (stream, "%c", *s);
+ break;
+ case ',':
+ (*info->fprintf_func) (stream, ", ");
+ break;
+ case '1':
+ (*info->fprintf_func) (stream, "r%d", dest);
+ break;
+ case '2':
+ (*info->fprintf_func) (stream, "r%d", src);
+ break;
+ case 'i':
+ (*info->fprintf_func) (stream, "%d", imm);
+ break;
+ case 'O':
+ (*info->fprintf_func) (stream, "%d", (int) off);
+ break;
+ case 'L':
+ info->target = memaddr + ((off - 1) * 8);
+ (*info->print_address_func) (info->target, info);
+ break;
+ case 'C':
+ info->target = imm;
+ (*info->print_address_func) (info->target, info);
+ break;
+ case 'D':
+ status = (*info->read_memory_func) (memaddr + 8, buffer,
+ sizeof (buffer), info);
+ if (status != 0)
+ {
+ (*info->memory_error_func) (status, memaddr, info);
+ return -1;
+ }
+ ret += sizeof (buffer);
+ imm2 = getword(&buffer[4]);
+ value = ((BFD_HOST_U_64_BIT) (unsigned) imm2) << 32;
+ value |= (BFD_HOST_U_64_BIT) (unsigned) imm;
+ (*info->fprintf_func) (stream, "%lld", (long long) value);
+ break;
+ }
+ }
+ break;
+ }
+
+ return ret;
+}
diff --git a/opcodes/bpf-opc.c b/opcodes/bpf-opc.c
new file mode 100644
index 0000000..8afb637
--- /dev/null
+++ b/opcodes/bpf-opc.c
@@ -0,0 +1,147 @@
+#include "sysdep.h"
+#include <stdio.h>
+#include "opcode/bpf.h"
+
+#define BPF_OPC_ALU64 0x07
+#define BPF_OPC_DW 0x18
+#define BPF_OPC_XADD 0xc0
+#define BPF_OPC_MOV 0xb0
+#define BPF_OPC_ARSH 0xc0
+#define BPF_OPC_END 0xd0
+#define BPF_OPC_TO_LE 0x00
+#define BPF_OPC_TO_BE 0x08
+#define BPF_OPC_JNE 0x50
+#define BPF_OPC_JSGT 0x60
+#define BPF_OPC_JSGE 0x70
+#define BPF_OPC_CALL 0x80
+#define BPF_OPC_EXIT 0x90
+
+#define BPF_OPC_LD 0x00
+#define BPF_OPC_LDX 0x01
+#define BPF_OPC_ST 0x02
+#define BPF_OPC_STX 0x03
+#define BPF_OPC_ALU 0x04
+#define BPF_OPC_JMP 0x05
+#define BPF_OPC_RET 0x06
+#define BPF_OPC_MISC 0x07
+
+#define BPF_OPC_W 0x00
+#define BPF_OPC_H 0x08
+#define BPF_OPC_B 0x10
+
+#define BPF_OPC_IMM 0x00
+#define BPF_OPC_ABS 0x20
+#define BPF_OPC_IND 0x40
+#define BPF_OPC_MEM 0x60
+#define BPF_OPC_LEL 0x80
+#define BPF_OPC_MSH 0xa0
+
+#define BPF_OPC_ADD 0x00
+#define BPF_OPC_SUB 0x10
+#define BPF_OPC_MUL 0x20
+#define BPF_OPC_DIV 0x30
+#define BPF_OPC_OR 0x40
+#define BPF_OPC_AND 0x50
+#define BPF_OPC_LSH 0x60
+#define BPF_OPC_RSH 0x70
+#define BPF_OPC_NEG 0x80
+#define BPF_OPC_MOD 0x90
+#define BPF_OPC_XOR 0xa0
+
+#define BPF_OPC_JA 0x00
+#define BPF_OPC_JEQ 0x10
+#define BPF_OPC_JGT 0x20
+#define BPF_OPC_JGE 0x30
+#define BPF_OPC_JSET 0x40
+
+#define BPF_OPC_K 0x00
+#define BPF_OPC_X 0x08
+
+const struct bpf_opcode bpf_opcodes[] = {
+ { "mov32", BPF_OPC_ALU | BPF_OPC_MOV | BPF_OPC_X, "1,2" },
+ { "mov32", BPF_OPC_ALU | BPF_OPC_MOV | BPF_OPC_K, "1,i" },
+ { "mov", BPF_OPC_ALU64 | BPF_OPC_MOV | BPF_OPC_X, "1,2" },
+ { "mov", BPF_OPC_ALU64 | BPF_OPC_MOV | BPF_OPC_K, "1,i" },
+ { "nop", BPF_OPC_ALU64 | BPF_OPC_MOV | BPF_OPC_X, "" },
+ { "add32", BPF_OPC_ALU | BPF_OPC_ADD | BPF_OPC_X, "1,2" },
+ { "add32", BPF_OPC_ALU | BPF_OPC_ADD | BPF_OPC_K, "1,i" },
+ { "add", BPF_OPC_ALU64 | BPF_OPC_ADD | BPF_OPC_X, "1,2" },
+ { "add", BPF_OPC_ALU64 | BPF_OPC_ADD | BPF_OPC_K, "1,i" },
+ { "sub32", BPF_OPC_ALU | BPF_OPC_SUB | BPF_OPC_X, "1,2" },
+ { "sub32", BPF_OPC_ALU | BPF_OPC_SUB | BPF_OPC_K, "1,i" },
+ { "sub", BPF_OPC_ALU64 | BPF_OPC_SUB | BPF_OPC_X, "1,2" },
+ { "sub", BPF_OPC_ALU64 | BPF_OPC_SUB | BPF_OPC_K, "1,i" },
+ { "and32", BPF_OPC_ALU | BPF_OPC_AND | BPF_OPC_X, "1,2" },
+ { "and32", BPF_OPC_ALU | BPF_OPC_AND | BPF_OPC_K, "1,i" },
+ { "and", BPF_OPC_ALU64 | BPF_OPC_AND | BPF_OPC_X, "1,2" },
+ { "and", BPF_OPC_ALU64 | BPF_OPC_AND | BPF_OPC_K, "1,i" },
+ { "or32", BPF_OPC_ALU | BPF_OPC_OR | BPF_OPC_X, "1,2" },
+ { "or32", BPF_OPC_ALU | BPF_OPC_XOR | BPF_OPC_K, "1,i" },
+ { "or", BPF_OPC_ALU64 | BPF_OPC_OR | BPF_OPC_X, "1,2" },
+ { "or", BPF_OPC_ALU64 | BPF_OPC_XOR | BPF_OPC_K, "1,i" },
+ { "xor32", BPF_OPC_ALU | BPF_OPC_XOR | BPF_OPC_X, "1,2" },
+ { "xor32", BPF_OPC_ALU | BPF_OPC_OR | BPF_OPC_K, "1,i" },
+ { "xor", BPF_OPC_ALU64 | BPF_OPC_XOR | BPF_OPC_X, "1,2" },
+ { "xor", BPF_OPC_ALU64 | BPF_OPC_OR | BPF_OPC_K, "1,i" },
+ { "mul32", BPF_OPC_ALU | BPF_OPC_MUL | BPF_OPC_X, "1,2" },
+ { "mul32", BPF_OPC_ALU | BPF_OPC_MUL | BPF_OPC_K, "1,i" },
+ { "mul", BPF_OPC_ALU64 | BPF_OPC_MUL | BPF_OPC_X, "1,2" },
+ { "mul", BPF_OPC_ALU64 | BPF_OPC_MUL | BPF_OPC_K, "1,i" },
+ { "div32", BPF_OPC_ALU | BPF_OPC_DIV | BPF_OPC_X, "1,2" },
+ { "div32", BPF_OPC_ALU | BPF_OPC_DIV | BPF_OPC_K, "1,i" },
+ { "div", BPF_OPC_ALU64 | BPF_OPC_DIV | BPF_OPC_X, "1,2" },
+ { "div", BPF_OPC_ALU64 | BPF_OPC_DIV | BPF_OPC_K, "1,i" },
+ { "mod32", BPF_OPC_ALU | BPF_OPC_MOD | BPF_OPC_X, "1,2" },
+ { "mod32", BPF_OPC_ALU | BPF_OPC_MOD | BPF_OPC_K, "1,i" },
+ { "mod", BPF_OPC_ALU64 | BPF_OPC_MOD | BPF_OPC_X, "1,2" },
+ { "mod", BPF_OPC_ALU64 | BPF_OPC_MOD | BPF_OPC_K, "1,i" },
+ { "lsh32", BPF_OPC_ALU | BPF_OPC_LSH | BPF_OPC_X, "1,2" },
+ { "lsh32", BPF_OPC_ALU | BPF_OPC_LSH | BPF_OPC_K, "1,i" },
+ { "lsh", BPF_OPC_ALU64 | BPF_OPC_LSH | BPF_OPC_X, "1,2" },
+ { "lsh", BPF_OPC_ALU64 | BPF_OPC_LSH | BPF_OPC_K, "1,i" },
+ { "rsh32", BPF_OPC_ALU | BPF_OPC_RSH | BPF_OPC_X, "1,2" },
+ { "rsh32", BPF_OPC_ALU | BPF_OPC_RSH | BPF_OPC_K, "1,i" },
+ { "rsh", BPF_OPC_ALU64 | BPF_OPC_RSH | BPF_OPC_X, "1,2" },
+ { "rsh", BPF_OPC_ALU64 | BPF_OPC_RSH | BPF_OPC_K, "1,i" },
+ { "arsh32", BPF_OPC_ALU | BPF_OPC_ARSH | BPF_OPC_X, "1,2" },
+ { "arsh32", BPF_OPC_ALU | BPF_OPC_ARSH | BPF_OPC_K, "1,i" },
+ { "arsh", BPF_OPC_ALU64 | BPF_OPC_ARSH | BPF_OPC_X, "1,2" },
+ { "arsh", BPF_OPC_ALU64 | BPF_OPC_ARSH | BPF_OPC_K, "1,i" },
+ { "neg32", BPF_OPC_ALU | BPF_OPC_NEG | BPF_OPC_X, "1" },
+ { "neg", BPF_OPC_ALU64 | BPF_OPC_NEG | BPF_OPC_X, "1" },
+ { "endbe", BPF_OPC_ALU | BPF_OPC_END | BPF_OPC_TO_BE, "1,i" },
+ { "endle", BPF_OPC_ALU | BPF_OPC_END | BPF_OPC_TO_LE, "1,i" },
+ { "ja", BPF_OPC_JMP | BPF_OPC_JA, "L" },
+ { "jeq", BPF_OPC_JMP | BPF_OPC_JEQ | BPF_OPC_X, "1,2,L" },
+ { "jeq", BPF_OPC_JMP | BPF_OPC_JEQ | BPF_OPC_K, "1,i,L" },
+ { "jgt", BPF_OPC_JMP | BPF_OPC_JGT | BPF_OPC_X, "1,2,L" },
+ { "jgt", BPF_OPC_JMP | BPF_OPC_JGT | BPF_OPC_K, "1,i,L" },
+ { "jge", BPF_OPC_JMP | BPF_OPC_JGE | BPF_OPC_X, "1,2,L" },
+ { "jge", BPF_OPC_JMP | BPF_OPC_JGE | BPF_OPC_K, "1,i,L" },
+ { "jne", BPF_OPC_JMP | BPF_OPC_JNE | BPF_OPC_X, "1,2,L" },
+ { "jne", BPF_OPC_JMP | BPF_OPC_JNE | BPF_OPC_K, "1,i,L" },
+ { "jsgt", BPF_OPC_JMP | BPF_OPC_JSGT | BPF_OPC_X, "1,2,L" },
+ { "jsgt", BPF_OPC_JMP | BPF_OPC_JSGT | BPF_OPC_K, "1,i,L" },
+ { "jsge", BPF_OPC_JMP | BPF_OPC_JSGE | BPF_OPC_X, "1,2,L" },
+ { "jsge", BPF_OPC_JMP | BPF_OPC_JSGE | BPF_OPC_K, "1,i,L" },
+ { "jset", BPF_OPC_JMP | BPF_OPC_JSET | BPF_OPC_X, "1,2,L" },
+ { "jset", BPF_OPC_JMP | BPF_OPC_JSET | BPF_OPC_K, "1,i,L" },
+ { "call", BPF_OPC_JMP | BPF_OPC_CALL, "C" },
+ { "exit", BPF_OPC_JMP | BPF_OPC_EXIT, "" },
+ { "ldimm64", BPF_OPC_LD | BPF_OPC_IMM | BPF_OPC_DW, "1,D" },
+ { "ldw", BPF_OPC_LDX | BPF_OPC_MEM | BPF_OPC_W, "1,[2+O]" },
+ { "ldh", BPF_OPC_LDX | BPF_OPC_MEM | BPF_OPC_H, "1,[2+O]" },
+ { "ldb", BPF_OPC_LDX | BPF_OPC_MEM | BPF_OPC_B, "1,[2+O]" },
+ { "lddw", BPF_OPC_LDX | BPF_OPC_MEM | BPF_OPC_DW, "1,[2+O]" },
+ { "stw", BPF_OPC_STX | BPF_OPC_MEM | BPF_OPC_W, "[1+O],2" },
+ { "stw", BPF_OPC_ST | BPF_OPC_MEM | BPF_OPC_W, "[1+O],i" },
+ { "sth", BPF_OPC_STX | BPF_OPC_MEM | BPF_OPC_H, "[1+O],2" },
+ { "sth", BPF_OPC_ST | BPF_OPC_MEM | BPF_OPC_H, "[1+O],i" },
+ { "stb", BPF_OPC_STX | BPF_OPC_MEM | BPF_OPC_B, "[1+O],2" },
+ { "stb", BPF_OPC_ST | BPF_OPC_MEM | BPF_OPC_B, "[1+O],i" },
+ { "stdw", BPF_OPC_STX | BPF_OPC_MEM | BPF_OPC_DW, "[1+O],2" },
+ { "stdw", BPF_OPC_ST | BPF_OPC_MEM | BPF_OPC_DW, "[1+O],i" },
+ { "xaddw", BPF_OPC_STX | BPF_OPC_XADD | BPF_OPC_W, "[1+O],2" },
+ { "xadddw", BPF_OPC_STX | BPF_OPC_XADD | BPF_OPC_DW, "[1+O],2" },
+};
+const int bpf_num_opcodes = ((sizeof bpf_opcodes)/(sizeof bpf_opcodes[0]));
diff --git a/opcodes/configure b/opcodes/configure
index 27d1472..7583220 100755
--- a/opcodes/configure
+++ b/opcodes/configure
@@ -12634,6 +12634,7 @@ if test x${all_targets} = xfalse ; then
bfd_arm_arch) ta="$ta arm-dis.lo" ;;
bfd_avr_arch) ta="$ta avr-dis.lo" ;;
bfd_bfin_arch) ta="$ta bfin-dis.lo" ;;
+ bfd_bpf_arch) ta="$ta bpf-dis.lo bpf-opc.lo" ;;
bfd_cr16_arch) ta="$ta cr16-dis.lo cr16-opc.lo" ;;
bfd_cris_arch) ta="$ta cris-dis.lo cris-opc.lo cgen-bitset.lo" ;;
bfd_crx_arch) ta="$ta crx-dis.lo crx-opc.lo" ;;
diff --git a/opcodes/configure.ac b/opcodes/configure.ac
index a9fbfd6..7dc6a92 100644
--- a/opcodes/configure.ac
+++ b/opcodes/configure.ac
@@ -258,6 +258,7 @@ if test x${all_targets} = xfalse ; then
bfd_arm_arch) ta="$ta arm-dis.lo" ;;
bfd_avr_arch) ta="$ta avr-dis.lo" ;;
bfd_bfin_arch) ta="$ta bfin-dis.lo" ;;
+ bfd_bpf_arch) ta="$ta bpf-dis.lo bpf-opc.lo" ;;
bfd_cr16_arch) ta="$ta cr16-dis.lo cr16-opc.lo" ;;
bfd_cris_arch) ta="$ta cris-dis.lo cris-opc.lo cgen-bitset.lo" ;;
bfd_crx_arch) ta="$ta crx-dis.lo crx-opc.lo" ;;
diff --git a/opcodes/disassemble.c b/opcodes/disassemble.c
index dd7d3a3..e594f86 100644
--- a/opcodes/disassemble.c
+++ b/opcodes/disassemble.c
@@ -29,6 +29,7 @@
#define ARCH_arm
#define ARCH_avr
#define ARCH_bfin
+#define ARCH_bpf
#define ARCH_cr16
#define ARCH_cris
#define ARCH_crx
@@ -151,6 +152,11 @@ disassembler (bfd *abfd)
disassemble = print_insn_bfin;
break;
#endif
+#ifdef ARCH_bpf
+ case bfd_arch_bpf:
+ disassemble = print_insn_bpf;
+ break;
+#endif
#ifdef ARCH_cr16
case bfd_arch_cr16:
disassemble = print_insn_cr16;
diff --git a/sim/configure.tgt b/sim/configure.tgt
index c958fb3..09eec72 100644
--- a/sim/configure.tgt
+++ b/sim/configure.tgt
@@ -26,6 +26,9 @@ case "${target}" in
bfin-*-*)
SIM_ARCH(bfin)
;;
+ bpf-*-*)
+ SIM_ARCH(bpf)
+ ;;
cr16*-*-*)
SIM_ARCH(cr16)
;;
--
2.7.4
^ permalink raw reply related
* Re: [PATCH] netvsc: make sure napi enabled before vmbus_open
From: Stephen Hemminger @ 2017-04-30 16:22 UTC (permalink / raw)
To: David Miller; +Cc: netdev, sthemmin
In-Reply-To: <20170428.160913.1378797538282359486.davem@davemloft.net>
On Fri, 28 Apr 2017 16:09:13 -0400 (EDT)
David Miller <davem@davemloft.net> wrote:
> From: Stephen Hemminger <stephen@networkplumber.org>
> Date: Wed, 26 Apr 2017 16:58:30 -0700
>
> > This fixes a race where vmbus callback for new packet arriving
> > could occur before NAPI is initialized. Happens more on WS2008
> > which takes longer to setup channel.
> >
> > Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
>
> This doesn't apply cleanly to 'net'.
Patch was for net-next. Will resend in next group
^ permalink raw reply
* Re: [Patch net-next v2] ipv4: get rid of ip_ra_lock
From: Eric Dumazet @ 2017-04-30 16:42 UTC (permalink / raw)
To: Cong Wang; +Cc: netdev
In-Reply-To: <1493399069-31743-1-git-send-email-xiyou.wangcong@gmail.com>
On Fri, 2017-04-28 at 10:04 -0700, Cong Wang wrote:
> After commit 1215e51edad1 ("ipv4: fix a deadlock in ip_ra_control")
> we always take RTNL lock for ip_ra_control() which is the only place
> we update the list ip_ra_chain, so the ip_ra_lock is no longer needed.
>
> As Eric points out, BH does not need to disable either, RCU readers
> don't care.
>
> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
> ---
> net/ipv4/ip_sockglue.c | 9 +--------
> 1 file changed, 1 insertion(+), 8 deletions(-)
>
> diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
> index 1d46d05..4c25458 100644
> --- a/net/ipv4/ip_sockglue.c
> +++ b/net/ipv4/ip_sockglue.c
> @@ -330,7 +330,6 @@ int ip_cmsg_send(struct sock *sk, struct msghdr *msg, struct ipcm_cookie *ipc,
> sent to multicast group to reach destination designated router.
> */
> struct ip_ra_chain __rcu *ip_ra_chain;
> -static DEFINE_SPINLOCK(ip_ra_lock);
>
>
> static void ip_ra_destroy_rcu(struct rcu_head *head)
> @@ -352,21 +351,17 @@ int ip_ra_control(struct sock *sk, unsigned char on,
>
> new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
>
> - spin_lock_bh(&ip_ra_lock);
> for (rap = &ip_ra_chain;
> - (ra = rcu_dereference_protected(*rap,
> - lockdep_is_held(&ip_ra_lock))) != NULL;
> + (ra = rtnl_dereference(*rap)) != NULL;
> rap = &ra->next) {
> if (ra->sk == sk) {
> if (on) {
> - spin_unlock_bh(&ip_ra_lock);
> kfree(new_ra);
> return -EADDRINUSE;
> }
> /* dont let ip_call_ra_chain() use sk again */
> ra->sk = NULL;
> RCU_INIT_POINTER(*rap, ra->next);
> - spin_unlock_bh(&ip_ra_lock);
>
> if (ra->destructor)
> ra->destructor(sk);
> @@ -381,7 +376,6 @@ int ip_ra_control(struct sock *sk, unsigned char on,
> }
> }
> if (!new_ra) {
> - spin_unlock_bh(&ip_ra_lock);
> return -ENOBUFS;
> }
Minor point : You could have removed the {}
Acked-by: Eric Dumazet <edumazet@google.com>
Thanks !
^ permalink raw reply
* [PATCH net-next] mlxsw: spectrum_router: Simplify VRF enslavement
From: idosch @ 2017-04-30 16:47 UTC (permalink / raw)
To: netdev; +Cc: davem, jiri, mlxsw, Ido Schimmel
From: Ido Schimmel <idosch@mellanox.com>
When a netdev is enslaved to a VRF master, its router interface (RIF)
needs to be destroyed (if exists) and a new one created using the
corresponding virtual router (VR).
>From the driver's perspective, the above is equivalent to an inetaddr
event sent for this netdev. Therefore, when a port netdev (or its
uppers) are enslaved to a VRF master, call the same function that
would've been called had a NETDEV_UP was sent for this netdev in the
inetaddr notification chain.
This patch also fixes a bug when a LAG netdev with an existing RIF is
enslaved to a VRF. Before this patch, each LAG port would drop the
reference on the RIF, but would re-join the same one (in the wrong VR)
soon after. With this patch, the corresponding RIF is first destroyed
and a new one is created using the correct VR.
Fixes: 7179eb5acd59 ("mlxsw: spectrum_router: Add support for VRFs")
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Reviewed-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 77 +++------------
drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 10 +-
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 107 +++++++++------------
3 files changed, 63 insertions(+), 131 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 20c1b6c..88357ce 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -4106,7 +4106,6 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *dev,
if (!is_vlan_dev(upper_dev) &&
!netif_is_lag_master(upper_dev) &&
!netif_is_bridge_master(upper_dev) &&
- !netif_is_l3_master(upper_dev) &&
!netif_is_ovs_master(upper_dev))
return -EINVAL;
if (!info->linking)
@@ -4151,11 +4150,6 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *dev,
else
mlxsw_sp_port_lag_leave(mlxsw_sp_port,
upper_dev);
- } else if (netif_is_l3_master(upper_dev)) {
- if (info->linking)
- err = mlxsw_sp_port_vrf_join(mlxsw_sp_port);
- else
- mlxsw_sp_port_vrf_leave(mlxsw_sp_port);
} else if (netif_is_ovs_master(upper_dev)) {
if (info->linking)
err = mlxsw_sp_port_ovs_join(mlxsw_sp_port);
@@ -4275,7 +4269,7 @@ static int mlxsw_sp_netdevice_bridge_event(struct net_device *br_dev,
switch (event) {
case NETDEV_PRECHANGEUPPER:
upper_dev = info->upper_dev;
- if (!is_vlan_dev(upper_dev) && !netif_is_l3_master(upper_dev))
+ if (!is_vlan_dev(upper_dev))
return -EINVAL;
if (is_vlan_dev(upper_dev) &&
br_dev != mlxsw_sp->master_bridge.dev)
@@ -4290,12 +4284,6 @@ static int mlxsw_sp_netdevice_bridge_event(struct net_device *br_dev,
else
mlxsw_sp_master_bridge_vlan_unlink(mlxsw_sp,
upper_dev);
- } else if (netif_is_l3_master(upper_dev)) {
- if (info->linking)
- err = mlxsw_sp_bridge_vrf_join(mlxsw_sp,
- br_dev);
- else
- mlxsw_sp_bridge_vrf_leave(mlxsw_sp, br_dev);
} else {
err = -EINVAL;
WARN_ON(1);
@@ -4529,8 +4517,7 @@ static int mlxsw_sp_netdevice_vport_event(struct net_device *dev,
switch (event) {
case NETDEV_PRECHANGEUPPER:
upper_dev = info->upper_dev;
- if (!netif_is_bridge_master(upper_dev) &&
- !netif_is_l3_master(upper_dev))
+ if (!netif_is_bridge_master(upper_dev))
return -EINVAL;
if (!info->linking)
break;
@@ -4550,11 +4537,6 @@ static int mlxsw_sp_netdevice_vport_event(struct net_device *dev,
upper_dev);
else
mlxsw_sp_vport_bridge_leave(mlxsw_sp_vport);
- } else if (netif_is_l3_master(upper_dev)) {
- if (info->linking)
- err = mlxsw_sp_vport_vrf_join(mlxsw_sp_vport);
- else
- mlxsw_sp_vport_vrf_leave(mlxsw_sp_vport);
} else {
err = -EINVAL;
WARN_ON(1);
@@ -4585,47 +4567,6 @@ static int mlxsw_sp_netdevice_lag_vport_event(struct net_device *lag_dev,
return 0;
}
-static int mlxsw_sp_netdevice_bridge_vlan_event(struct net_device *vlan_dev,
- unsigned long event, void *ptr)
-{
- struct netdev_notifier_changeupper_info *info;
- struct mlxsw_sp *mlxsw_sp;
- int err = 0;
-
- mlxsw_sp = mlxsw_sp_lower_get(vlan_dev);
- if (!mlxsw_sp)
- return 0;
-
- info = ptr;
-
- switch (event) {
- case NETDEV_PRECHANGEUPPER:
- /* VLAN devices are only allowed on top of the
- * VLAN-aware bridge.
- */
- if (WARN_ON(vlan_dev_real_dev(vlan_dev) !=
- mlxsw_sp->master_bridge.dev))
- return -EINVAL;
- if (!netif_is_l3_master(info->upper_dev))
- return -EINVAL;
- break;
- case NETDEV_CHANGEUPPER:
- if (netif_is_l3_master(info->upper_dev)) {
- if (info->linking)
- err = mlxsw_sp_bridge_vrf_join(mlxsw_sp,
- vlan_dev);
- else
- mlxsw_sp_bridge_vrf_leave(mlxsw_sp, vlan_dev);
- } else {
- err = -EINVAL;
- WARN_ON(1);
- }
- break;
- }
-
- return err;
-}
-
static int mlxsw_sp_netdevice_vlan_event(struct net_device *vlan_dev,
unsigned long event, void *ptr)
{
@@ -4638,13 +4579,19 @@ static int mlxsw_sp_netdevice_vlan_event(struct net_device *vlan_dev,
else if (netif_is_lag_master(real_dev))
return mlxsw_sp_netdevice_lag_vport_event(real_dev, event, ptr,
vid);
- else if (netif_is_bridge_master(real_dev))
- return mlxsw_sp_netdevice_bridge_vlan_event(vlan_dev, event,
- ptr);
return 0;
}
+static bool mlxsw_sp_is_vrf_event(unsigned long event, void *ptr)
+{
+ struct netdev_notifier_changeupper_info *info = ptr;
+
+ if (event != NETDEV_PRECHANGEUPPER && event != NETDEV_CHANGEUPPER)
+ return false;
+ return netif_is_l3_master(info->upper_dev);
+}
+
static int mlxsw_sp_netdevice_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
@@ -4653,6 +4600,8 @@ static int mlxsw_sp_netdevice_event(struct notifier_block *unused,
if (event == NETDEV_CHANGEADDR || event == NETDEV_CHANGEMTU)
err = mlxsw_sp_netdevice_router_port_event(dev);
+ else if (mlxsw_sp_is_vrf_event(event, ptr))
+ err = mlxsw_sp_netdevice_vrf_event(dev, event, ptr);
else if (mlxsw_sp_port_dev_check(dev))
err = mlxsw_sp_netdevice_port_event(dev, event, ptr);
else if (netif_is_lag_master(dev))
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index 0af6e1a..0c23bc1 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -576,14 +576,8 @@ int mlxsw_sp_inetaddr_event(struct notifier_block *unused,
unsigned long event, void *ptr);
void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_rif *rif);
-int mlxsw_sp_vport_vrf_join(struct mlxsw_sp_port *mlxsw_sp_vport);
-void mlxsw_sp_vport_vrf_leave(struct mlxsw_sp_port *mlxsw_sp_vport);
-int mlxsw_sp_port_vrf_join(struct mlxsw_sp_port *mlxsw_sp_port);
-void mlxsw_sp_port_vrf_leave(struct mlxsw_sp_port *mlxsw_sp_port);
-int mlxsw_sp_bridge_vrf_join(struct mlxsw_sp *mlxsw_sp,
- struct net_device *l3_dev);
-void mlxsw_sp_bridge_vrf_leave(struct mlxsw_sp *mlxsw_sp,
- struct net_device *l3_dev);
+int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event,
+ struct netdev_notifier_changeupper_info *info);
int mlxsw_sp_kvdl_alloc(struct mlxsw_sp *mlxsw_sp, unsigned int entry_count,
u32 *p_entry_index);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 146f8c7..33cec1c 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -3345,6 +3345,21 @@ static int mlxsw_sp_inetaddr_vlan_event(struct net_device *vlan_dev,
return 0;
}
+static int __mlxsw_sp_inetaddr_event(struct net_device *dev,
+ unsigned long event)
+{
+ if (mlxsw_sp_port_dev_check(dev))
+ return mlxsw_sp_inetaddr_port_event(dev, event);
+ else if (netif_is_lag_master(dev))
+ return mlxsw_sp_inetaddr_lag_event(dev, event);
+ else if (netif_is_bridge_master(dev))
+ return mlxsw_sp_inetaddr_bridge_event(dev, dev, event);
+ else if (is_vlan_dev(dev))
+ return mlxsw_sp_inetaddr_vlan_event(dev, event);
+ else
+ return 0;
+}
+
int mlxsw_sp_inetaddr_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
@@ -3362,15 +3377,7 @@ int mlxsw_sp_inetaddr_event(struct notifier_block *unused,
if (!mlxsw_sp_rif_should_config(rif, ifa->ifa_dev, event))
goto out;
- if (mlxsw_sp_port_dev_check(dev))
- err = mlxsw_sp_inetaddr_port_event(dev, event);
- else if (netif_is_lag_master(dev))
- err = mlxsw_sp_inetaddr_lag_event(dev, event);
- else if (netif_is_bridge_master(dev))
- err = mlxsw_sp_inetaddr_bridge_event(dev, dev, event);
- else if (is_vlan_dev(dev))
- err = mlxsw_sp_inetaddr_vlan_event(dev, event);
-
+ err = __mlxsw_sp_inetaddr_event(dev, event);
out:
return notifier_from_errno(err);
}
@@ -3433,71 +3440,53 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev)
return err;
}
-int mlxsw_sp_vport_vrf_join(struct mlxsw_sp_port *mlxsw_sp_vport)
+static int mlxsw_sp_port_vrf_join(struct mlxsw_sp *mlxsw_sp,
+ struct net_device *l3_dev)
{
- struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport);
- struct net_device *dev = mlxsw_sp_vport->dev;
+ struct mlxsw_sp_rif *rif;
- /* In case vPort already has a RIF, then we need to drop it.
- * A new one will be created using the VRF's VR.
+ /* If netdev is already associated with a RIF, then we need to
+ * destroy it and create a new one with the new virtual router ID.
*/
- if (f && f->rif)
- mlxsw_sp_vport_rif_sp_leave(mlxsw_sp_vport);
-
- return mlxsw_sp_vport_rif_sp_join(mlxsw_sp_vport, dev);
-}
-
-void mlxsw_sp_vport_vrf_leave(struct mlxsw_sp_port *mlxsw_sp_vport)
-{
- mlxsw_sp_vport_rif_sp_leave(mlxsw_sp_vport);
-}
-
-int mlxsw_sp_port_vrf_join(struct mlxsw_sp_port *mlxsw_sp_port)
-{
- struct mlxsw_sp_port *mlxsw_sp_vport;
-
- mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, 1);
- if (WARN_ON(!mlxsw_sp_vport))
- return -EINVAL;
+ rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
+ if (rif)
+ __mlxsw_sp_inetaddr_event(l3_dev, NETDEV_DOWN);
- return mlxsw_sp_vport_vrf_join(mlxsw_sp_vport);
+ return __mlxsw_sp_inetaddr_event(l3_dev, NETDEV_UP);
}
-void mlxsw_sp_port_vrf_leave(struct mlxsw_sp_port *mlxsw_sp_port)
+static void mlxsw_sp_port_vrf_leave(struct mlxsw_sp *mlxsw_sp,
+ struct net_device *l3_dev)
{
- struct mlxsw_sp_port *mlxsw_sp_vport;
+ struct mlxsw_sp_rif *rif;
- mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, 1);
- if (WARN_ON(!mlxsw_sp_vport))
+ rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
+ if (!rif)
return;
-
- mlxsw_sp_vport_vrf_leave(mlxsw_sp_vport);
+ __mlxsw_sp_inetaddr_event(l3_dev, NETDEV_DOWN);
}
-int mlxsw_sp_bridge_vrf_join(struct mlxsw_sp *mlxsw_sp,
- struct net_device *l3_dev)
+int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event,
+ struct netdev_notifier_changeupper_info *info)
{
- struct mlxsw_sp_fid *f;
-
- f = mlxsw_sp_bridge_fid_get(mlxsw_sp, l3_dev);
- if (WARN_ON(!f))
- return -EINVAL;
-
- if (f->rif)
- mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->rif);
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(l3_dev);
+ int err = 0;
- return mlxsw_sp_rif_bridge_create(mlxsw_sp, l3_dev, f);
-}
+ if (!mlxsw_sp)
+ return 0;
-void mlxsw_sp_bridge_vrf_leave(struct mlxsw_sp *mlxsw_sp,
- struct net_device *l3_dev)
-{
- struct mlxsw_sp_fid *f;
+ switch (event) {
+ case NETDEV_PRECHANGEUPPER:
+ return 0;
+ case NETDEV_CHANGEUPPER:
+ if (info->linking)
+ err = mlxsw_sp_port_vrf_join(mlxsw_sp, l3_dev);
+ else
+ mlxsw_sp_port_vrf_leave(mlxsw_sp, l3_dev);
+ break;
+ }
- f = mlxsw_sp_bridge_fid_get(mlxsw_sp, l3_dev);
- if (WARN_ON(!f))
- return;
- mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->rif);
+ return err;
}
static void mlxsw_sp_router_fib_dump_flush(struct notifier_block *nb)
--
2.9.3
^ permalink raw reply related
* Re: [PATCH v3 binutils] Add BPF support to binutils...
From: David Miller @ 2017-04-30 18:21 UTC (permalink / raw)
To: ast; +Cc: daniel, aconole, netdev, xdp-newbies
In-Reply-To: <76ed19a7-add3-0642-4298-9402c7ff0be8@fb.com>
From: Alexei Starovoitov <ast@fb.com>
Date: Sat, 29 Apr 2017 23:44:59 -0700
> '-g' still doesn't seem to work:
> /w/binutils-gdb/bld/binutils/objdump: invalid relocation type 10
> /w/binutils-gdb/bld/binutils/objdump: BFD (GNU Binutils)
> 2.28.51.20170429 assertion fail ../../bfd/elf64-bpf.c:139
> 0: 18 01 00 00 39 47 98 83 ldimm64 r0, 590618314553
Ok, I can look at the debug info in little endian objects created by
clang now, but something is up with the dwarf information in
big-endian objects.
Your test program:
int bpf_prog1(void *ign)
{
volatile unsigned long t = 0x8983984739ull;
return *(unsigned long *)((0xffffffff8fff0002ull) + t);
}
built with:
clang -O2 -target bpfel -g -c x.c -o x.o
readelf can see it just fine:
[davem@localhost binutils]$ ./readelf --debug-dump=loc ./xel.o
Contents of the .debug_loc section:
Offset Begin End Expression
00000000 0000000000000000 0000000000000010 (DW_OP_reg1 (r1))
00000013 <End of list>
00000023 0000000000000010 0000000000000020 (DW_OP_constu: 590618314553; DW_OP_stack_value)
0000003d 0000000000000020 0000000000000030 (DW_OP_reg1 (r1))
00000050 <End of list>
But with big-endian:
[davem@localhost binutils]$ ./readelf --debug-dump=loc ./xeb.o
readelf: Warning: Invalid pointer size (0) in compunit header, using 4 instead
readelf: Warning: Bogus end-of-siblings marker detected at offset 27 in .debug_info section
readelf: Warning: Bogus end-of-siblings marker detected at offset 28 in .debug_info section
readelf: Warning: DIE at offset 0x29 refers to abbreviation number 48 which does not exist
readelf: Warning: Unable to load/parse the .debug_info section, so cannot interpret the .debug_loc section.
GDB behaves similarly, xel.o works fine but for the big-endian object:
Reading symbols from ./xeb.o...../../binutils-gdb/gdb/dwarf2read.c:16933: internal-error: read_address: bad switch, unsigned [in module /home/davem/src/GIT/BINUTILS/build-bpf/binutils/xeb.o]
It is entirely possible that the problem is on the LLVM side.
Can you double check that the dwarf2 emission code in LLVM is
using the correct endianness?
Here is my working diff against v4:
diff --git a/bfd/elf64-bpf.c b/bfd/elf64-bpf.c
index a42f768..1d8085e 100644
--- a/bfd/elf64-bpf.c
+++ b/bfd/elf64-bpf.c
@@ -15,6 +15,7 @@
static reloc_howto_type _bfd_bpf_elf_howto_table[] =
{
HOWTO(R_BPF_NONE, 0,3, 0,FALSE,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_BPF_NONE", FALSE,0,0x00000000,TRUE),
+ HOWTO(R_BPF_DATA_64, 0,4,64,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_BPF_DATA_64", FALSE,0,MINUS_ONE,TRUE),
/* XXX these are wrong XXX */
HOWTO(R_BPF_INSN_64, 0,4,64,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_BPF_INSN_64", FALSE,0,MINUS_ONE,TRUE),
@@ -22,13 +23,11 @@ static reloc_howto_type _bfd_bpf_elf_howto_table[] =
HOWTO(R_BPF_INSN_16, 0,1,16,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_BPF_INSN_16", FALSE,0,0x0000ffff,TRUE),
HOWTO(R_BPF_WDISP16, 0,1,16,TRUE, 0,complain_overflow_signed, bfd_elf_generic_reloc, "R_BPF_WDISP16", FALSE,0,0x0000ffff,TRUE),
- EMPTY_HOWTO(5),
EMPTY_HOWTO(6),
EMPTY_HOWTO(7),
HOWTO(R_BPF_DATA_8, 0,0, 8,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_BPF_DATA_8", FALSE,0,0x000000ff,TRUE),
HOWTO(R_BPF_DATA_16, 0,1,16,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_BPF_DATA_16", FALSE,0,0x0000ffff,TRUE),
HOWTO(R_BPF_DATA_32, 0,2,32,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_BPF_DATA_32", FALSE,0,0xffffffff,TRUE),
- HOWTO(R_BPF_DATA_64, 0,4,64,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_BPF_DATA_64", FALSE,0,MINUS_ONE,TRUE),
};
reloc_howto_type *
diff --git a/binutils/readelf.c b/binutils/readelf.c
index b4013fb..0e9716b 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -12254,7 +12254,7 @@ is_64bit_abs_reloc (unsigned int reloc_type)
case EM_ALPHA:
return reloc_type == 2; /* R_ALPHA_REFQUAD. */
case EM_BPF:
- return reloc_type == 11; /* R_BPF_DATA_64 */
+ return reloc_type == 1; /* R_BPF_DATA_64 */
case EM_IA_64:
return reloc_type == 0x27; /* R_IA64_DIR64LSB. */
case EM_PARISC:
diff --git a/include/elf/bpf.h b/include/elf/bpf.h
index 4aa38cc..0d6fddc 100644
--- a/include/elf/bpf.h
+++ b/include/elf/bpf.h
@@ -26,14 +26,14 @@
/* Relocation types. */
START_RELOC_NUMBERS (elf_bpf_reloc_type)
RELOC_NUMBER (R_BPF_NONE, 0)
- RELOC_NUMBER (R_BPF_INSN_64, 1)
- RELOC_NUMBER (R_BPF_INSN_32, 2)
- RELOC_NUMBER (R_BPF_INSN_16, 3)
- RELOC_NUMBER (R_BPF_WDISP16, 4)
+ RELOC_NUMBER (R_BPF_DATA_64, 1)
+ RELOC_NUMBER (R_BPF_INSN_64, 2)
+ RELOC_NUMBER (R_BPF_INSN_32, 3)
+ RELOC_NUMBER (R_BPF_INSN_16, 4)
+ RELOC_NUMBER (R_BPF_WDISP16, 5)
RELOC_NUMBER (R_BPF_DATA_8, 8)
RELOC_NUMBER (R_BPF_DATA_16, 9)
RELOC_NUMBER (R_BPF_DATA_32, 10)
- RELOC_NUMBER (R_BPF_DATA_64, 11)
END_RELOC_NUMBERS (R_BPF_max)
#endif /* _ELF_BPF_H */
^ permalink raw reply related
* Re: xdp_redirect ifindex vs port. Was: best API for returning/setting egress port?
From: John Fastabend @ 2017-04-30 22:55 UTC (permalink / raw)
To: Alexei Starovoitov, Jesper Dangaard Brouer
Cc: Andy Gospodarek, Alexei Starovoitov, Daniel Borkmann,
Daniel Borkmann, netdev@vger.kernel.org,
xdp-newbies@vger.kernel.org
In-Reply-To: <eff4fc1b-072b-13ed-a606-065904a6c9c3@fb.com>
On 17-04-29 06:04 PM, Alexei Starovoitov wrote:
> On 4/28/17 3:58 AM, Jesper Dangaard Brouer wrote:
>> On Thu, 27 Apr 2017 16:31:14 -0700
>> Alexei Starovoitov <ast@fb.com> wrote:
>>
>>> On 4/27/17 1:41 AM, Jesper Dangaard Brouer wrote:
>>>> When registering/attaching a XDP/bpf program, we would just send the
>>>> file-descriptor for this port-map along (like we do with the bpf_prog
>>>> FD). Plus, it own ingress-port number this program is in the port-map.
>>>>
>>>> It is not clear to me, in-which-data-structure on the kernel-side we
>>>> store this reference to the port-map and ingress-port. As today we only
>>>> have the "raw" struct bpf_prog pointer. I see several options:
>>>>
>>>> 1. Create a new xdp_prog struct that contains existing bpf_prog,
>>>> a port-map pointer and ingress-port. (IMHO easiest solution)
>>>>
>>>> 2. Just create a new pointer to port-map and store it in driver rx-ring
>>>> struct (like existing bpf_prog), but this create a race-challenge
>>>> replacing (cmpxchg) the program (or perhaps it's not a problem as it
>>>> runs under rcu and RTNL-lock).
>>>>
>>>> 3. Extend bpf_prog to store this port-map and ingress-port, and have a
>>>> fast-way to access it. I assume it will be accessible via
>>>> bpf_prog->bpf_prog_aux->used_maps[X] but it will be too slow for XDP.
>>>
>>> I'm not sure I completely follow the 3 proposals.
>>> Are you suggesting to have only one netdev_array per program?
>>
>> Yes, but I can see you have a more clever idea below.
>>
>>> Why not to allow any number like we do for tailcall+prog_array, etc?
>>
>>> We can teach verifier to allow new helper
>>> bpf_tx_port(netdev_array, port_num);
>>> to only be used with netdev_array map type.
>>> It will fetch netdevice pointer from netdev_array[port_num]
>>> and will tx the packet into it.
>>
>> I love it.
>>
>> I just don't like the "netdev" part of the name "netdev_array" as one
>> basic ideas of a port tabel, is that a port can be anything that can
>> consume a XDP_buff packet. This generalization allow us to move code
>> out of the drivers. We might be on the same page, as I do imagine that
>> netdev_array or port_array is just a struct bpf_map pointer, and the
>> bpf_map->map_type will tell us that this bpf_map contains net_device
>> pointers. Thus, when later introducing a new type of redirect (like to
>> a socket or remote-CPU) then we just add a new bpf_map_type for this,
>> without needing to change anything in the drivers, right?
>
> In theory, yes, but in practice I doubt it will be so easy.
> We probably shouldn't allow very different types of netdev
> into the same netdev_array or port_array (whatever the name).
> They need to be similar enough, otherwise we'd have to do run-time
> checks. If they're all the same, these checks can be done at
> insertion time instead.
>
I think we can just have different map types for each redirect type. So
a netdev_map_array, socket_map_array, etc.
>> Do you imagine that bpf-side bpf_tx_port() returns XDP_REDIRECT?
>> Or does it return if the call was successful (e.g validate port_num
>> existed in map)?
>
> don't know :)
> we need to brainstorm pros and cons.
>
>> On the kernel side, we need to receive this info "port_array" and
>> "port_num", given you don't provide the call a xdp_buff/ctx, then I
>> assume you want the per-CPU temp-store solution. Then during the
>> XDP_REDIRECT action we call a core redirect function that based on the
>> bpf_map_type does a lookup, and find the net_device ptr.
>
> hmm. didn't think that far either :)
> indeed makes sense to pass 'ctx' into such helper as well,
> so it's easier to deal with original netdev.
>
>>> We can make it similar to bpf_tail_call(), so that program will
>>> finish on successful bpf_tx_port() or
>>> make it into 'delayed' tx which will be executed when program finishes.
>>> Not sure which approach is better.
>>
>> I know you are talking about something slightly different, about
>> delaying TX.
>>
>> But I want to mention (as I've done before) that it is important (for
>> me) that we get bulking working/integrated. I imagine the driver will
>> call a function that will delay the TX/redirect action and at the end
>> of the NAPI cycle have a function that flush packets, bulk per
>> destination port.
>>
>> I was wondering where to store these delayed TX packets, but now that
>> we have an associated bpf_map data-structure (netdev_array), I'm thinking
>> about storing packets (ordered by port) inside that. And then have a
>> bpf_tx_flush(netdev_array) call in the driver (for every port-table-map
>> seen, which will likely be small).
>
> makes sense to me as well.
> Ideally we should try to make an api such, that batching or no-batching
> can be kernel choice. The program will just do
> xdp_tx_port(...something here...)
> and the kernel does the best for performance. If it needs to delay
> the result to do batching the api should allow that transparently.
> Like right now xdp program does 'return XDP_TX;' and
> on the kernel side we can either do immediate xmit (like we do today)
> or can change it to do batching and programs don't need to change.
I think on the kernel side we can just add a flag to tell the xmit routine
to hold off hitting the tail. Then when we have the last packet we can
just set the flag. For the case where you don't know when the last packet
is coming you can send a NULL xdp buff and have the tail updated. This seems
to give the most flexibility to driver writers to optimize for their hardware.
I also tried a xmit routine to send many xdp_bufs in one call. This
became a bit ugly IMO and I decided the above was actually better. The
basic problem is, in general, we get packets for all sorts of ports and
do not get say 10 packets all for one port in one call.
>
>>> We can also extend this netdev_array into broadcast/multicast. Like
>>> bpf_tx_allports(&netdev_array);
>>> call from the program will xmit the packet to all netdevices
>>> in that 'netdev_array' map type.
>>
>> When broadcasting you often don't want to broadcast the packet out of
>> the incoming interface. How can you support this?
>>
>> Normally you would know your ingress port, and then excluded that port
>> in the broadcast. But with many netdev_array's how do the program know
>> it's own ingress port.
>
> absolutely!
> bpf_tx_allports() should somehow exclude the port packet arrived on.
> What you're proposing about passing 'ctx' into this helper,
> should solve it, I guess.
+1 seems reasonable.
>
>> Thanks a lot for all this input, I got a much more clear picture of how
>> I can/should implement this :-)
>
> awesome :) Let's brainstorm more and get John's opinion on it as well,
> since sounds like he'll be heavy user of such api.
>
Yep I have a couple cls_tc programs that I'm eager to port as soon as the
infrastructure is there. I think this is generally headed the "right" direction.
I'm trying to wrap up the qdisc codes now and then will start working on getting
the basic xdp_redirect working. The qdisc stuff took a bit longer than I hoped
:/
Thanks,
John
^ permalink raw reply
* [PATCH 0/6] Drivers: hv: Miscellaneous fixes
From: kys @ 2017-04-30 23:20 UTC (permalink / raw)
To: davem, netdev, linux-kernel, devel, olaf, apw, jasowang,
leann.ogasawara, marcelo.cerri, sthemmin
From: K. Y. Srinivasan <kys@microsoft.com>
Miscellaneous fixes to vmbus and util drivers.
Alex Ng (1):
Tools: hv: vss: Thaw the filesystem and continue if freeze call has
timed out
K. Y. Srinivasan (3):
Drivers: hv: vmbus: Fix error code returned by vmbus_post_msg()
Drivers: hv: util: Make hv_poll_channel() a little more efficient
Drivers: hv: vmbus: Fix rescind handling
Long Li (1):
HV: properly delay KVP packets when negotiation is in progress
Vitaly Kuznetsov (1):
tools: hv: properly handle long paths
drivers/hv/channel.c | 8 ++++-
drivers/hv/channel_mgmt.c | 69 ++++++++++++++++++++++++++++++++++----------
drivers/hv/connection.c | 9 ++++--
drivers/hv/hv_kvp.c | 14 +++++----
drivers/hv/hyperv_vmbus.h | 11 +++++++
drivers/hv/vmbus_drv.c | 29 ++++++++++++++++++-
tools/hv/hv_kvp_daemon.c | 44 ++++++++++++-----------------
tools/hv/hv_vss_daemon.c | 4 ++-
8 files changed, 133 insertions(+), 55 deletions(-)
^ permalink raw reply
* [PATCH 1/6] Tools: hv: vss: Thaw the filesystem and continue if freeze call has timed out
From: kys @ 2017-04-30 23:21 UTC (permalink / raw)
To: davem, netdev, linux-kernel, devel, olaf, apw, jasowang,
leann.ogasawara, marcelo.cerri, sthemmin
Cc: Alex Ng, Michael Gissing
In-Reply-To: <1493594420-25214-1-git-send-email-kys@exchange.microsoft.com>
From: Alex Ng <alexng@messages.microsoft.com>
If a FREEZE operation takes too long, the driver may time out and move on
to another operation. The daemon is unaware of this and attempts to
notify the driver that the FREEZE succeeded. This results in an error from
the driver and the daemon leaves the filesystem in frozen state.
Fix this by thawing the filesystem and continuing.
Signed-off-by: Michael Gissing <mg@faulpeltz.net>
Signed-off-by: Alex Ng <alexng@messages.microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
---
tools/hv/hv_vss_daemon.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c
index e082980..7ba5419 100644
--- a/tools/hv/hv_vss_daemon.c
+++ b/tools/hv/hv_vss_daemon.c
@@ -261,7 +261,9 @@ int main(int argc, char *argv[])
if (len != sizeof(struct hv_vss_msg)) {
syslog(LOG_ERR, "write failed; error: %d %s", errno,
strerror(errno));
- exit(EXIT_FAILURE);
+
+ if (op == VSS_OP_FREEZE)
+ vss_operate(VSS_OP_THAW);
}
}
--
1.7.1
^ permalink raw reply related
* [PATCH 2/6] tools: hv: properly handle long paths
From: kys @ 2017-04-30 23:21 UTC (permalink / raw)
To: davem, netdev, linux-kernel, devel, olaf, apw, jasowang,
leann.ogasawara, marcelo.cerri, sthemmin
In-Reply-To: <1493594420-25214-1-git-send-email-kys@exchange.microsoft.com>
From: Vitaly Kuznetsov <vkuznets@redhat.com>
Paths can be up to PATH_MAX long and PATH_MAX is usually greater than 256.
While on it, simplify path reconstruction to a simple snprintf(), define
and reuse KVP_NET_DIR.
Suggested-by: Tomas Hozza <thozza@redhat.com>
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
---
tools/hv/hv_kvp_daemon.c | 44 ++++++++++++++++++--------------------------
1 files changed, 18 insertions(+), 26 deletions(-)
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index f1758fc..88b20e0 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -39,6 +39,7 @@
#include <fcntl.h>
#include <dirent.h>
#include <net/if.h>
+#include <limits.h>
#include <getopt.h>
/*
@@ -97,6 +98,8 @@ enum {
#define KVP_SCRIPTS_PATH "/usr/libexec/hypervkvpd/"
#endif
+#define KVP_NET_DIR "/sys/class/net/"
+
#define MAX_FILE_NAME 100
#define ENTRIES_PER_BLOCK 50
@@ -596,26 +599,21 @@ void kvp_get_os_info(void)
DIR *dir;
struct dirent *entry;
FILE *file;
- char *p, *q, *x;
+ char *p, *x;
char *if_name = NULL;
char buf[256];
- char *kvp_net_dir = "/sys/class/net/";
- char dev_id[256];
+ char dev_id[PATH_MAX];
- dir = opendir(kvp_net_dir);
+ dir = opendir(KVP_NET_DIR);
if (dir == NULL)
return NULL;
- snprintf(dev_id, sizeof(dev_id), "%s", kvp_net_dir);
- q = dev_id + strlen(kvp_net_dir);
-
while ((entry = readdir(dir)) != NULL) {
/*
* Set the state for the next pass.
*/
- *q = '\0';
- strcat(dev_id, entry->d_name);
- strcat(dev_id, "/device/device_id");
+ snprintf(dev_id, sizeof(dev_id), "%s%s/device/device_id",
+ KVP_NET_DIR, entry->d_name);
file = fopen(dev_id, "r");
if (file == NULL)
@@ -653,12 +651,12 @@ void kvp_get_os_info(void)
FILE *file;
char *p, *x;
char buf[256];
- char addr_file[256];
+ char addr_file[PATH_MAX];
unsigned int i;
char *mac_addr = NULL;
- snprintf(addr_file, sizeof(addr_file), "%s%s%s", "/sys/class/net/",
- if_name, "/address");
+ snprintf(addr_file, sizeof(addr_file), "%s%s%s", KVP_NET_DIR,
+ if_name, "/address");
file = fopen(addr_file, "r");
if (file == NULL)
@@ -688,28 +686,22 @@ void kvp_get_os_info(void)
DIR *dir;
struct dirent *entry;
FILE *file;
- char *p, *q, *x;
+ char *p, *x;
char *if_name = NULL;
char buf[256];
- char *kvp_net_dir = "/sys/class/net/";
- char dev_id[256];
+ char dev_id[PATH_MAX];
unsigned int i;
- dir = opendir(kvp_net_dir);
+ dir = opendir(KVP_NET_DIR);
if (dir == NULL)
return NULL;
- snprintf(dev_id, sizeof(dev_id), "%s", kvp_net_dir);
- q = dev_id + strlen(kvp_net_dir);
-
while ((entry = readdir(dir)) != NULL) {
/*
* Set the state for the next pass.
*/
- *q = '\0';
-
- strcat(dev_id, entry->d_name);
- strcat(dev_id, "/address");
+ snprintf(dev_id, sizeof(dev_id), "%s%s/address", KVP_NET_DIR,
+ entry->d_name);
file = fopen(dev_id, "r");
if (file == NULL)
@@ -1218,9 +1210,9 @@ static int process_ip_string(FILE *f, char *ip_string, int type)
static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
{
int error = 0;
- char if_file[128];
+ char if_file[PATH_MAX];
FILE *file;
- char cmd[512];
+ char cmd[PATH_MAX];
char *mac_addr;
/*
--
1.7.1
^ permalink raw reply related
* [PATCH 3/6] Drivers: hv: vmbus: Fix error code returned by vmbus_post_msg()
From: kys @ 2017-04-30 23:21 UTC (permalink / raw)
To: davem, netdev, linux-kernel, devel, olaf, apw, jasowang,
leann.ogasawara, marcelo.cerri, sthemmin
In-Reply-To: <1493594420-25214-1-git-send-email-kys@exchange.microsoft.com>
From: K. Y. Srinivasan <kys@microsoft.com>
ENOBUFS is a more approrpiate error code to be returned
when the hypervisor cannot post the message because of
insufficient buffers. Make the adjustment.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
---
drivers/hv/connection.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index fce27fb..a938fcf 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -370,7 +370,7 @@ int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep)
break;
case HV_STATUS_INSUFFICIENT_MEMORY:
case HV_STATUS_INSUFFICIENT_BUFFERS:
- ret = -ENOMEM;
+ ret = -ENOBUFS;
break;
case HV_STATUS_SUCCESS:
return ret;
--
1.7.1
^ permalink raw reply related
* [PATCH 4/6] Drivers: hv: util: Make hv_poll_channel() a little more efficient
From: kys @ 2017-04-30 23:21 UTC (permalink / raw)
To: davem, netdev, linux-kernel, devel, olaf, apw, jasowang,
leann.ogasawara, marcelo.cerri, sthemmin
In-Reply-To: <1493594420-25214-1-git-send-email-kys@exchange.microsoft.com>
From: K. Y. Srinivasan <kys@microsoft.com>
The current code unconditionally sends an IPI. If we are running on the
correct CPU and are in interrupt level, we don't need an IPI.
Make this adjustment.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
---
drivers/hv/hyperv_vmbus.h | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 6113e91..fa514be 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -411,6 +411,10 @@ static inline void hv_poll_channel(struct vmbus_channel *channel,
if (!channel)
return;
+ if (in_interrupt() && (channel->target_cpu == smp_processor_id())) {
+ cb(channel);
+ return;
+ }
smp_call_function_single(channel->target_cpu, cb, channel, true);
}
--
1.7.1
^ permalink raw reply related
* [PATCH 5/6] Drivers: hv: vmbus: Fix rescind handling
From: kys @ 2017-04-30 23:21 UTC (permalink / raw)
To: davem, netdev, linux-kernel, devel, olaf, apw, jasowang,
leann.ogasawara, marcelo.cerri, sthemmin
In-Reply-To: <1493594420-25214-1-git-send-email-kys@exchange.microsoft.com>
From: K. Y. Srinivasan <kys@microsoft.com>
Fix the rescind handling. This patch addresses the following rescind
scenario that is currently not handled correctly:
If a rescind were to be received while the offer is still being
peocessed, we will be blocked indefinitely since the rescind message
is handled on the same work element as the offer message. Fix this
issue.
I would like to thank Dexuan Cui <decui@microsoft.com> and
Long Li <longli@microsoft.com> for working with me on this patch.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
---
drivers/hv/channel.c | 8 ++++-
drivers/hv/channel_mgmt.c | 69 ++++++++++++++++++++++++++++++++++----------
drivers/hv/connection.c | 7 +++-
drivers/hv/hyperv_vmbus.h | 7 ++++
drivers/hv/vmbus_drv.c | 29 ++++++++++++++++++-
5 files changed, 99 insertions(+), 21 deletions(-)
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index 736ac76..e9bf0bb 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -630,9 +630,13 @@ void vmbus_close(struct vmbus_channel *channel)
*/
list_for_each_safe(cur, tmp, &channel->sc_list) {
cur_channel = list_entry(cur, struct vmbus_channel, sc_list);
- if (cur_channel->state != CHANNEL_OPENED_STATE)
- continue;
vmbus_close_internal(cur_channel);
+ if (cur_channel->rescind) {
+ mutex_lock(&vmbus_connection.channel_mutex);
+ hv_process_channel_removal(cur_channel,
+ cur_channel->offermsg.child_relid);
+ mutex_unlock(&vmbus_connection.channel_mutex);
+ }
}
/*
* Now close the primary.
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index eec616a..06529b3 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -428,7 +428,6 @@ void vmbus_free_channels(void)
{
struct vmbus_channel *channel, *tmp;
- mutex_lock(&vmbus_connection.channel_mutex);
list_for_each_entry_safe(channel, tmp, &vmbus_connection.chn_list,
listentry) {
/* hv_process_channel_removal() needs this */
@@ -436,7 +435,6 @@ void vmbus_free_channels(void)
vmbus_device_unregister(channel->device_obj);
}
- mutex_unlock(&vmbus_connection.channel_mutex);
}
/*
@@ -483,8 +481,10 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
list_add_tail(&newchannel->sc_list, &channel->sc_list);
channel->num_sc++;
spin_unlock_irqrestore(&channel->lock, flags);
- } else
+ } else {
+ atomic_dec(&vmbus_connection.offer_in_progress);
goto err_free_chan;
+ }
}
dev_type = hv_get_dev_type(newchannel);
@@ -511,6 +511,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
if (!fnew) {
if (channel->sc_creation_callback != NULL)
channel->sc_creation_callback(newchannel);
+ atomic_dec(&vmbus_connection.offer_in_progress);
return;
}
@@ -532,9 +533,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
* binding which eventually invokes the device driver's AddDevice()
* method.
*/
- mutex_lock(&vmbus_connection.channel_mutex);
ret = vmbus_device_register(newchannel->device_obj);
- mutex_unlock(&vmbus_connection.channel_mutex);
if (ret != 0) {
pr_err("unable to add child device object (relid %d)\n",
@@ -542,6 +541,8 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
kfree(newchannel->device_obj);
goto err_deq_chan;
}
+
+ atomic_dec(&vmbus_connection.offer_in_progress);
return;
err_deq_chan:
@@ -799,6 +800,7 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
newchannel = alloc_channel();
if (!newchannel) {
vmbus_release_relid(offer->child_relid);
+ atomic_dec(&vmbus_connection.offer_in_progress);
pr_err("Unable to allocate channel object\n");
return;
}
@@ -845,16 +847,38 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
rescind = (struct vmbus_channel_rescind_offer *)hdr;
+ /*
+ * The offer msg and the corresponding rescind msg
+ * from the host are guranteed to be ordered -
+ * offer comes in first and then the rescind.
+ * Since we process these events in work elements,
+ * and with preemption, we may end up processing
+ * the events out of order. Given that we handle these
+ * work elements on the same CPU, this is possible only
+ * in the case of preemption. In any case wait here
+ * until the offer processing has moved beyond the
+ * point where the channel is discoverable.
+ */
+
+ while (atomic_read(&vmbus_connection.offer_in_progress) != 0) {
+ /*
+ * We wait here until any channel offer is currently
+ * being processed.
+ */
+ msleep(1);
+ }
+
mutex_lock(&vmbus_connection.channel_mutex);
channel = relid2channel(rescind->child_relid);
+ mutex_unlock(&vmbus_connection.channel_mutex);
if (channel == NULL) {
/*
- * This is very impossible, because in
- * vmbus_process_offer(), we have already invoked
- * vmbus_release_relid() on error.
+ * We failed in processing the offer message;
+ * we would have cleaned up the relid in that
+ * failure path.
*/
- goto out;
+ return;
}
spin_lock_irqsave(&channel->lock, flags);
@@ -866,7 +890,7 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
if (channel->device_obj) {
if (channel->chn_rescind_callback) {
channel->chn_rescind_callback(channel);
- goto out;
+ return;
}
/*
* We will have to unregister this device from the
@@ -877,13 +901,26 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
vmbus_device_unregister(channel->device_obj);
put_device(dev);
}
- } else {
- hv_process_channel_removal(channel,
- channel->offermsg.child_relid);
}
-
-out:
- mutex_unlock(&vmbus_connection.channel_mutex);
+ if (channel->primary_channel != NULL) {
+ /*
+ * Sub-channel is being rescinded. Following is the channel
+ * close sequence when initiated from the driveri (refer to
+ * vmbus_close() for details):
+ * 1. Close all sub-channels first
+ * 2. Then close the primary channel.
+ */
+ if (channel->state == CHANNEL_OPEN_STATE) {
+ /*
+ * The channel is currently not open;
+ * it is safe for us to cleanup the channel.
+ */
+ mutex_lock(&vmbus_connection.channel_mutex);
+ hv_process_channel_removal(channel,
+ channel->offermsg.child_relid);
+ mutex_unlock(&vmbus_connection.channel_mutex);
+ }
+ }
}
void vmbus_hvsock_device_unregister(struct vmbus_channel *channel)
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index a938fcf..c2d74ee 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -93,10 +93,13 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,
* all the CPUs. This is needed for kexec to work correctly where
* the CPU attempting to connect may not be CPU 0.
*/
- if (version >= VERSION_WIN8_1)
+ if (version >= VERSION_WIN8_1) {
msg->target_vcpu = hv_context.vp_index[smp_processor_id()];
- else
+ vmbus_connection.connect_cpu = smp_processor_id();
+ } else {
msg->target_vcpu = 0;
+ vmbus_connection.connect_cpu = 0;
+ }
/*
* Add to list before we send the request since we may
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index fa514be..1b6a5e0 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -303,6 +303,13 @@ enum vmbus_connect_state {
#define MAX_SIZE_CHANNEL_MESSAGE HV_MESSAGE_PAYLOAD_BYTE_COUNT
struct vmbus_connection {
+ /*
+ * CPU on which the initial host contact was made.
+ */
+ int connect_cpu;
+
+ atomic_t offer_in_progress;
+
enum vmbus_connect_state conn_state;
atomic_t next_gpadl_handle;
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 0087b49..59bb3ef 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -798,8 +798,10 @@ static void vmbus_device_release(struct device *device)
struct hv_device *hv_dev = device_to_hv_device(device);
struct vmbus_channel *channel = hv_dev->channel;
+ mutex_lock(&vmbus_connection.channel_mutex);
hv_process_channel_removal(channel,
channel->offermsg.child_relid);
+ mutex_unlock(&vmbus_connection.channel_mutex);
kfree(hv_dev);
}
@@ -877,7 +879,32 @@ void vmbus_on_msg_dpc(unsigned long data)
INIT_WORK(&ctx->work, vmbus_onmessage_work);
memcpy(&ctx->msg, msg, sizeof(*msg));
- queue_work(vmbus_connection.work_queue, &ctx->work);
+ /*
+ * The host can generate a rescind message while we
+ * may still be handling the original offer. We deal with
+ * this condition by ensuring the processing is done on the
+ * same CPU.
+ */
+ switch (hdr->msgtype) {
+ case CHANNELMSG_RESCIND_CHANNELOFFER:
+ /*
+ * If we are handling the rescind message;
+ * schedule the work on the global work queue.
+ */
+ schedule_work_on(vmbus_connection.connect_cpu,
+ &ctx->work);
+ break;
+
+ case CHANNELMSG_OFFERCHANNEL:
+ atomic_inc(&vmbus_connection.offer_in_progress);
+ queue_work_on(vmbus_connection.connect_cpu,
+ vmbus_connection.work_queue,
+ &ctx->work);
+ break;
+
+ default:
+ queue_work(vmbus_connection.work_queue, &ctx->work);
+ }
} else
entry->message_handler(hdr);
--
1.7.1
^ permalink raw reply related
* [PATCH 6/6] HV: properly delay KVP packets when negotiation is in progress
From: kys @ 2017-04-30 23:21 UTC (permalink / raw)
To: davem, netdev, linux-kernel, devel, olaf, apw, jasowang,
leann.ogasawara, marcelo.cerri, sthemmin
In-Reply-To: <1493594420-25214-1-git-send-email-kys@exchange.microsoft.com>
From: Long Li <longli@microsoft.com>
The host may send multiple negotiation packets
(due to timeout) before the KVP user-mode daemon
is connected. KVP user-mode daemon is connected.
We need to defer processing those packets
until the daemon is negotiated and connected.
It's okay for guest to respond
to all negotiation packets.
In addition, the host may send multiple staged
KVP requests as soon as negotiation is done.
We need to properly process those packets using one
tasklet for exclusive access to ring buffer.
This patch is based on the work of
Nick Meier <Nick.Meier@microsoft.com>.
Signed-off-by: Long Li <longli@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
---
drivers/hv/hv_kvp.c | 14 ++++++++------
1 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index e99ff2d..9a90b91 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -112,7 +112,7 @@ static void kvp_poll_wrapper(void *channel)
{
/* Transaction is finished, reset the state here to avoid races. */
kvp_transaction.state = HVUTIL_READY;
- hv_kvp_onchannelcallback(channel);
+ tasklet_schedule(&((struct vmbus_channel *)channel)->callback_event);
}
static void kvp_register_done(void)
@@ -159,7 +159,7 @@ static void kvp_timeout_func(struct work_struct *dummy)
static void kvp_host_handshake_func(struct work_struct *dummy)
{
- hv_poll_channel(kvp_transaction.recv_channel, hv_kvp_onchannelcallback);
+ tasklet_schedule(&kvp_transaction.recv_channel->callback_event);
}
static int kvp_handle_handshake(struct hv_kvp_msg *msg)
@@ -625,16 +625,17 @@ void hv_kvp_onchannelcallback(void *context)
NEGO_IN_PROGRESS,
NEGO_FINISHED} host_negotiatied = NEGO_NOT_STARTED;
- if (host_negotiatied == NEGO_NOT_STARTED &&
- kvp_transaction.state < HVUTIL_READY) {
+ if (kvp_transaction.state < HVUTIL_READY) {
/*
* If userspace daemon is not connected and host is asking
* us to negotiate we need to delay to not lose messages.
* This is important for Failover IP setting.
*/
- host_negotiatied = NEGO_IN_PROGRESS;
- schedule_delayed_work(&kvp_host_handshake_work,
+ if (host_negotiatied == NEGO_NOT_STARTED) {
+ host_negotiatied = NEGO_IN_PROGRESS;
+ schedule_delayed_work(&kvp_host_handshake_work,
HV_UTIL_NEGO_TIMEOUT * HZ);
+ }
return;
}
if (kvp_transaction.state > HVUTIL_READY)
@@ -702,6 +703,7 @@ void hv_kvp_onchannelcallback(void *context)
VM_PKT_DATA_INBAND, 0);
host_negotiatied = NEGO_FINISHED;
+ hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
}
}
--
1.7.1
^ permalink raw reply related
* Re: [PATCH net-next iproute2] ip: increase number of MPLS labels
From: David Ahern @ 2017-04-30 23:42 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev, Eric W. Biederman, roopa
In-Reply-To: <20170429230430.702c6b72@xeon-e3>
On 4/30/17 12:04 AM, Stephen Hemminger wrote:
> On Sat, 29 Apr 2017 20:48:50 -0700
> David Ahern <dsa@cumulusnetworks.com> wrote:
>
>> Kernel now supports more than 2 labels. Increase ip to
>> handle up to 16 labels.
>>
>> Signed-off-by: David Ahern <dsa@cumulusnetworks.com>
>> ---
>> include/utils.h | 8 ++++----
>> lib/utils.c | 2 +-
>> 2 files changed, 5 insertions(+), 5 deletions(-)
>>
>> diff --git a/include/utils.h b/include/utils.h
>> index 8c12e1e2a60c..a69e176c260d 100644
>> --- a/include/utils.h
>> +++ b/include/utils.h
>> @@ -54,6 +54,9 @@ void incomplete_command(void) __attribute__((noreturn));
>> #define NEXT_ARG_FWD() do { argv++; argc--; } while(0)
>> #define PREV_ARG() do { argv--; argc++; } while(0)
>>
>> +/* Maximum number of labels the mpls helpers support */
>> +#define MPLS_MAX_LABELS 16
>> +
>
> Why is the kernel limit not in include/uapi/ header file?
>
I believe Eric had reasons, but not sure why.
^ permalink raw reply
* Re: [PATCH net-next] samples/bpf: Add support for SKB_MODE to xdp1 and xdp_tx_iptunnel
From: David Ahern @ 2017-04-30 23:46 UTC (permalink / raw)
To: Jesper Dangaard Brouer; +Cc: netdev, ast, daniel
In-Reply-To: <20170428234035.5f0beec6@redhat.com>
On 4/28/17 3:40 PM, Jesper Dangaard Brouer wrote:
> [...]
>> diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c
>> index 0d449d8032d1..d4433a47e6c3 100644
>> --- a/samples/bpf/bpf_load.c
>> +++ b/samples/bpf/bpf_load.c
>> @@ -563,7 +563,7 @@ struct ksym *ksym_search(long key)
>> return &syms[0];
>> }
>>
>> -int set_link_xdp_fd(int ifindex, int fd)
>> +int set_link_xdp_fd(int ifindex, int fd, int flags)
> Shouldn't the flags be a unsigned int, actually a __u32 ?
>
sure. I'll send a patch
^ permalink raw reply
* Re: [PATCH] net: phy: Allow BCM5481x PHYs to setup internal TX/RX clock delay
From: Florian Fainelli @ 2017-05-01 0:53 UTC (permalink / raw)
To: Abhishek Shah
Cc: netdev, bcm-kernel-feedback-list, linux-kernel, linux-arm-kernel,
Andrew Lunn
In-Reply-To: <1493530461-11935-1-git-send-email-abhishek.shah@broadcom.com>
On 04/29/2017 10:34 PM, Abhishek Shah wrote:
> This patch allows users to enable/disable internal TX and/or RX
> clock delay for BCM5481x series PHYs so as to satisfy RGMII timing
> specifications.
>
> On a particular platform, whether TX and/or RX clock delay is required
> depends on how PHY connected to the MAC IP. This requirement can be
> specified through "phy-mode" property in the platform device tree.
>
> Signed-off-by: Abhishek Shah <abhishek.shah@broadcom.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
> ---
> drivers/net/phy/broadcom.c | 69 ++++++++++++++++++++++------------------------
> 1 file changed, 33 insertions(+), 36 deletions(-)
>
> diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
> index 9cd8b27..a32dc5d 100644
> --- a/drivers/net/phy/broadcom.c
> +++ b/drivers/net/phy/broadcom.c
> @@ -74,27 +74,40 @@ static int bcm54612e_config_init(struct phy_device *phydev)
> return 0;
> }
>
> -static int bcm54810_config(struct phy_device *phydev)
> +static int bcm5481x_config(struct phy_device *phydev)
> {
> int rc, val;
>
> - val = bcm_phy_read_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
> - val &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
> - rc = bcm_phy_write_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
> - val);
> - if (rc < 0)
> - return rc;
> -
> + /* handling PHY's internal RX clock delay */
> val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
> - val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
> val |= MII_BCM54XX_AUXCTL_MISC_WREN;
> + if (phydev->interface == PHY_INTERFACE_MODE_RGMII ||
> + phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
> + /* Disable RGMII RXC-RXD skew */
> + val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
> + }
> + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
> + phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
> + /* Enable RGMII RXC-RXD skew */
> + val |= MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
> + }
> rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
> val);
> if (rc < 0)
> return rc;
>
> + /* handling PHY's internal TX clock delay */
> val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL);
> - val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN;
> + if (phydev->interface == PHY_INTERFACE_MODE_RGMII ||
> + phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
> + /* Disable internal TX clock delay */
> + val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN;
> + }
> + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
> + phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
> + /* Enable internal TX clock delay */
> + val |= BCM54810_SHD_CLK_CTL_GTXCLK_EN;
> + }
> rc = bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val);
> if (rc < 0)
> return rc;
> @@ -244,7 +257,7 @@ static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
>
> static int bcm54xx_config_init(struct phy_device *phydev)
> {
> - int reg, err;
> + int reg, err, val;
>
> reg = phy_read(phydev, MII_BCM54XX_ECR);
> if (reg < 0)
> @@ -283,8 +296,14 @@ static int bcm54xx_config_init(struct phy_device *phydev)
> if (err)
> return err;
> } else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810) {
> - err = bcm54810_config(phydev);
> - if (err)
> + /* For BCM54810, we need to disable BroadR-Reach function */
> + val = bcm_phy_read_exp(phydev,
> + BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
> + val &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
> + err = bcm_phy_write_exp(phydev,
> + BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
> + val);
> + if (err < 0)
> return err;
> }
>
> @@ -392,29 +411,7 @@ static int bcm5481_config_aneg(struct phy_device *phydev)
> ret = genphy_config_aneg(phydev);
>
> /* Then we can set up the delay. */
> - if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
> - u16 reg;
> -
> - /*
> - * There is no BCM5481 specification available, so down
> - * here is everything we know about "register 0x18". This
> - * at least helps BCM5481 to successfully receive packets
> - * on MPC8360E-RDK board. Peter Barada <peterb@logicpd.com>
> - * says: "This sets delay between the RXD and RXC signals
> - * instead of using trace lengths to achieve timing".
> - */
> -
> - /* Set RDX clk delay. */
> - reg = 0x7 | (0x7 << 12);
> - phy_write(phydev, 0x18, reg);
> -
> - reg = phy_read(phydev, 0x18);
> - /* Set RDX-RXC skew. */
> - reg |= (1 << 8);
> - /* Write bits 14:0. */
> - reg |= (1 << 15);
> - phy_write(phydev, 0x18, reg);
> - }
> + bcm5481x_config(phydev);
>
> if (of_property_read_bool(np, "enet-phy-lane-swap")) {
> /* Lane Swap - Undocumented register...magic! */
>
--
Florian
^ permalink raw reply
* [PATCH net-next] bpf, arm64: implement jiting of BPF_XADD
From: Daniel Borkmann @ 2017-05-01 0:57 UTC (permalink / raw)
To: davem; +Cc: ast, zlim.lnx, netdev, linux-arm-kernel, Daniel Borkmann
This work adds BPF_XADD for BPF_W/BPF_DW to the arm64 JIT and therefore
completes JITing of all BPF instructions, meaning we can thus also remove
the 'notyet' label and do not need to fall back to the interpreter when
BPF_XADD is used in a program!
This now also brings arm64 JIT in line with x86_64, s390x, ppc64, sparc64,
where all current eBPF features are supported.
BPF_W example from test_bpf:
.u.insns_int = {
BPF_ALU32_IMM(BPF_MOV, R0, 0x12),
BPF_ST_MEM(BPF_W, R10, -40, 0x10),
BPF_STX_XADD(BPF_W, R10, R0, -40),
BPF_LDX_MEM(BPF_W, R0, R10, -40),
BPF_EXIT_INSN(),
},
[...]
00000020: 52800247 mov w7, #0x12 // #18
00000024: 928004eb mov x11, #0xffffffffffffffd8 // #-40
00000028: d280020a mov x10, #0x10 // #16
0000002c: b82b6b2a str w10, [x25,x11]
// start of xadd mapping:
00000030: 928004ea mov x10, #0xffffffffffffffd8 // #-40
00000034: 8b19014a add x10, x10, x25
00000038: f9800151 prfm pstl1strm, [x10]
0000003c: 885f7d4b ldxr w11, [x10]
00000040: 0b07016b add w11, w11, w7
00000044: 880b7d4b stxr w11, w11, [x10]
00000048: 35ffffab cbnz w11, 0x0000003c
// end of xadd mapping:
[...]
BPF_DW example from test_bpf:
.u.insns_int = {
BPF_ALU32_IMM(BPF_MOV, R0, 0x12),
BPF_ST_MEM(BPF_DW, R10, -40, 0x10),
BPF_STX_XADD(BPF_DW, R10, R0, -40),
BPF_LDX_MEM(BPF_DW, R0, R10, -40),
BPF_EXIT_INSN(),
},
[...]
00000020: 52800247 mov w7, #0x12 // #18
00000024: 928004eb mov x11, #0xffffffffffffffd8 // #-40
00000028: d280020a mov x10, #0x10 // #16
0000002c: f82b6b2a str x10, [x25,x11]
// start of xadd mapping:
00000030: 928004ea mov x10, #0xffffffffffffffd8 // #-40
00000034: 8b19014a add x10, x10, x25
00000038: f9800151 prfm pstl1strm, [x10]
0000003c: c85f7d4b ldxr x11, [x10]
00000040: 8b07016b add x11, x11, x7
00000044: c80b7d4b stxr w11, x11, [x10]
00000048: 35ffffab cbnz w11, 0x0000003c
// end of xadd mapping:
[...]
Tested on Cavium ThunderX ARMv8, test suite results after the patch:
No JIT: [ 3751.855362] test_bpf: Summary: 311 PASSED, 0 FAILED, [0/303 JIT'ed]
With JIT: [ 3573.759527] test_bpf: Summary: 311 PASSED, 0 FAILED, [303/303 JIT'ed]
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Alexei Starovoitov <ast@kernel.org>
---
( Based against net-next where BPF related patches are usually
routed, if something else is preferred please let me know. )
arch/arm64/include/asm/insn.h | 30 ++++++++++++
arch/arm64/kernel/insn.c | 106 ++++++++++++++++++++++++++++++++++++++++++
arch/arm64/net/bpf_jit.h | 19 ++++++++
arch/arm64/net/bpf_jit_comp.c | 16 +++++--
lib/test_bpf.c | 105 +++++++++++++++++++++++++++++++++++++++++
5 files changed, 271 insertions(+), 5 deletions(-)
diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h
index aecc07e..29cb2ca 100644
--- a/arch/arm64/include/asm/insn.h
+++ b/arch/arm64/include/asm/insn.h
@@ -80,6 +80,7 @@ enum aarch64_insn_register_type {
AARCH64_INSN_REGTYPE_RM,
AARCH64_INSN_REGTYPE_RD,
AARCH64_INSN_REGTYPE_RA,
+ AARCH64_INSN_REGTYPE_RS,
};
enum aarch64_insn_register {
@@ -188,6 +189,8 @@ enum aarch64_insn_ldst_type {
AARCH64_INSN_LDST_STORE_PAIR_PRE_INDEX,
AARCH64_INSN_LDST_LOAD_PAIR_POST_INDEX,
AARCH64_INSN_LDST_STORE_PAIR_POST_INDEX,
+ AARCH64_INSN_LDST_LOAD_EX,
+ AARCH64_INSN_LDST_STORE_EX,
};
enum aarch64_insn_adsb_type {
@@ -240,6 +243,23 @@ enum aarch64_insn_logic_type {
AARCH64_INSN_LOGIC_BIC_SETFLAGS
};
+enum aarch64_insn_prfm_type {
+ AARCH64_INSN_PRFM_TYPE_PLD,
+ AARCH64_INSN_PRFM_TYPE_PLI,
+ AARCH64_INSN_PRFM_TYPE_PST,
+};
+
+enum aarch64_insn_prfm_target {
+ AARCH64_INSN_PRFM_TARGET_L1,
+ AARCH64_INSN_PRFM_TARGET_L2,
+ AARCH64_INSN_PRFM_TARGET_L3,
+};
+
+enum aarch64_insn_prfm_policy {
+ AARCH64_INSN_PRFM_POLICY_KEEP,
+ AARCH64_INSN_PRFM_POLICY_STRM,
+};
+
#define __AARCH64_INSN_FUNCS(abbr, mask, val) \
static __always_inline bool aarch64_insn_is_##abbr(u32 code) \
{ return (code & (mask)) == (val); } \
@@ -248,6 +268,7 @@ enum aarch64_insn_logic_type {
__AARCH64_INSN_FUNCS(adr, 0x9F000000, 0x10000000)
__AARCH64_INSN_FUNCS(adrp, 0x9F000000, 0x90000000)
+__AARCH64_INSN_FUNCS(prfm, 0x3FC00000, 0x39800000)
__AARCH64_INSN_FUNCS(prfm_lit, 0xFF000000, 0xD8000000)
__AARCH64_INSN_FUNCS(str_reg, 0x3FE0EC00, 0x38206800)
__AARCH64_INSN_FUNCS(ldr_reg, 0x3FE0EC00, 0x38606800)
@@ -357,6 +378,11 @@ u32 aarch64_insn_gen_load_store_pair(enum aarch64_insn_register reg1,
int offset,
enum aarch64_insn_variant variant,
enum aarch64_insn_ldst_type type);
+u32 aarch64_insn_gen_load_store_ex(enum aarch64_insn_register reg,
+ enum aarch64_insn_register base,
+ enum aarch64_insn_register state,
+ enum aarch64_insn_size_type size,
+ enum aarch64_insn_ldst_type type);
u32 aarch64_insn_gen_add_sub_imm(enum aarch64_insn_register dst,
enum aarch64_insn_register src,
int imm, enum aarch64_insn_variant variant,
@@ -397,6 +423,10 @@ u32 aarch64_insn_gen_logical_shifted_reg(enum aarch64_insn_register dst,
int shift,
enum aarch64_insn_variant variant,
enum aarch64_insn_logic_type type);
+u32 aarch64_insn_gen_prefetch(enum aarch64_insn_register base,
+ enum aarch64_insn_prfm_type type,
+ enum aarch64_insn_prfm_target target,
+ enum aarch64_insn_prfm_policy policy);
s32 aarch64_get_branch_offset(u32 insn);
u32 aarch64_set_branch_offset(u32 insn, s32 offset);
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
index 3a63954..b884a92 100644
--- a/arch/arm64/kernel/insn.c
+++ b/arch/arm64/kernel/insn.c
@@ -474,6 +474,7 @@ static u32 aarch64_insn_encode_register(enum aarch64_insn_register_type type,
shift = 10;
break;
case AARCH64_INSN_REGTYPE_RM:
+ case AARCH64_INSN_REGTYPE_RS:
shift = 16;
break;
default:
@@ -757,6 +758,111 @@ u32 aarch64_insn_gen_load_store_pair(enum aarch64_insn_register reg1,
offset >> shift);
}
+u32 aarch64_insn_gen_load_store_ex(enum aarch64_insn_register reg,
+ enum aarch64_insn_register base,
+ enum aarch64_insn_register state,
+ enum aarch64_insn_size_type size,
+ enum aarch64_insn_ldst_type type)
+{
+ u32 insn;
+
+ switch (type) {
+ case AARCH64_INSN_LDST_LOAD_EX:
+ insn = aarch64_insn_get_load_ex_value();
+ break;
+ case AARCH64_INSN_LDST_STORE_EX:
+ insn = aarch64_insn_get_store_ex_value();
+ break;
+ default:
+ pr_err("%s: unknown load/store exclusive encoding %d\n", __func__, type);
+ return AARCH64_BREAK_FAULT;
+ }
+
+ insn = aarch64_insn_encode_ldst_size(size, insn);
+
+ insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT, insn,
+ reg);
+
+ insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn,
+ base);
+
+ insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT2, insn,
+ AARCH64_INSN_REG_ZR);
+
+ return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RS, insn,
+ state);
+}
+
+static u32 aarch64_insn_encode_prfm_imm(enum aarch64_insn_prfm_type type,
+ enum aarch64_insn_prfm_target target,
+ enum aarch64_insn_prfm_policy policy,
+ u32 insn)
+{
+ u32 imm_type = 0, imm_target = 0, imm_policy = 0;
+
+ switch (type) {
+ case AARCH64_INSN_PRFM_TYPE_PLD:
+ break;
+ case AARCH64_INSN_PRFM_TYPE_PLI:
+ imm_type = BIT(0);
+ break;
+ case AARCH64_INSN_PRFM_TYPE_PST:
+ imm_type = BIT(1);
+ break;
+ default:
+ pr_err("%s: unknown prfm type encoding %d\n", __func__, type);
+ return AARCH64_BREAK_FAULT;
+ }
+
+ switch (target) {
+ case AARCH64_INSN_PRFM_TARGET_L1:
+ break;
+ case AARCH64_INSN_PRFM_TARGET_L2:
+ imm_target = BIT(0);
+ break;
+ case AARCH64_INSN_PRFM_TARGET_L3:
+ imm_target = BIT(1);
+ break;
+ default:
+ pr_err("%s: unknown prfm target encoding %d\n", __func__, target);
+ return AARCH64_BREAK_FAULT;
+ }
+
+ switch (policy) {
+ case AARCH64_INSN_PRFM_POLICY_KEEP:
+ break;
+ case AARCH64_INSN_PRFM_POLICY_STRM:
+ imm_policy = BIT(0);
+ break;
+ default:
+ pr_err("%s: unknown prfm policy encoding %d\n", __func__, policy);
+ return AARCH64_BREAK_FAULT;
+ }
+
+ /* In this case, imm5 is encoded into Rt field. */
+ insn &= ~GENMASK(4, 0);
+ insn |= imm_policy | (imm_target << 1) | (imm_type << 3);
+
+ return insn;
+}
+
+u32 aarch64_insn_gen_prefetch(enum aarch64_insn_register base,
+ enum aarch64_insn_prfm_type type,
+ enum aarch64_insn_prfm_target target,
+ enum aarch64_insn_prfm_policy policy)
+{
+ u32 insn = aarch64_insn_get_prfm_value();
+
+ insn = aarch64_insn_encode_ldst_size(AARCH64_INSN_SIZE_64, insn);
+
+ insn = aarch64_insn_encode_prfm_imm(type, target, policy, insn);
+
+ insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn,
+ base);
+
+ return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_12, insn, 0);
+}
+
u32 aarch64_insn_gen_add_sub_imm(enum aarch64_insn_register dst,
enum aarch64_insn_register src,
int imm, enum aarch64_insn_variant variant,
diff --git a/arch/arm64/net/bpf_jit.h b/arch/arm64/net/bpf_jit.h
index 7c16e54..b02a926 100644
--- a/arch/arm64/net/bpf_jit.h
+++ b/arch/arm64/net/bpf_jit.h
@@ -83,6 +83,25 @@
/* Rt = Rn[0]; Rt2 = Rn[8]; Rn += 16; */
#define A64_POP(Rt, Rt2, Rn) A64_LS_PAIR(Rt, Rt2, Rn, 16, LOAD, POST_INDEX)
+/* Load/store exclusive */
+#define A64_SIZE(sf) \
+ ((sf) ? AARCH64_INSN_SIZE_64 : AARCH64_INSN_SIZE_32)
+#define A64_LSX(sf, Rt, Rn, Rs, type) \
+ aarch64_insn_gen_load_store_ex(Rt, Rn, Rs, A64_SIZE(sf), \
+ AARCH64_INSN_LDST_##type)
+/* Rt = [Rn]; (atomic) */
+#define A64_LDXR(sf, Rt, Rn) \
+ A64_LSX(sf, Rt, Rn, A64_ZR, LOAD_EX)
+/* [Rn] = Rt; (atomic) Rs = [state] */
+#define A64_STXR(sf, Rt, Rn, Rs) \
+ A64_LSX(sf, Rt, Rn, Rs, STORE_EX)
+
+/* Prefetch */
+#define A64_PRFM(Rn, type, target, policy) \
+ aarch64_insn_gen_prefetch(Rn, AARCH64_INSN_PRFM_TYPE_##type, \
+ AARCH64_INSN_PRFM_TARGET_##target, \
+ AARCH64_INSN_PRFM_POLICY_##policy)
+
/* Add/subtract (immediate) */
#define A64_ADDSUB_IMM(sf, Rd, Rn, imm12, type) \
aarch64_insn_gen_add_sub_imm(Rd, Rn, imm12, \
diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
index 3047368..4f2b351 100644
--- a/arch/arm64/net/bpf_jit_comp.c
+++ b/arch/arm64/net/bpf_jit_comp.c
@@ -321,6 +321,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
const s32 imm = insn->imm;
const int i = insn - ctx->prog->insnsi;
const bool is64 = BPF_CLASS(code) == BPF_ALU64;
+ const bool isdw = BPF_SIZE(code) == BPF_DW;
u8 jmp_cond;
s32 jmp_offset;
@@ -681,7 +682,16 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
case BPF_STX | BPF_XADD | BPF_W:
/* STX XADD: lock *(u64 *)(dst + off) += src */
case BPF_STX | BPF_XADD | BPF_DW:
- goto notyet;
+ emit_a64_mov_i(1, tmp, off, ctx);
+ emit(A64_ADD(1, tmp, tmp, dst), ctx);
+ emit(A64_PRFM(tmp, PST, L1, STRM), ctx);
+ emit(A64_LDXR(isdw, tmp2, tmp), ctx);
+ emit(A64_ADD(isdw, tmp2, tmp2, src), ctx);
+ emit(A64_STXR(isdw, tmp2, tmp, tmp2), ctx);
+ jmp_offset = -3;
+ check_imm19(jmp_offset);
+ emit(A64_CBNZ(0, tmp2, jmp_offset), ctx);
+ break;
/* R0 = ntohx(*(size *)(((struct sk_buff *)R6)->data + imm)) */
case BPF_LD | BPF_ABS | BPF_W:
@@ -748,10 +758,6 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
}
break;
}
-notyet:
- pr_info_once("*** NOT YET: opcode %02x ***\n", code);
- return -EFAULT;
-
default:
pr_err_once("unknown opcode %02x\n", code);
return -EINVAL;
diff --git a/lib/test_bpf.c b/lib/test_bpf.c
index 0362da0..3a7730c 100644
--- a/lib/test_bpf.c
+++ b/lib/test_bpf.c
@@ -434,6 +434,41 @@ static int bpf_fill_ld_abs_vlan_push_pop(struct bpf_test *self)
return 0;
}
+static int __bpf_fill_stxdw(struct bpf_test *self, int size)
+{
+ unsigned int len = BPF_MAXINSNS;
+ struct bpf_insn *insn;
+ int i;
+
+ insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL);
+ if (!insn)
+ return -ENOMEM;
+
+ insn[0] = BPF_ALU32_IMM(BPF_MOV, R0, 1);
+ insn[1] = BPF_ST_MEM(size, R10, -40, 42);
+
+ for (i = 2; i < len - 2; i++)
+ insn[i] = BPF_STX_XADD(size, R10, R0, -40);
+
+ insn[len - 2] = BPF_LDX_MEM(size, R0, R10, -40);
+ insn[len - 1] = BPF_EXIT_INSN();
+
+ self->u.ptr.insns = insn;
+ self->u.ptr.len = len;
+
+ return 0;
+}
+
+static int bpf_fill_stxw(struct bpf_test *self)
+{
+ return __bpf_fill_stxdw(self, BPF_W);
+}
+
+static int bpf_fill_stxdw(struct bpf_test *self)
+{
+ return __bpf_fill_stxdw(self, BPF_DW);
+}
+
static struct bpf_test tests[] = {
{
"TAX",
@@ -4303,6 +4338,41 @@ static int bpf_fill_ld_abs_vlan_push_pop(struct bpf_test *self)
{ { 0, 0x22 } },
},
{
+ "STX_XADD_W: Test side-effects, r10: 0x12 + 0x10 = 0x22",
+ .u.insns_int = {
+ BPF_ALU64_REG(BPF_MOV, R1, R10),
+ BPF_ALU32_IMM(BPF_MOV, R0, 0x12),
+ BPF_ST_MEM(BPF_W, R10, -40, 0x10),
+ BPF_STX_XADD(BPF_W, R10, R0, -40),
+ BPF_ALU64_REG(BPF_MOV, R0, R10),
+ BPF_ALU64_REG(BPF_SUB, R0, R1),
+ BPF_EXIT_INSN(),
+ },
+ INTERNAL,
+ { },
+ { { 0, 0 } },
+ },
+ {
+ "STX_XADD_W: Test side-effects, r0: 0x12 + 0x10 = 0x22",
+ .u.insns_int = {
+ BPF_ALU32_IMM(BPF_MOV, R0, 0x12),
+ BPF_ST_MEM(BPF_W, R10, -40, 0x10),
+ BPF_STX_XADD(BPF_W, R10, R0, -40),
+ BPF_EXIT_INSN(),
+ },
+ INTERNAL,
+ { },
+ { { 0, 0x12 } },
+ },
+ {
+ "STX_XADD_W: X + 1 + 1 + 1 + ...",
+ { },
+ INTERNAL,
+ { },
+ { { 0, 4134 } },
+ .fill_helper = bpf_fill_stxw,
+ },
+ {
"STX_XADD_DW: Test: 0x12 + 0x10 = 0x22",
.u.insns_int = {
BPF_ALU32_IMM(BPF_MOV, R0, 0x12),
@@ -4315,6 +4385,41 @@ static int bpf_fill_ld_abs_vlan_push_pop(struct bpf_test *self)
{ },
{ { 0, 0x22 } },
},
+ {
+ "STX_XADD_DW: Test side-effects, r10: 0x12 + 0x10 = 0x22",
+ .u.insns_int = {
+ BPF_ALU64_REG(BPF_MOV, R1, R10),
+ BPF_ALU32_IMM(BPF_MOV, R0, 0x12),
+ BPF_ST_MEM(BPF_DW, R10, -40, 0x10),
+ BPF_STX_XADD(BPF_DW, R10, R0, -40),
+ BPF_ALU64_REG(BPF_MOV, R0, R10),
+ BPF_ALU64_REG(BPF_SUB, R0, R1),
+ BPF_EXIT_INSN(),
+ },
+ INTERNAL,
+ { },
+ { { 0, 0 } },
+ },
+ {
+ "STX_XADD_DW: Test side-effects, r0: 0x12 + 0x10 = 0x22",
+ .u.insns_int = {
+ BPF_ALU32_IMM(BPF_MOV, R0, 0x12),
+ BPF_ST_MEM(BPF_DW, R10, -40, 0x10),
+ BPF_STX_XADD(BPF_DW, R10, R0, -40),
+ BPF_EXIT_INSN(),
+ },
+ INTERNAL,
+ { },
+ { { 0, 0x12 } },
+ },
+ {
+ "STX_XADD_DW: X + 1 + 1 + 1 + ...",
+ { },
+ INTERNAL,
+ { },
+ { { 0, 4134 } },
+ .fill_helper = bpf_fill_stxdw,
+ },
/* BPF_JMP | BPF_EXIT */
{
"JMP_EXIT",
--
1.9.3
^ permalink raw reply related
* Re: [PATCH] net: macb: fix phy interrupt parsing
From: David Miller @ 2017-05-01 2:22 UTC (permalink / raw)
To: alexandre.belloni; +Cc: nicolas.ferre, bfolta, netdev, linux-kernel
In-Reply-To: <20170426100628.14493-1-alexandre.belloni@free-electrons.com>
From: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Date: Wed, 26 Apr 2017 12:06:28 +0200
> Since 83a77e9ec415, the phydev irq is explicitly set to PHY_POLL when
> there is no pdata. It doesn't work on DT enabled platforms because the
> phydev irq is already set by libphy before.
>
> Fixes: 83a77e9ec415 ("net: macb: Added PCI wrapper for Platform Driver.")
> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Applied and queued up for -stable, thanks.
^ permalink raw reply
* Re: [PATCH net-next] bpf: restore skb->sk before pskb_trim() call
From: David Miller @ 2017-05-01 2:23 UTC (permalink / raw)
To: eric.dumazet; +Cc: netdev, andreyknvl, willemb
In-Reply-To: <1493222963.6453.77.camel@edumazet-glaptop3.roam.corp.google.com>
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Wed, 26 Apr 2017 09:09:23 -0700
> From: Eric Dumazet <edumazet@google.com>
>
> While testing a fix [1] in ___pskb_trim(), addressing the WARN_ON_ONCE()
> in skb_try_coalesce() reported by Andrey, I found that we had an skb
> with skb->sk set but no skb->destructor.
>
> This invalidated heuristic found in commit 158f323b9868 ("net: adjust
> skb->truesize in pskb_expand_head()") and in cited patch.
>
> Considering the BUG_ON(skb->sk) we have in skb_orphan(), we should
> restrain the temporary setting to a minimal section.
>
> [1] https://patchwork.ozlabs.org/patch/755570/
> net: adjust skb->truesize in ___pskb_trim()
>
> Fixes: 8f917bba0042 ("bpf: pass sk to helper functions")
> Signed-off-by: Eric Dumazet <edumazet@google.com>
Applied, thanks Eric.
^ permalink raw reply
* Re: [PATCH net] tcp: fix access to sk->sk_state in tcp_poll()
From: David Miller @ 2017-05-01 2:25 UTC (permalink / raw)
To: dcaratti; +Cc: kuznet, jmorris, yoshfuji, kaber, weiwan, netdev
In-Reply-To: <0a1710138c3e55c388a52dba817b2d1b1996c899.1493226034.git.dcaratti@redhat.com>
From: Davide Caratti <dcaratti@redhat.com>
Date: Wed, 26 Apr 2017 19:07:35 +0200
> avoid direct access to sk->sk_state when tcp_poll() is called on a socket
> using active TCP fastopen with deferred connect. Use local variable
> 'state', which stores the result of sk_state_load(), like it was done in
> commit 00fd38d938db ("tcp: ensure proper barriers in lockless contexts").
>
> Fixes: 19f6d3f3c842 ("net/tcp-fastopen: Add new API support")
> Signed-off-by: Davide Caratti <dcaratti@redhat.com>
Applied.
^ permalink raw reply
* Re: [PATCH net-next] Fix inaccurate helper function description
From: David Miller @ 2017-05-01 2:25 UTC (permalink / raw)
To: chenbofeng.kernel; +Cc: netdev, mic, fengc
In-Reply-To: <1493250083-1954-1-git-send-email-chenbofeng.kernel@gmail.com>
From: Chenbo Feng <chenbofeng.kernel@gmail.com>
Date: Wed, 26 Apr 2017 16:41:23 -0700
> From: Chenbo Feng <fengc@google.com>
>
> The description inside uapi/linux/bpf.h about bpf_get_socket_uid
> helper function is no longer valid. It returns overflowuid rather
> than 0 when failed.
>
> Signed-off-by: Chenbo Feng <fengc@google.com>
Applied.
^ permalink raw reply
* Re: pull-request: can-next 2017-04-25,pull-request: can-next 2017-04-25
From: David Miller @ 2017-05-01 2:26 UTC (permalink / raw)
To: mkl; +Cc: netdev, kernel, linux-can
In-Reply-To: <17d73df9-8f7a-1458-c4f8-e8153be206d5@pengutronix.de>
From: Marc Kleine-Budde <mkl@pengutronix.de>
Date: Thu, 27 Apr 2017 09:54:33 +0200
> this is a pull request of 1 patch for net-next/master.
>
> This patch by Oliver Hartkopp fixes the build of the broad cast manager
> with CONFIG_PROC_FS disabled.
Pulled, thanks!
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox