From 366d259ff597e81d90639ae21269b3f82cd4ebb7 Mon Sep 17 00:00:00 2001 From: Alexandre Ghiti Date: Wed, 2 Aug 2023 10:03:19 +0200 Subject: perf: Fix wrong comment about default event_idx Since commit c719f56092ad ("perf: Fix and clean up initialization of pmu::event_idx"), event_idx default implementation has returned 0, not idx + 1, so fix the comment that can be misleading. Signed-off-by: Alexandre Ghiti Reviewed-by: Andrew Jones Reviewed-by: Atish Patra --- include/linux/perf_event.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 2166a69e3bf2..1269c96bc3b6 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -445,7 +445,8 @@ struct pmu { /* * Will return the value for perf_event_mmap_page::index for this event, - * if no implementation is provided it will default to: event->hw.idx + 1. + * if no implementation is provided it will default to 0 (see + * perf_event_idx_default). */ int (*event_idx) (struct perf_event *event); /*optional */ -- cgit v1.2.3 From f117ae55b0198dd6fc36ce521e06d8b44a4bb203 Mon Sep 17 00:00:00 2001 From: Alexandre Ghiti Date: Wed, 2 Aug 2023 10:03:20 +0200 Subject: include: riscv: Fix wrong include guard in riscv_pmu.h The current include guard prevents the inclusion of asm/perf_event.h which uses the same include guard: fix the one in riscv_pmu.h so that it matches the file name. Signed-off-by: Alexandre Ghiti Reviewed-by: Conor Dooley Reviewed-by: Andrew Jones Reviewed-by: Atish Patra --- include/linux/perf/riscv_pmu.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/perf/riscv_pmu.h b/include/linux/perf/riscv_pmu.h index 43fc892aa7d9..9f70d94942e0 100644 --- a/include/linux/perf/riscv_pmu.h +++ b/include/linux/perf/riscv_pmu.h @@ -6,8 +6,8 @@ * */ -#ifndef _ASM_RISCV_PERF_EVENT_H -#define _ASM_RISCV_PERF_EVENT_H +#ifndef _RISCV_PMU_H +#define _RISCV_PMU_H #include #include @@ -81,4 +81,4 @@ int riscv_pmu_get_hpm_info(u32 *hw_ctr_width, u32 *num_hw_ctr); #endif /* CONFIG_RISCV_PMU */ -#endif /* _ASM_RISCV_PERF_EVENT_H */ +#endif /* _RISCV_PMU_H */ -- cgit v1.2.3 From d5ac062d82d87124ac75e4273e3887578a7fae60 Mon Sep 17 00:00:00 2001 From: Alexandre Ghiti Date: Wed, 2 Aug 2023 10:03:22 +0200 Subject: drivers: perf: Rename riscv pmu sbi driver That's just cosmetic, no functional changes. Signed-off-by: Alexandre Ghiti Reviewed-by: Andrew Jones Reviewed-by: Atish Patra --- drivers/perf/riscv_pmu_sbi.c | 4 ++-- include/linux/perf/riscv_pmu.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c index 4163ff517471..760eb2afcf82 100644 --- a/drivers/perf/riscv_pmu_sbi.c +++ b/drivers/perf/riscv_pmu_sbi.c @@ -907,7 +907,7 @@ out_free: static struct platform_driver pmu_sbi_driver = { .probe = pmu_sbi_device_probe, .driver = { - .name = RISCV_PMU_PDEV_NAME, + .name = RISCV_PMU_SBI_PDEV_NAME, }, }; @@ -934,7 +934,7 @@ static int __init pmu_sbi_devinit(void) if (ret) return ret; - pdev = platform_device_register_simple(RISCV_PMU_PDEV_NAME, -1, NULL, 0); + pdev = platform_device_register_simple(RISCV_PMU_SBI_PDEV_NAME, -1, NULL, 0); if (IS_ERR(pdev)) { platform_driver_unregister(&pmu_sbi_driver); return PTR_ERR(pdev); diff --git a/include/linux/perf/riscv_pmu.h b/include/linux/perf/riscv_pmu.h index 9f70d94942e0..5deeea0be7cb 100644 --- a/include/linux/perf/riscv_pmu.h +++ b/include/linux/perf/riscv_pmu.h @@ -21,7 +21,7 @@ #define RISCV_MAX_COUNTERS 64 #define RISCV_OP_UNSUPP (-EOPNOTSUPP) -#define RISCV_PMU_PDEV_NAME "riscv-pmu" +#define RISCV_PMU_SBI_PDEV_NAME "riscv-pmu-sbi" #define RISCV_PMU_LEGACY_PDEV_NAME "riscv-pmu-legacy" #define RISCV_PMU_STOP_FLAG_RESET 1 -- cgit v1.2.3 From 83c5e13b8cbbed9479cf568e03a5010d827e9781 Mon Sep 17 00:00:00 2001 From: Alexandre Ghiti Date: Wed, 2 Aug 2023 10:03:23 +0200 Subject: riscv: Prepare for user-space perf event mmap support Provide all the necessary bits in the generic riscv pmu driver to be able to mmap perf events in userspace: the heavy lifting lies in the driver backend, namely the legacy and sbi implementations. Note that arch_perf_update_userpage is almost a copy of arm64 code. Signed-off-by: Alexandre Ghiti Reviewed-by: Andrew Jones Reviewed-by: Atish Patra --- drivers/perf/riscv_pmu.c | 105 +++++++++++++++++++++++++++++++++++++++++ include/linux/perf/riscv_pmu.h | 4 ++ 2 files changed, 109 insertions(+) (limited to 'include/linux') diff --git a/drivers/perf/riscv_pmu.c b/drivers/perf/riscv_pmu.c index ebca5eab9c9b..432ad2e80ce3 100644 --- a/drivers/perf/riscv_pmu.c +++ b/drivers/perf/riscv_pmu.c @@ -14,9 +14,73 @@ #include #include #include +#include #include +static bool riscv_perf_user_access(struct perf_event *event) +{ + return ((event->attr.type == PERF_TYPE_HARDWARE) || + (event->attr.type == PERF_TYPE_HW_CACHE) || + (event->attr.type == PERF_TYPE_RAW)) && + !!(event->hw.flags & PERF_EVENT_FLAG_USER_READ_CNT); +} + +void arch_perf_update_userpage(struct perf_event *event, + struct perf_event_mmap_page *userpg, u64 now) +{ + struct clock_read_data *rd; + unsigned int seq; + u64 ns; + + userpg->cap_user_time = 0; + userpg->cap_user_time_zero = 0; + userpg->cap_user_time_short = 0; + userpg->cap_user_rdpmc = riscv_perf_user_access(event); + + userpg->pmc_width = 64; + + do { + rd = sched_clock_read_begin(&seq); + + userpg->time_mult = rd->mult; + userpg->time_shift = rd->shift; + userpg->time_zero = rd->epoch_ns; + userpg->time_cycles = rd->epoch_cyc; + userpg->time_mask = rd->sched_clock_mask; + + /* + * Subtract the cycle base, such that software that + * doesn't know about cap_user_time_short still 'works' + * assuming no wraps. + */ + ns = mul_u64_u32_shr(rd->epoch_cyc, rd->mult, rd->shift); + userpg->time_zero -= ns; + + } while (sched_clock_read_retry(seq)); + + userpg->time_offset = userpg->time_zero - now; + + /* + * time_shift is not expected to be greater than 31 due to + * the original published conversion algorithm shifting a + * 32-bit value (now specifies a 64-bit value) - refer + * perf_event_mmap_page documentation in perf_event.h. + */ + if (userpg->time_shift == 32) { + userpg->time_shift = 31; + userpg->time_mult >>= 1; + } + + /* + * Internal timekeeping for enabled/running/stopped times + * is always computed with the sched_clock. + */ + userpg->cap_user_time = 1; + userpg->cap_user_time_zero = 1; + userpg->cap_user_time_short = 1; +} + static unsigned long csr_read_num(int csr_num) { #define switchcase_csr_read(__csr_num, __val) {\ @@ -171,6 +235,8 @@ int riscv_pmu_event_set_period(struct perf_event *event) local64_set(&hwc->prev_count, (u64)-left); + perf_event_update_userpage(event); + return overflow; } @@ -267,6 +333,9 @@ static int riscv_pmu_event_init(struct perf_event *event) hwc->idx = -1; hwc->event_base = mapped_event; + if (rvpmu->event_init) + rvpmu->event_init(event); + if (!is_sampling_event(event)) { /* * For non-sampling runs, limit the sample_period to half @@ -283,6 +352,39 @@ static int riscv_pmu_event_init(struct perf_event *event) return 0; } +static int riscv_pmu_event_idx(struct perf_event *event) +{ + struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu); + + if (!(event->hw.flags & PERF_EVENT_FLAG_USER_READ_CNT)) + return 0; + + if (rvpmu->csr_index) + return rvpmu->csr_index(event) + 1; + + return 0; +} + +static void riscv_pmu_event_mapped(struct perf_event *event, struct mm_struct *mm) +{ + struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu); + + if (rvpmu->event_mapped) { + rvpmu->event_mapped(event, mm); + perf_event_update_userpage(event); + } +} + +static void riscv_pmu_event_unmapped(struct perf_event *event, struct mm_struct *mm) +{ + struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu); + + if (rvpmu->event_unmapped) { + rvpmu->event_unmapped(event, mm); + perf_event_update_userpage(event); + } +} + struct riscv_pmu *riscv_pmu_alloc(void) { struct riscv_pmu *pmu; @@ -307,6 +409,9 @@ struct riscv_pmu *riscv_pmu_alloc(void) } pmu->pmu = (struct pmu) { .event_init = riscv_pmu_event_init, + .event_mapped = riscv_pmu_event_mapped, + .event_unmapped = riscv_pmu_event_unmapped, + .event_idx = riscv_pmu_event_idx, .add = riscv_pmu_add, .del = riscv_pmu_del, .start = riscv_pmu_start, diff --git a/include/linux/perf/riscv_pmu.h b/include/linux/perf/riscv_pmu.h index 5deeea0be7cb..43282e22ebe1 100644 --- a/include/linux/perf/riscv_pmu.h +++ b/include/linux/perf/riscv_pmu.h @@ -55,6 +55,10 @@ struct riscv_pmu { void (*ctr_start)(struct perf_event *event, u64 init_val); void (*ctr_stop)(struct perf_event *event, unsigned long flag); int (*event_map)(struct perf_event *event, u64 *config); + void (*event_init)(struct perf_event *event); + void (*event_mapped)(struct perf_event *event, struct mm_struct *mm); + void (*event_unmapped)(struct perf_event *event, struct mm_struct *mm); + uint8_t (*csr_index)(struct perf_event *event); struct cpu_hw_events __percpu *hw_events; struct hlist_node node; -- cgit v1.2.3 From b922bf04d2c1355633bdefbc2ed5fba1f0d4df07 Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Tue, 11 Jul 2023 23:07:53 +1000 Subject: binfmt_elf_fdpic: support 64-bit systems The binfmt_flat_fdpic code has a number of 32-bit specific data structures associated with it. Extend it to be able to support and be used on 64-bit systems as well. The new code defines a number of key 64-bit variants of the core elf-fdpic data structures - along side the existing 32-bit sized ones. A common set of generic named structures are defined to be either the 32-bit or 64-bit ones as required at compile time. This is a similar technique to that used in the ELF binfmt loader. For example: elf_fdpic_loadseg is either elf32_fdpic_loadseg or elf64_fdpic_loadseg elf_fdpic_loadmap is either elf32_fdpic_loadmap or elf64_fdpic_loadmap the choice based on ELFCLASS32 or ELFCLASS64. Signed-off-by: Greg Ungerer Acked-by: Kees Cook Link: https://lore.kernel.org/r/20230711130754.481209-2-gerg@kernel.org Signed-off-by: Palmer Dabbelt --- fs/binfmt_elf_fdpic.c | 38 +++++++++++++++++++------------------- include/linux/elf-fdpic.h | 14 +++++++++++++- include/uapi/linux/elf-fdpic.h | 15 +++++++++++++++ 3 files changed, 47 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 1c6c5832af86..43b2a2851ba3 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -138,7 +138,7 @@ static int is_constdisp(struct elfhdr *hdr) static int elf_fdpic_fetch_phdrs(struct elf_fdpic_params *params, struct file *file) { - struct elf32_phdr *phdr; + struct elf_phdr *phdr; unsigned long size; int retval, loop; loff_t pos = params->hdr.e_phoff; @@ -560,8 +560,8 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm, sp &= ~7UL; /* stack the load map(s) */ - len = sizeof(struct elf32_fdpic_loadmap); - len += sizeof(struct elf32_fdpic_loadseg) * exec_params->loadmap->nsegs; + len = sizeof(struct elf_fdpic_loadmap); + len += sizeof(struct elf_fdpic_loadseg) * exec_params->loadmap->nsegs; sp = (sp - len) & ~7UL; exec_params->map_addr = sp; @@ -571,8 +571,8 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm, current->mm->context.exec_fdpic_loadmap = (unsigned long) sp; if (interp_params->loadmap) { - len = sizeof(struct elf32_fdpic_loadmap); - len += sizeof(struct elf32_fdpic_loadseg) * + len = sizeof(struct elf_fdpic_loadmap); + len += sizeof(struct elf_fdpic_loadseg) * interp_params->loadmap->nsegs; sp = (sp - len) & ~7UL; interp_params->map_addr = sp; @@ -740,13 +740,13 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params, struct mm_struct *mm, const char *what) { - struct elf32_fdpic_loadmap *loadmap; + struct elf_fdpic_loadmap *loadmap; #ifdef CONFIG_MMU - struct elf32_fdpic_loadseg *mseg; + struct elf_fdpic_loadseg *mseg; unsigned long load_addr; #endif - struct elf32_fdpic_loadseg *seg; - struct elf32_phdr *phdr; + struct elf_fdpic_loadseg *seg; + struct elf_phdr *phdr; unsigned nloads, tmp; unsigned long stop; int loop, ret; @@ -766,7 +766,7 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params, params->loadmap = loadmap; - loadmap->version = ELF32_FDPIC_LOADMAP_VERSION; + loadmap->version = ELF_FDPIC_LOADMAP_VERSION; loadmap->nsegs = nloads; /* map the requested LOADs into the memory space */ @@ -839,8 +839,8 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params, if (phdr->p_vaddr >= seg->p_vaddr && phdr->p_vaddr + phdr->p_memsz <= seg->p_vaddr + seg->p_memsz) { - Elf32_Dyn __user *dyn; - Elf32_Sword d_tag; + Elf_Dyn __user *dyn; + Elf_Sword d_tag; params->dynamic_addr = (phdr->p_vaddr - seg->p_vaddr) + @@ -850,11 +850,11 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params, * one item, and that the last item is a NULL * entry */ if (phdr->p_memsz == 0 || - phdr->p_memsz % sizeof(Elf32_Dyn) != 0) + phdr->p_memsz % sizeof(Elf_Dyn) != 0) goto dynamic_error; - tmp = phdr->p_memsz / sizeof(Elf32_Dyn); - dyn = (Elf32_Dyn __user *)params->dynamic_addr; + tmp = phdr->p_memsz / sizeof(Elf_Dyn); + dyn = (Elf_Dyn __user *)params->dynamic_addr; if (get_user(d_tag, &dyn[tmp - 1].d_tag) || d_tag != 0) goto dynamic_error; @@ -923,8 +923,8 @@ static int elf_fdpic_map_file_constdisp_on_uclinux( struct file *file, struct mm_struct *mm) { - struct elf32_fdpic_loadseg *seg; - struct elf32_phdr *phdr; + struct elf_fdpic_loadseg *seg; + struct elf_phdr *phdr; unsigned long load_addr, base = ULONG_MAX, top = 0, maddr = 0; int loop, ret; @@ -1007,8 +1007,8 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params, struct file *file, struct mm_struct *mm) { - struct elf32_fdpic_loadseg *seg; - struct elf32_phdr *phdr; + struct elf_fdpic_loadseg *seg; + struct elf_phdr *phdr; unsigned long load_addr, delta_vaddr; int loop, dvset; diff --git a/include/linux/elf-fdpic.h b/include/linux/elf-fdpic.h index 3bea95a1af53..e533f4513194 100644 --- a/include/linux/elf-fdpic.h +++ b/include/linux/elf-fdpic.h @@ -10,13 +10,25 @@ #include +#if ELF_CLASS == ELFCLASS32 +#define Elf_Sword Elf32_Sword +#define elf_fdpic_loadseg elf32_fdpic_loadseg +#define elf_fdpic_loadmap elf32_fdpic_loadmap +#define ELF_FDPIC_LOADMAP_VERSION ELF32_FDPIC_LOADMAP_VERSION +#else +#define Elf_Sword Elf64_Sxword +#define elf_fdpic_loadmap elf64_fdpic_loadmap +#define elf_fdpic_loadseg elf64_fdpic_loadseg +#define ELF_FDPIC_LOADMAP_VERSION ELF64_FDPIC_LOADMAP_VERSION +#endif + /* * binfmt binary parameters structure */ struct elf_fdpic_params { struct elfhdr hdr; /* ref copy of ELF header */ struct elf_phdr *phdrs; /* ref copy of PT_PHDR table */ - struct elf32_fdpic_loadmap *loadmap; /* loadmap to be passed to userspace */ + struct elf_fdpic_loadmap *loadmap; /* loadmap to be passed to userspace */ unsigned long elfhdr_addr; /* mapped ELF header user address */ unsigned long ph_addr; /* mapped PT_PHDR user address */ unsigned long map_addr; /* mapped loadmap user address */ diff --git a/include/uapi/linux/elf-fdpic.h b/include/uapi/linux/elf-fdpic.h index 4fcc6cfebe18..ec23f0871129 100644 --- a/include/uapi/linux/elf-fdpic.h +++ b/include/uapi/linux/elf-fdpic.h @@ -32,4 +32,19 @@ struct elf32_fdpic_loadmap { #define ELF32_FDPIC_LOADMAP_VERSION 0x0000 +/* segment mappings for ELF FDPIC libraries/executables/interpreters */ +struct elf64_fdpic_loadseg { + Elf64_Addr addr; /* core address to which mapped */ + Elf64_Addr p_vaddr; /* VMA recorded in file */ + Elf64_Word p_memsz; /* allocation size recorded in file */ +}; + +struct elf64_fdpic_loadmap { + Elf64_Half version; /* version of these structures, just in case... */ + Elf64_Half nsegs; /* number of segments */ + struct elf64_fdpic_loadseg segs[]; +}; + +#define ELF64_FDPIC_LOADMAP_VERSION 0x0000 + #endif /* _UAPI_LINUX_ELF_FDPIC_H */ -- cgit v1.2.3