| 1 | |
| 2 | |
| 3 | * Provide kernel BTF information for introspection and use by eBPF tools.
|
| 4 |
|
| 5 | #include <linux/kernel.h>
|
| 6 | #include <linux/module.h>
|
| 7 | #include <linux/kobject.h>
|
| 8 | #include <linux/init.h>
|
| 9 | #include <linux/sysfs.h>
|
| 10 | #include <linux/mm.h>
|
| 11 | #include <linux/io.h>
|
| 12 | #include <linux/btf.h>
|
| 13 |
|
| 14 |
|
| 15 | extern char __start_BTF[];
|
| 16 | extern char __stop_BTF[];
|
| 17 |
|
| 18 | static int btf_sysfs_vmlinux_mmap(struct file *filp, struct kobject *kobj,
|
| 19 | const struct bin_attribute *attr,
|
| 20 | struct vm_area_struct *vma)
|
| 21 | {
|
| 22 | unsigned long pages = PAGE_ALIGN(attr->size) >> PAGE_SHIFT;
|
| 23 | size_t vm_size = vma->vm_end - vma->vm_start;
|
| 24 | phys_addr_t addr = __pa_symbol(__start_BTF);
|
| 25 | unsigned long pfn = addr >> PAGE_SHIFT;
|
| 26 |
|
| 27 | if (attr->private != __start_BTF || !PAGE_ALIGNED(addr))
|
| 28 | return -EINVAL;
|
| 29 |
|
| 30 | if (vma->vm_pgoff)
|
| 31 | return -EINVAL;
|
| 32 |
|
| 33 | if (vma->vm_flags & (VM_WRITE | VM_EXEC | VM_MAYSHARE))
|
| 34 | return -EACCES;
|
| 35 |
|
| 36 | if (pfn + pages < pfn)
|
| 37 | return -EINVAL;
|
| 38 |
|
| 39 | if ((vm_size >> PAGE_SHIFT) > pages)
|
| 40 | return -EINVAL;
|
| 41 |
|
| 42 | vm_flags_mod(vma, VM_DONTDUMP, VM_MAYEXEC | VM_MAYWRITE);
|
| 43 | return remap_pfn_range(vma, vma->vm_start, pfn, vm_size, vma->vm_page_prot);
|
| 44 | }
|
| 45 |
|
| 46 | static struct bin_attribute bin_attr_btf_vmlinux __ro_after_init = {
|
| 47 | .attr = { .name = "vmlinux", .mode = 0444, },
|
| 48 | .read = sysfs_bin_attr_simple_read,
|
| 49 | .mmap = btf_sysfs_vmlinux_mmap,
|
| 50 | };
|
| 51 |
|
| 52 | struct kobject *btf_kobj;
|
| 53 |
|
| 54 | static int __init btf_vmlinux_init(void)
|
| 55 | {
|
| 56 | bin_attr_btf_vmlinux.private = __start_BTF;
|
| 57 | bin_attr_btf_vmlinux.size = __stop_BTF - __start_BTF;
|
| 58 |
|
| 59 | if (bin_attr_btf_vmlinux.size == 0)
|
| 60 | return 0;
|
| 61 |
|
| 62 | btf_kobj = kobject_create_and_add("btf", kernel_kobj);
|
| 63 | if (!btf_kobj)
|
| 64 | return -ENOMEM;
|
| 65 |
|
| 66 | return sysfs_create_bin_file(btf_kobj, &bin_attr_btf_vmlinux);
|
| 67 | }
|
| 68 |
|
| 69 | subsys_initcall(btf_vmlinux_init);
|