const struct btf *btf,
                             const struct btf_type *key_type,
                             const struct btf_type *value_type);
+
+       /* Direct value access helpers. */
+       int (*map_direct_value_addr)(const struct bpf_map *map,
+                                    u64 *imm, u32 off);
+       int (*map_direct_value_meta)(const struct bpf_map *map,
+                                    u64 imm, u32 *off);
 };
 
 struct bpf_map {
 
                unsigned long map_state;        /* pointer/poison value for maps */
                s32 call_imm;                   /* saved imm field of call insn */
                u32 alu_limit;                  /* limit for add/sub register with pointer */
+               struct {
+                       u32 map_index;          /* index into used_maps[] */
+                       u32 map_off;            /* offset from value base address */
+               };
        };
        int ctx_field_size; /* the ctx field size for load insn, maybe 0 */
        int sanitize_stack_off; /* stack slot to be cleared */
 
  */
 #define BPF_F_ANY_ALIGNMENT    (1U << 1)
 
-/* when bpf_ldimm64->src_reg == BPF_PSEUDO_MAP_FD, bpf_ldimm64->imm == fd */
+/* When BPF ldimm64's insn[0].src_reg != 0 then this can have
+ * two extensions:
+ *
+ * insn[0].src_reg:  BPF_PSEUDO_MAP_FD   BPF_PSEUDO_MAP_VALUE
+ * insn[0].imm:      map fd              map fd
+ * insn[1].imm:      0                   offset into value
+ * insn[0].off:      0                   0
+ * insn[1].off:      0                   0
+ * ldimm64 rewrite:  address of map      address of map[0]+offset
+ * verifier type:    CONST_PTR_TO_MAP    PTR_TO_MAP_VALUE
+ */
 #define BPF_PSEUDO_MAP_FD      1
+#define BPF_PSEUDO_MAP_VALUE   2
 
 /* when bpf_call->src_reg == BPF_PSEUDO_CALL, bpf_call->imm == pc-relative
  * offset to another bpf function
 
        return array->value + array->elem_size * (index & array->index_mask);
 }
 
+static int array_map_direct_value_addr(const struct bpf_map *map, u64 *imm,
+                                      u32 off)
+{
+       struct bpf_array *array = container_of(map, struct bpf_array, map);
+
+       if (map->max_entries != 1)
+               return -ENOTSUPP;
+       if (off >= map->value_size)
+               return -EINVAL;
+
+       *imm = (unsigned long)array->value;
+       return 0;
+}
+
+static int array_map_direct_value_meta(const struct bpf_map *map, u64 imm,
+                                      u32 *off)
+{
+       struct bpf_array *array = container_of(map, struct bpf_array, map);
+       u64 base = (unsigned long)array->value;
+       u64 range = array->elem_size;
+
+       if (map->max_entries != 1)
+               return -ENOTSUPP;
+       if (imm < base || imm >= base + range)
+               return -ENOENT;
+
+       *off = imm - base;
+       return 0;
+}
+
 /* emit BPF instructions equivalent to C code of array_map_lookup_elem() */
 static u32 array_map_gen_lookup(struct bpf_map *map, struct bpf_insn *insn_buf)
 {
        .map_update_elem = array_map_update_elem,
        .map_delete_elem = array_map_delete_elem,
        .map_gen_lookup = array_map_gen_lookup,
+       .map_direct_value_addr = array_map_direct_value_addr,
+       .map_direct_value_meta = array_map_direct_value_meta,
        .map_seq_show_elem = array_map_seq_show_elem,
        .map_check_btf = array_map_check_btf,
 };
 
                dst[i] = fp->insnsi[i];
                if (!was_ld_map &&
                    dst[i].code == (BPF_LD | BPF_IMM | BPF_DW) &&
-                   dst[i].src_reg == BPF_PSEUDO_MAP_FD) {
+                   (dst[i].src_reg == BPF_PSEUDO_MAP_FD ||
+                    dst[i].src_reg == BPF_PSEUDO_MAP_VALUE)) {
                        was_ld_map = true;
                        dst[i].imm = 0;
                } else if (was_ld_map &&
 
                         * part of the ldimm64 insn is accessible.
                         */
                        u64 imm = ((u64)(insn + 1)->imm << 32) | (u32)insn->imm;
-                       bool map_ptr = insn->src_reg == BPF_PSEUDO_MAP_FD;
+                       bool is_ptr = insn->src_reg == BPF_PSEUDO_MAP_FD ||
+                                     insn->src_reg == BPF_PSEUDO_MAP_VALUE;
                        char tmp[64];
 
-                       if (map_ptr && !allow_ptr_leaks)
+                       if (is_ptr && !allow_ptr_leaks)
                                imm = 0;
 
                        verbose(cbs->private_data, "(%02x) r%d = %s\n",
 
 }
 
 static const struct bpf_map *bpf_map_from_imm(const struct bpf_prog *prog,
-                                             unsigned long addr)
+                                             unsigned long addr, u32 *off,
+                                             u32 *type)
 {
+       const struct bpf_map *map;
        int i;
 
-       for (i = 0; i < prog->aux->used_map_cnt; i++)
-               if (prog->aux->used_maps[i] == (void *)addr)
-                       return prog->aux->used_maps[i];
+       for (i = 0, *off = 0; i < prog->aux->used_map_cnt; i++) {
+               map = prog->aux->used_maps[i];
+               if (map == (void *)addr) {
+                       *type = BPF_PSEUDO_MAP_FD;
+                       return map;
+               }
+               if (!map->ops->map_direct_value_meta)
+                       continue;
+               if (!map->ops->map_direct_value_meta(map, addr, off)) {
+                       *type = BPF_PSEUDO_MAP_VALUE;
+                       return map;
+               }
+       }
+
        return NULL;
 }
 
 {
        const struct bpf_map *map;
        struct bpf_insn *insns;
+       u32 off, type;
        u64 imm;
        int i;
 
                        continue;
 
                imm = ((u64)insns[i + 1].imm << 32) | (u32)insns[i].imm;
-               map = bpf_map_from_imm(prog, imm);
+               map = bpf_map_from_imm(prog, imm, &off, &type);
                if (map) {
-                       insns[i].src_reg = BPF_PSEUDO_MAP_FD;
+                       insns[i].src_reg = type;
                        insns[i].imm = map->id;
-                       insns[i + 1].imm = 0;
+                       insns[i + 1].imm = off;
                        continue;
                }
        }
 
        return 0;
 }
 
-/* return the map pointer stored inside BPF_LD_IMM64 instruction */
-static struct bpf_map *ld_imm64_to_map_ptr(struct bpf_insn *insn)
-{
-       u64 imm64 = ((u64) (u32) insn[0].imm) | ((u64) (u32) insn[1].imm) << 32;
-
-       return (struct bpf_map *) (unsigned long) imm64;
-}
-
 /* verify BPF_LD_IMM64 instruction */
 static int check_ld_imm(struct bpf_verifier_env *env, struct bpf_insn *insn)
 {
+       struct bpf_insn_aux_data *aux = cur_aux(env);
        struct bpf_reg_state *regs = cur_regs(env);
+       struct bpf_map *map;
        int err;
 
        if (BPF_SIZE(insn->code) != BPF_DW) {
                return 0;
        }
 
-       /* replace_map_fd_with_map_ptr() should have caught bad ld_imm64 */
-       BUG_ON(insn->src_reg != BPF_PSEUDO_MAP_FD);
+       map = env->used_maps[aux->map_index];
+       mark_reg_known_zero(env, regs, insn->dst_reg);
+       regs[insn->dst_reg].map_ptr = map;
+
+       if (insn->src_reg == BPF_PSEUDO_MAP_VALUE) {
+               regs[insn->dst_reg].type = PTR_TO_MAP_VALUE;
+               regs[insn->dst_reg].off = aux->map_off;
+               if (map_value_has_spin_lock(map))
+                       regs[insn->dst_reg].id = ++env->id_gen;
+       } else if (insn->src_reg == BPF_PSEUDO_MAP_FD) {
+               regs[insn->dst_reg].type = CONST_PTR_TO_MAP;
+       } else {
+               verbose(env, "bpf verifier is misconfigured\n");
+               return -EINVAL;
+       }
 
-       regs[insn->dst_reg].type = CONST_PTR_TO_MAP;
-       regs[insn->dst_reg].map_ptr = ld_imm64_to_map_ptr(insn);
        return 0;
 }
 
                }
 
                if (insn[0].code == (BPF_LD | BPF_IMM | BPF_DW)) {
+                       struct bpf_insn_aux_data *aux;
                        struct bpf_map *map;
                        struct fd f;
+                       u64 addr;
 
                        if (i == insn_cnt - 1 || insn[1].code != 0 ||
                            insn[1].dst_reg != 0 || insn[1].src_reg != 0 ||
                                return -EINVAL;
                        }
 
-                       if (insn->src_reg == 0)
+                       if (insn[0].src_reg == 0)
                                /* valid generic load 64-bit imm */
                                goto next_insn;
 
-                       if (insn[0].src_reg != BPF_PSEUDO_MAP_FD ||
-                           insn[1].imm != 0) {
-                               verbose(env, "unrecognized bpf_ld_imm64 insn\n");
+                       /* In final convert_pseudo_ld_imm64() step, this is
+                        * converted into regular 64-bit imm load insn.
+                        */
+                       if ((insn[0].src_reg != BPF_PSEUDO_MAP_FD &&
+                            insn[0].src_reg != BPF_PSEUDO_MAP_VALUE) ||
+                           (insn[0].src_reg == BPF_PSEUDO_MAP_FD &&
+                            insn[1].imm != 0)) {
+                               verbose(env,
+                                       "unrecognized bpf_ld_imm64 insn\n");
                                return -EINVAL;
                        }
 
                                return err;
                        }
 
-                       /* store map pointer inside BPF_LD_IMM64 instruction */
-                       insn[0].imm = (u32) (unsigned long) map;
-                       insn[1].imm = ((u64) (unsigned long) map) >> 32;
+                       aux = &env->insn_aux_data[i];
+                       if (insn->src_reg == BPF_PSEUDO_MAP_FD) {
+                               addr = (unsigned long)map;
+                       } else {
+                               u32 off = insn[1].imm;
+
+                               if (off >= BPF_MAX_VAR_OFF) {
+                                       verbose(env, "direct value offset of %u is not allowed\n", off);
+                                       fdput(f);
+                                       return -EINVAL;
+                               }
+
+                               if (!map->ops->map_direct_value_addr) {
+                                       verbose(env, "no direct value access support for this map type\n");
+                                       fdput(f);
+                                       return -EINVAL;
+                               }
+
+                               err = map->ops->map_direct_value_addr(map, &addr, off);
+                               if (err) {
+                                       verbose(env, "invalid access to map value pointer, value_size=%u off=%u\n",
+                                               map->value_size, off);
+                                       fdput(f);
+                                       return err;
+                               }
+
+                               aux->map_off = off;
+                               addr += off;
+                       }
+
+                       insn[0].imm = (u32)addr;
+                       insn[1].imm = addr >> 32;
 
                        /* check whether we recorded this map already */
-                       for (j = 0; j < env->used_map_cnt; j++)
+                       for (j = 0; j < env->used_map_cnt; j++) {
                                if (env->used_maps[j] == map) {
+                                       aux->map_index = j;
                                        fdput(f);
                                        goto next_insn;
                                }
+                       }
 
                        if (env->used_map_cnt >= MAX_USED_MAPS) {
                                fdput(f);
                                fdput(f);
                                return PTR_ERR(map);
                        }
+
+                       aux->map_index = env->used_map_cnt;
                        env->used_maps[env->used_map_cnt++] = map;
 
                        if (bpf_map_is_cgroup_storage(map) &&
 
        if (insn->src_reg == BPF_PSEUDO_MAP_FD)
                snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
                         "map[id:%u]", insn->imm);
+       else if (insn->src_reg == BPF_PSEUDO_MAP_VALUE)
+               snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
+                        "map[id:%u][0]+%u", insn->imm, (insn + 1)->imm);
        else
                snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
                         "0x%llx", (unsigned long long)full_imm);