|
7 | 7 | #include <linux/kobject.h>
|
8 | 8 | #include <linux/init.h>
|
9 | 9 | #include <linux/sysfs.h>
|
| 10 | +#include <linux/mm.h> |
| 11 | +#include <linux/io.h> |
| 12 | +#include <linux/btf.h> |
10 | 13 |
|
11 | 14 | /* See scripts/link-vmlinux.sh, gen_btf() func for details */
|
12 | 15 | extern char __start_BTF[];
|
13 | 16 | extern char __stop_BTF[];
|
14 | 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 = virt_to_phys(__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 | + |
15 | 46 | static struct bin_attribute bin_attr_btf_vmlinux __ro_after_init = {
|
16 | 47 | .attr = { .name = "vmlinux", .mode = 0444, },
|
17 | 48 | .read_new = sysfs_bin_attr_simple_read,
|
| 49 | + .mmap = btf_sysfs_vmlinux_mmap, |
18 | 50 | };
|
19 | 51 |
|
20 | 52 | struct kobject *btf_kobj;
|
|
0 commit comments