* bits 24-28: kind (e.g. int, ptr, array...etc)
         * bits 29-30: unused
         * bit     31: kind_flag, currently used by
-        *             struct, union and fwd
+        *             struct, union, enum, fwd and enum64
         */
        __u32 info;
-       /* "size" is used by INT, ENUM, STRUCT, UNION and DATASEC.
+       /* "size" is used by INT, ENUM, STRUCT, UNION, DATASEC and ENUM64.
         * "size" tells the size of the type it is describing.
         *
         * "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
        BTF_KIND_ARRAY          = 3,    /* Array        */
        BTF_KIND_STRUCT         = 4,    /* Struct       */
        BTF_KIND_UNION          = 5,    /* Union        */
-       BTF_KIND_ENUM           = 6,    /* Enumeration  */
+       BTF_KIND_ENUM           = 6,    /* Enumeration up to 32-bit values */
        BTF_KIND_FWD            = 7,    /* Forward      */
        BTF_KIND_TYPEDEF        = 8,    /* Typedef      */
        BTF_KIND_VOLATILE       = 9,    /* Volatile     */
        BTF_KIND_FLOAT          = 16,   /* Floating point       */
        BTF_KIND_DECL_TAG       = 17,   /* Decl Tag */
        BTF_KIND_TYPE_TAG       = 18,   /* Type Tag */
+       BTF_KIND_ENUM64         = 19,   /* Enumeration up to 64-bit values */
 
        NR_BTF_KINDS,
        BTF_KIND_MAX            = NR_BTF_KINDS - 1,
        __s32   component_idx;
 };
 
+/* BTF_KIND_ENUM64 is followed by multiple "struct btf_enum64".
+ * The exact number of btf_enum64 is stored in the vlen (of the
+ * info in "struct btf_type").
+ */
+struct btf_enum64 {
+       __u32   name_off;
+       __u32   val_lo32;
+       __u32   val_hi32;
+};
+
 #endif /* _UAPI__LINUX_BTF_H__ */
 
        [BTF_KIND_FLOAT]        = "FLOAT",
        [BTF_KIND_DECL_TAG]     = "DECL_TAG",
        [BTF_KIND_TYPE_TAG]     = "TYPE_TAG",
+       [BTF_KIND_ENUM64]       = "ENUM64",
 };
 
 const char *btf_type_str(const struct btf_type *t)
        case BTF_KIND_ENUM:
        case BTF_KIND_DATASEC:
        case BTF_KIND_FLOAT:
+       case BTF_KIND_ENUM64:
                return true;
        }
 
        return (const struct btf_decl_tag *)(t + 1);
 }
 
+static const struct btf_enum64 *btf_type_enum64(const struct btf_type *t)
+{
+       return (const struct btf_enum64 *)(t + 1);
+}
+
 static const struct btf_kind_operations *btf_type_ops(const struct btf_type *t)
 {
        return kind_ops[BTF_INFO_KIND(t->info)];
                        parens = "{";
                break;
        case BTF_KIND_ENUM:
+       case BTF_KIND_ENUM64:
                prefix = "enum";
                break;
        default:
                case BTF_KIND_UNION:
                case BTF_KIND_ENUM:
                case BTF_KIND_FLOAT:
+               case BTF_KIND_ENUM64:
                        size = type->size;
                        goto resolved;
 
 {
        const struct btf_enum *enums = btf_type_enum(t);
        struct btf *btf = env->btf;
+       const char *fmt_str;
        u16 i, nr_enums;
        u32 meta_needed;
 
                return -EINVAL;
        }
 
-       if (btf_type_kflag(t)) {
-               btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
-               return -EINVAL;
-       }
-
        if (t->size > 8 || !is_power_of_2(t->size)) {
                btf_verifier_log_type(env, t, "Unexpected size");
                return -EINVAL;
 
                if (env->log.level == BPF_LOG_KERNEL)
                        continue;
-               btf_verifier_log(env, "\t%s val=%d\n",
+               fmt_str = btf_type_kflag(t) ? "\t%s val=%d\n" : "\t%s val=%u\n";
+               btf_verifier_log(env, fmt_str,
                                 __btf_name_by_offset(btf, enums[i].name_off),
                                 enums[i].val);
        }
                return;
        }
 
-       btf_show_type_value(show, "%d", v);
+       if (btf_type_kflag(t))
+               btf_show_type_value(show, "%d", v);
+       else
+               btf_show_type_value(show, "%u", v);
        btf_show_end_type(show);
 }
 
        .show = btf_enum_show,
 };
 
+static s32 btf_enum64_check_meta(struct btf_verifier_env *env,
+                                const struct btf_type *t,
+                                u32 meta_left)
+{
+       const struct btf_enum64 *enums = btf_type_enum64(t);
+       struct btf *btf = env->btf;
+       const char *fmt_str;
+       u16 i, nr_enums;
+       u32 meta_needed;
+
+       nr_enums = btf_type_vlen(t);
+       meta_needed = nr_enums * sizeof(*enums);
+
+       if (meta_left < meta_needed) {
+               btf_verifier_log_basic(env, t,
+                                      "meta_left:%u meta_needed:%u",
+                                      meta_left, meta_needed);
+               return -EINVAL;
+       }
+
+       if (t->size > 8 || !is_power_of_2(t->size)) {
+               btf_verifier_log_type(env, t, "Unexpected size");
+               return -EINVAL;
+       }
+
+       /* enum type either no name or a valid one */
+       if (t->name_off &&
+           !btf_name_valid_identifier(env->btf, t->name_off)) {
+               btf_verifier_log_type(env, t, "Invalid name");
+               return -EINVAL;
+       }
+
+       btf_verifier_log_type(env, t, NULL);
+
+       for (i = 0; i < nr_enums; i++) {
+               if (!btf_name_offset_valid(btf, enums[i].name_off)) {
+                       btf_verifier_log(env, "\tInvalid name_offset:%u",
+                                        enums[i].name_off);
+                       return -EINVAL;
+               }
+
+               /* enum member must have a valid name */
+               if (!enums[i].name_off ||
+                   !btf_name_valid_identifier(btf, enums[i].name_off)) {
+                       btf_verifier_log_type(env, t, "Invalid name");
+                       return -EINVAL;
+               }
+
+               if (env->log.level == BPF_LOG_KERNEL)
+                       continue;
+
+               fmt_str = btf_type_kflag(t) ? "\t%s val=%lld\n" : "\t%s val=%llu\n";
+               btf_verifier_log(env, fmt_str,
+                                __btf_name_by_offset(btf, enums[i].name_off),
+                                btf_enum64_value(enums + i));
+       }
+
+       return meta_needed;
+}
+
+static void btf_enum64_show(const struct btf *btf, const struct btf_type *t,
+                           u32 type_id, void *data, u8 bits_offset,
+                           struct btf_show *show)
+{
+       const struct btf_enum64 *enums = btf_type_enum64(t);
+       u32 i, nr_enums = btf_type_vlen(t);
+       void *safe_data;
+       s64 v;
+
+       safe_data = btf_show_start_type(show, t, type_id, data);
+       if (!safe_data)
+               return;
+
+       v = *(u64 *)safe_data;
+
+       for (i = 0; i < nr_enums; i++) {
+               if (v != btf_enum64_value(enums + i))
+                       continue;
+
+               btf_show_type_value(show, "%s",
+                                   __btf_name_by_offset(btf,
+                                                        enums[i].name_off));
+
+               btf_show_end_type(show);
+               return;
+       }
+
+       if (btf_type_kflag(t))
+               btf_show_type_value(show, "%lld", v);
+       else
+               btf_show_type_value(show, "%llu", v);
+       btf_show_end_type(show);
+}
+
+static struct btf_kind_operations enum64_ops = {
+       .check_meta = btf_enum64_check_meta,
+       .resolve = btf_df_resolve,
+       .check_member = btf_enum_check_member,
+       .check_kflag_member = btf_enum_check_kflag_member,
+       .log_details = btf_enum_log,
+       .show = btf_enum64_show,
+};
+
 static s32 btf_func_proto_check_meta(struct btf_verifier_env *env,
                                     const struct btf_type *t,
                                     u32 meta_left)
        [BTF_KIND_FLOAT] = &float_ops,
        [BTF_KIND_DECL_TAG] = &decl_tag_ops,
        [BTF_KIND_TYPE_TAG] = &modifier_ops,
+       [BTF_KIND_ENUM64] = &enum64_ops,
 };
 
 static s32 btf_check_meta(struct btf_verifier_env *env,
        /* skip modifiers */
        while (btf_type_is_modifier(t))
                t = btf_type_by_id(btf, t->type);
-       if (btf_type_is_small_int(t) || btf_type_is_enum(t))
+       if (btf_type_is_small_int(t) || btf_is_any_enum(t))
                /* accessing a scalar */
                return true;
        if (!btf_type_is_ptr(t)) {
        if (btf_type_is_ptr(t))
                /* kernel size of pointer. Not BPF's size of pointer*/
                return sizeof(void *);
-       if (btf_type_is_int(t) || btf_type_is_enum(t))
+       if (btf_type_is_int(t) || btf_is_any_enum(t))
                return t->size;
        *bad_type = t;
        return -EINVAL;
                 * to context only. And only global functions can be replaced.
                 * Hence type check only those types.
                 */
-               if (btf_type_is_int(t1) || btf_type_is_enum(t1))
+               if (btf_type_is_int(t1) || btf_is_any_enum(t1))
                        continue;
                if (!btf_type_is_ptr(t1)) {
                        bpf_log(log,
        t = btf_type_by_id(btf, t->type);
        while (btf_type_is_modifier(t))
                t = btf_type_by_id(btf, t->type);
-       if (!btf_type_is_int(t) && !btf_type_is_enum(t)) {
+       if (!btf_type_is_int(t) && !btf_is_any_enum(t)) {
                bpf_log(log,
                        "Global function %s() doesn't return scalar. Only those are supported.\n",
                        tname);
                t = btf_type_by_id(btf, args[i].type);
                while (btf_type_is_modifier(t))
                        t = btf_type_by_id(btf, t->type);
-               if (btf_type_is_int(t) || btf_type_is_enum(t)) {
+               if (btf_type_is_int(t) || btf_is_any_enum(t)) {
                        reg->type = SCALAR_VALUE;
                        continue;
                }
        case BTF_KIND_UNION:
        case BTF_KIND_ENUM:
        case BTF_KIND_FWD:
+       case BTF_KIND_ENUM64:
                return 1;
        case BTF_KIND_INT:
                /* just reject deprecated bitfield-like integers; all other
  * field-based relocations. This function assumes that root types were already
  * checked for name match. Beyond that initial root-level name check, names
  * are completely ignored. Compatibility rules are as follows:
- *   - any two STRUCTs/UNIONs/FWDs/ENUMs/INTs are considered compatible, but
+ *   - any two STRUCTs/UNIONs/FWDs/ENUMs/INTs/ENUM64s are considered compatible, but
  *     kind should match for local and target types (i.e., STRUCT is not
  *     compatible with UNION);
- *   - for ENUMs, the size is ignored;
+ *   - for ENUMs/ENUM64s, the size is ignored;
  *   - for INT, size and signedness are ignored;
  *   - for ARRAY, dimensionality is ignored, element types are checked for
  *     compatibility recursively;
 
         * bits 24-28: kind (e.g. int, ptr, array...etc)
         * bits 29-30: unused
         * bit     31: kind_flag, currently used by
-        *             struct, union and fwd
+        *             struct, union, enum, fwd and enum64
         */
        __u32 info;
-       /* "size" is used by INT, ENUM, STRUCT, UNION and DATASEC.
+       /* "size" is used by INT, ENUM, STRUCT, UNION, DATASEC and ENUM64.
         * "size" tells the size of the type it is describing.
         *
         * "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
        BTF_KIND_ARRAY          = 3,    /* Array        */
        BTF_KIND_STRUCT         = 4,    /* Struct       */
        BTF_KIND_UNION          = 5,    /* Union        */
-       BTF_KIND_ENUM           = 6,    /* Enumeration  */
+       BTF_KIND_ENUM           = 6,    /* Enumeration up to 32-bit values */
        BTF_KIND_FWD            = 7,    /* Forward      */
        BTF_KIND_TYPEDEF        = 8,    /* Typedef      */
        BTF_KIND_VOLATILE       = 9,    /* Volatile     */
        BTF_KIND_FLOAT          = 16,   /* Floating point       */
        BTF_KIND_DECL_TAG       = 17,   /* Decl Tag */
        BTF_KIND_TYPE_TAG       = 18,   /* Type Tag */
+       BTF_KIND_ENUM64         = 19,   /* Enumeration up to 64-bit values */
 
        NR_BTF_KINDS,
        BTF_KIND_MAX            = NR_BTF_KINDS - 1,
        __s32   component_idx;
 };
 
+/* BTF_KIND_ENUM64 is followed by multiple "struct btf_enum64".
+ * The exact number of btf_enum64 is stored in the vlen (of the
+ * info in "struct btf_type").
+ */
+struct btf_enum64 {
+       __u32   name_off;
+       __u32   val_lo32;
+       __u32   val_hi32;
+};
+
 #endif /* _UAPI__LINUX_BTF_H__ */