diff --git a/README.md b/README.md
new file mode 100644
index 0000000..715496a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,27 @@
+# eBPF Standard Documentation
+
+This repository is a working draft of standard eBPF documentation
+to be published by the eBPF Foundation in PDF format.
+
+The authoritative source from which it is built is expected to be
+in the Linux kernel.org repository, but not be Linux specific.
+
+A GitHub mirror should be used, as is presently done for libbpf and
+bpftool, so that other platforms and tools can easily use it.
+As such, the documentation uses the subset of RST that GitHub
+renders correctly.
+
+The documentation can be IETF RFC style MUST/SHOULD/MAY language
+if desired.  It does not currently do so.
+
+## Questions
+
+1. Any objections to the github mirror approach?
+
+2. Should we include or exclude Linux implementation notes
+   and Clang implementation notes?
+
+3. How do we handle the legacy packet instructions?
+
+4. How do we handle the wide instructions that reference
+   map fd, map indices, BTF ids, and BPF callbacks?
diff --git a/isa/README.md b/isa/README.md
index 98c49da..60cc347 100644
--- a/isa/README.md
+++ b/isa/README.md
@@ -8,6 +8,8 @@ Some documentation links include:
* https://www.kernel.org/doc/Documentation/networking/filter.txt
* https://pchaigno.github.io/bpf/2021/10/20/ebpf-instruction-sets.html
* https://www.kernel.org/doc/html/latest/bpf/bpf_design_QA.html#instruction-level-questions
+* https://lore.kernel.org/bpf/8DA9E260-AE56-4B21-90BF-CF0049CFD04D@intel.com/
+* https://github.com/iovisor/bpf-docs/pull/26/files

 Some implementation links include:

diff --git a/isa/kernel.org/instruction-set.rst b/isa/kernel.org/instruction-set.rst
index 1b0e671..7f8ee00 100644
--- a/isa/kernel.org/instruction-set.rst
+++ b/isa/kernel.org/instruction-set.rst
@@ -1,8 +1,24 @@
+.. contents::
+.. sectnum::

 ====================
eBPF Instruction Set
====================

+The eBPF instruction set consists of eleven 64 bit registers, a program counter,
+and 512 bytes of stack space.
+
+Versions
+========
+
+The current Instruction Set Architecture (ISA) version, sometimes referred to in other documents
+as a "CPU" version, is 3.  This document also covers older versions of the ISA.
+
+   **Note**
+
+   *Clang implementation*: Clang can select the eBPF ISA version using
+   ``-mcpu=v2`` for example to select version 2.
+
Registers and calling convention
================================

@@ -11,198 +27,331 @@ all of which are 64-bits wide.

 The eBPF calling convention is defined as:

- * R0: return value from function calls, and exit value for eBPF programs
- * R1 - R5: arguments for function calls
- * R6 - R9: callee saved registers that function calls will preserve
- * R10: read-only frame pointer to access stack
+* R0: return value from function calls, and exit value for eBPF programs
+* R1 - R5: arguments for function calls
+* R6 - R9: callee saved registers that function calls will preserve
+* R10: read-only frame pointer to access stack
+
+Registers R0 - R5 are scratch registers, meaning the BPF program needs to either
+spill them to the BPF stack or move them to callee saved registers if these
+arguments are to be reused across multiple function calls. Spilling means
+that the value in the register is moved to the BPF stack. The reverse operation
+of moving the variable from the BPF stack to the register is called filling.
+The reason for spilling/filling is due to the limited number of registers.

-R0 - R5 are scratch registers and eBPF programs needs to spill/fill them if
-necessary across calls.
+   **Note**
+
+   *Linux implementation*: In the Linux kernel, the exit value for eBPF
+   programs is passed as a 32 bit value.
+
+Upon entering execution of an eBPF program, registers R1 - R5 initially can contain
+the input arguments for the program (similar to the argc/argv pair for a typical C program).
+The actual number of registers used, and their meaning, is defined by the program type;
+for example, a networking program might have an argument that includes network packet data
+and/or metadata.
+
+   **Note**
+
+   *Linux implementation*: In the Linux kernel, all program types only use
+   R1 which contains the "context", which is typically a structure containing all
+   the inputs needed.  
 
 Instruction encoding
====================

+An eBPF program is a sequence of instructions.
+
eBPF has two instruction encodings:

- * the basic instruction encoding, which uses 64 bits to encode an instruction
- * the wide instruction encoding, which appends a second 64-bit immediate value
-   (imm64) after the basic instruction for a total of 128 bits.
+* the basic instruction encoding, which uses 64 bits to encode an instruction
+* the wide instruction encoding, which appends a second 64-bit immediate (i.e.,
+  constant) value after the basic instruction for a total of 128 bits.
+
+The basic instruction encoding is as follows:

-The basic instruction encoding looks as follows:
+=============  =======  ===============  ====================  ============
+32 bits (MSB)  16 bits  4 bits           4 bits                8 bits (LSB)
+=============  =======  ===============  ====================  ============
+imm            offset   src              dst                   opcode
+=============  =======  ===============  ====================  ============

- =============  =======  ===============  ====================  ============
- 32 bits (MSB)  16 bits  4 bits           4 bits                8 bits (LSB)
- =============  =======  ===============  ====================  ============
- immediate      offset   source register  destination register  opcode
- =============  =======  ===============  ====================  ============
+imm         
+  integer immediate value
+
+offset
+  signed integer offset used with pointer arithmetic
+
+src
+  source register number (0-10)
+
+dst
+  destination register number (0-10)
+
+opcode
+  operation to perform

 Note that most instructions do not use all of the fields.
-Unused fields shall be cleared to zero.
+Unused fields must be set to zero.
+
+As discussed below in `64-bit immediate instructions`_, some basic
+instructions denote that a 64-bit immediate value follows.  Thus
+the wide instruction encoding is as follows:
+
+=================  =============
+64 bits (MSB)      64 bits (LSB)
+=================  =============
+basic instruction  imm64
+=================  =============
+
+where MSB and LSB mean the most significant bits and least significant bits, respectively.
+
+In the remainder of this document 'src' and 'dst' refer to the values of the source
+and destination registers, respectively, rather than the register number.

 Instruction classes
-------------------

-The three LSB bits of the 'opcode' field store the instruction class:
-
-  =========  =====  ===============================
-  class      value  description
-  =========  =====  ===============================
-  BPF_LD     0x00   non-standard load operations
-  BPF_LDX    0x01   load into register operations
-  BPF_ST     0x02   store from immediate operations
-  BPF_STX    0x03   store from register operations
-  BPF_ALU    0x04   32-bit arithmetic operations
-  BPF_JMP    0x05   64-bit jump operations
-  BPF_JMP32  0x06   32-bit jump operations
-  BPF_ALU64  0x07   64-bit arithmetic operations
-  =========  =====  ===============================
+The encoding of the 'opcode' field varies and can be determined from
+the three least significant bits (LSB) of the 'opcode' field which holds
+the "instruction class", as follows:
+
+=========  =====  ===============================  =======  =================
+class      value  description                      version  reference
+=========  =====  ===============================  =======  =================
+BPF_LD     0x00   non-standard load operations     1        `Load and store instructions`_
+BPF_LDX    0x01   load into register operations    1        `Load and store instructions`_
+BPF_ST     0x02   store from immediate operations  1        `Load and store instructions`_
+BPF_STX    0x03   store from register operations   1        `Load and store instructions`_
+BPF_ALU    0x04   32-bit arithmetic operations     3        `Arithmetic and jump instructions`_
+BPF_JMP    0x05   64-bit jump operations           1        `Arithmetic and jump instructions`_
+BPF_JMP32  0x06   32-bit jump operations           3        `Arithmetic and jump instructions`_
+BPF_ALU64  0x07   64-bit arithmetic operations     1        `Arithmetic and jump instructions`_
+=========  =====  ===============================  =======  =================
+
+where 'version' indicates the first ISA version in which support for the value was mandatory.

 Arithmetic and jump instructions
================================

-For arithmetic and jump instructions (BPF_ALU, BPF_ALU64, BPF_JMP and
-BPF_JMP32), the 8-bit 'opcode' field is divided into three parts:
+For arithmetic and jump instructions (``BPF_ALU``, ``BPF_ALU64``, ``BPF_JMP`` and
+``BPF_JMP32``), the 8-bit 'opcode' field is divided into three parts:
+
+==============  ======  =================
+4 bits (MSB)    1 bit   3 bits (LSB)
+==============  ======  =================
+code            source  instruction class
+==============  ======  =================

-  ==============  ======  =================
-  4 bits (MSB)    1 bit   3 bits (LSB)
-  ==============  ======  =================
-  operation code  source  instruction class
-  ==============  ======  =================
+code
+  the operation code, whose meaning varies by instruction class

-The 4th bit encodes the source operand:
+source
+  the source operand location, which unless otherwise specified is one of:

   ======  =====  ========================================
   source  value  description
   ======  =====  ========================================
-  BPF_K   0x00   use 32-bit immediate as source operand
-  BPF_X   0x08   use 'src_reg' register as source operand
+  BPF_K   0x00   use 32-bit 'imm' value as source operand
+  BPF_X   0x08   use 'src' register value as source operand
   ======  =====  ========================================

-The four MSB bits store the operation code.
-
+instruction class
+  the instruction class (see `Instruction classes`_)

 Arithmetic instructions
-----------------------

-BPF_ALU uses 32-bit wide operands while BPF_ALU64 uses 64-bit wide operands for
+Instruction class ``BPF_ALU`` uses 32-bit wide operands (zeroing the upper 32 bits
+of the destination register) while ``BPF_ALU64`` uses 64-bit wide operands for
otherwise identical operations.
-The code field encodes the operation as below:

-  ========  =====  =================================================
-  code      value  description
-  ========  =====  =================================================
-  BPF_ADD   0x00   dst += src
-  BPF_SUB   0x10   dst -= src
-  BPF_MUL   0x20   dst \*= src
-  BPF_DIV   0x30   dst /= src
-  BPF_OR    0x40   dst \|= src
-  BPF_AND   0x50   dst &= src
-  BPF_LSH   0x60   dst <<= src
-  BPF_RSH   0x70   dst >>= src
-  BPF_NEG   0x80   dst = ~src
-  BPF_MOD   0x90   dst %= src
-  BPF_XOR   0xa0   dst ^= src
-  BPF_MOV   0xb0   dst = src
-  BPF_ARSH  0xc0   sign extending shift right
-  BPF_END   0xd0   byte swap operations (see separate section below)
-  ========  =====  =================================================
+Support for ``BPF_ALU`` is required in ISA version 3, and optional in earlier
+versions.
+
+   **Note**
+
+   *Clang implementation*:
+   For ISA versions prior to 3, Clang v7.0 and later can enable ``BPF_ALU`` support with
+   ``-Xclang -target-feature -Xclang +alu32``.
+
+The 4-bit 'code' field encodes the operation as follows:
+
+========  =====  =================================================
+code      value  description
+========  =====  =================================================
+BPF_ADD   0x00   dst += src
+BPF_SUB   0x10   dst -= src
+BPF_MUL   0x20   dst \*= src
+BPF_DIV   0x30   dst /= src
+BPF_OR    0x40   dst \|= src
+BPF_AND   0x50   dst &= src
+BPF_LSH   0x60   dst <<= src
+BPF_RSH   0x70   dst >>= src
+BPF_NEG   0x80   dst = ~src
+BPF_MOD   0x90   dst %= src
+BPF_XOR   0xa0   dst ^= src
+BPF_MOV   0xb0   dst = src
+BPF_ARSH  0xc0   sign extending shift right
+BPF_END   0xd0   byte swap operations (see `Byte swap instructions`_ below)
+========  =====  =================================================
+
+Underflow and overflow are allowed during arithmetic operations,
+meaning the 64-bit or 32-bit value will wrap.
+
+``BPF_DIV`` has an implicit program exit condition as well. If
+eBPF program execution would result in division by zero,
+program execution must be gracefully aborted.
+
+Examples:

-BPF_ADD | BPF_X | BPF_ALU means::
+``BPF_ADD | BPF_X | BPF_ALU`` (0x0c) means::

-  dst_reg = (u32) dst_reg + (u32) src_reg;
+  dst = (uint32_t) (dst + src);

-BPF_ADD | BPF_X | BPF_ALU64 means::
+where '(uint32_t)' indicates truncation to 32 bits.

-  dst_reg = dst_reg + src_reg
+   **Note**

-BPF_XOR | BPF_K | BPF_ALU means::
+   *Linux implementation*: In the Linux kernel, uint32_t is expressed as u32,
+   uint64_t is expressed as u64, etc.  This document uses the standard C terminology
+   as the cross-platform specification.

-  src_reg = (u32) src_reg ^ (u32) imm32
+``BPF_ADD | BPF_X | BPF_ALU64`` (0x0f) means::

-BPF_XOR | BPF_K | BPF_ALU64 means::
+  dst = dst + src

-  src_reg = src_reg ^ imm32
+``BPF_XOR | BPF_K | BPF_ALU`` (0xa4) means::
+
+  src = (uint32_t) src ^ (uint32_t) imm
+
+``BPF_XOR | BPF_K | BPF_ALU64`` (0xa7) means::
+
+  src = src ^ imm

 
 Byte swap instructions
-----------------------
+~~~~~~~~~~~~~~~~~~~~~~

 The byte swap instructions use an instruction class of ``BPF_ALU`` and a 4-bit
-code field of ``BPF_END``.
+'code' field of ``BPF_END``.

 The byte swap instructions operate on the destination register
only and do not use a separate source register or immediate value.

-The 1-bit source operand field in the opcode is used to to select what byte
-order the operation convert from or to:
+Byte swap instructions use non-default semantics of the 1-bit 'source' field in
+the 'opcode' field.  Instead of indicating the source operator, it is instead
+used to select what byte order the operation converts from or to:

-  =========  =====  =================================================
-  source     value  description
-  =========  =====  =================================================
-  BPF_TO_LE  0x00   convert between host byte order and little endian
-  BPF_TO_BE  0x08   convert between host byte order and big endian
-  =========  =====  =================================================
-
-The imm field encodes the width of the swap operations.  The following widths
-are supported: 16, 32 and 64.
-
-Examples:
+=========  =====  =================================================
+source     value  description
+=========  =====  =================================================
+BPF_TO_LE  0x00   convert between host byte order and little endian
+BPF_TO_BE  0x08   convert between host byte order and big endian
+=========  =====  =================================================

-``BPF_ALU | BPF_TO_LE | BPF_END`` with imm = 16 means::
+   **Note**

-  dst_reg = htole16(dst_reg)
+   *Linux implementation*:
+   ``BPF_FROM_LE`` and ``BPF_FROM_BE`` exist as aliases for ``BPF_TO_LE`` and
+   ``BPF_TO_BE`` respectively.

-``BPF_ALU | BPF_TO_BE | BPF_END`` with imm = 64 means::
+The 'imm' field encodes the width of the swap operations.  The following widths
+are supported: 16, 32 and 64. The following table summarizes the resulting
+possibilities:

-  dst_reg = htobe64(dst_reg)
+=============================  =========  ===  ========  ==================
+opcode construction            opcode     imm  mnemonic  pseudocode
+=============================  =========  ===  ========  ==================
+BPF_END | BPF_TO_LE | BPF_ALU  0xd4       16   le16 dst  dst = htole16(dst)
+BPF_END | BPF_TO_LE | BPF_ALU  0xd4       32   le32 dst  dst = htole32(dst)
+BPF_END | BPF_TO_LE | BPF_ALU  0xd4       64   le64 dst  dst = htole64(dst)
+BPF_END | BPF_TO_BE | BPF_ALU  0xdc       16   be16 dst  dst = htobe16(dst)
+BPF_END | BPF_TO_BE | BPF_ALU  0xdc       32   be32 dst  dst = htobe32(dst)
+BPF_END | BPF_TO_BE | BPF_ALU  0xdc       64   be64 dst  dst = htobe64(dst)
+=============================  =========  ===  ========  ==================

-``BPF_FROM_LE`` and ``BPF_FROM_BE`` exist as aliases for ``BPF_TO_LE`` and
-``BPF_TO_BE`` respectively.
+where

+* mnenomic indicates a short form that might be displayed by some tools such as disassemblers
+* 'htoleNN()' indicates converting a NN-bit value from host byte order to little-endian byte order
+* 'htobeNN()' indicates converting a NN-bit value from host byte order to big-endian byte order

 Jump instructions
-----------------

-BPF_JMP32 uses 32-bit wide operands while BPF_JMP uses 64-bit wide operands for
+Instruction class ``BPF_JMP32`` uses 32-bit wide operands while ``BPF_JMP`` uses 64-bit wide operands for
otherwise identical operations.
-The code field encodes the operation as below:
-
-  ========  =====  =========================  ============
-  code      value  description                notes
-  ========  =====  =========================  ============
-  BPF_JA    0x00   PC += off                  BPF_JMP only
-  BPF_JEQ   0x10   PC += off if dst == src
-  BPF_JGT   0x20   PC += off if dst > src     unsigned
-  BPF_JGE   0x30   PC += off if dst >= src    unsigned
-  BPF_JSET  0x40   PC += off if dst & src
-  BPF_JNE   0x50   PC += off if dst != src
-  BPF_JSGT  0x60   PC += off if dst > src     signed
-  BPF_JSGE  0x70   PC += off if dst >= src    signed
-  BPF_CALL  0x80   function call
-  BPF_EXIT  0x90   function / program return  BPF_JMP only
-  BPF_JLT   0xa0   PC += off if dst < src     unsigned
-  BPF_JLE   0xb0   PC += off if dst <= src    unsigned
-  BPF_JSLT  0xc0   PC += off if dst < src     signed
-  BPF_JSLE  0xd0   PC += off if dst <= src    signed
-  ========  =====  =========================  ============
-
-The eBPF program needs to store the return value into register R0 before doing a
-BPF_EXIT.

+Support for ``BPF_JMP32`` is required in ISA version 3, and optional in earlier
+versions.
+
+The 4-bit 'code' field encodes the operation as below, where PC is the program counter:
+
+========  =====  ============================  =======  ============
+code      value  description                   version  notes
+========  =====  ============================  =======  ============
+BPF_JA    0x00   PC += offset                  1        BPF_JMP only
+BPF_JEQ   0x10   PC += offset if dst == src    1
+BPF_JGT   0x20   PC += offset if dst > src     1        unsigned
+BPF_JGE   0x30   PC += offset if dst >= src    1        unsigned
+BPF_JSET  0x40   PC += offset if dst & src     1
+BPF_JNE   0x50   PC += offset if dst != src    1
+BPF_JSGT  0x60   PC += offset if dst > src     1        signed
+BPF_JSGE  0x70   PC += offset if dst >= src    1        signed
+BPF_CALL  0x80   call function imm             1        see `Helper functions`_
+BPF_EXIT  0x90   function / program return     1        BPF_JMP only
+BPF_JLT   0xa0   PC += offset if dst < src     2        unsigned
+BPF_JLE   0xb0   PC += offset if dst <= src    2        unsigned
+BPF_JSLT  0xc0   PC += offset if dst < src     2        signed
+BPF_JSLE  0xd0   PC += offset if dst <= src    2        signed
+========  =====  ============================  =======  ============
+
+where 'version' indicates the first ISA version in which the value was supported.
+
+Helper functions
+~~~~~~~~~~~~~~~~
+Helper functions are a concept whereby BPF programs can call into
+set of function calls exposed by the eBPF runtime.  Each helper
+function is identified by an integer used in a ``BPF_CALL`` instruction.
+The available helper functions may differ for each eBPF program type.
+
+Conceptually, each helper function is implemented with a commonly shared function
+signature defined as:
+
+  uint64_t function(uint64_t r1, uint64_t r2, uint64_t r3, uint64_t r4, uint64_t r5)
+
+In actuality, each helper function is defined as taking between 0 and 5 arguments,
+with the remaining registers being ignored.  The definition of a helper function
+is responsible for specifying the type (e.g., integer, pointer, etc.) of the value returned,
+the number of arguments, and the type of each argument.

 Load and store instructions
===========================

-For load and store instructions (BPF_LD, BPF_LDX, BPF_ST and BPF_STX), the
+For load and store instructions (``BPF_LD``, ``BPF_LDX``, ``BPF_ST``, and ``BPF_STX``), the
8-bit 'opcode' field is divided as:

-  ============  ======  =================
-  3 bits (MSB)  2 bits  3 bits (LSB)
-  ============  ======  =================
-  mode          size    instruction class
-  ============  ======  =================
+============  ======  =================
+3 bits (MSB)  2 bits  3 bits (LSB)
+============  ======  =================
+mode          size    instruction class
+============  ======  =================

-The size modifier is one of:
+mode
+  one of:
+
+  =============  =====  ====================================  =============
+  mode modifier  value  description                           reference
+  =============  =====  ====================================  =============
+  BPF_IMM        0x00   64-bit immediate instructions         `64-bit immediate instructions`_
+  BPF_ABS        0x20   legacy BPF packet access (absolute)   `Legacy BPF Packet access instructions`_
+  BPF_IND        0x40   legacy BPF packet access (indirect)   `Legacy BPF Packet access instructions`_
+  BPF_MEM        0x60   regular load and store operations     `Regular load and store operations`_
+  BPF_ATOMIC     0xc0   atomic operations                     `Atomic operations`_
+  =============  =====  ====================================  =============
+
+size
+  one of:

   =============  =====  =====================
   size modifier  value  description
@@ -213,18 +362,8 @@ The size modifier is one of:
   BPF_DW         0x18   double word (8 bytes)
   =============  =====  =====================
