|
@@ -1575,6 +1575,9 @@ static void __perf_event_header_size(struct perf_event *event, u64 sample_type)
|
|
|
if (sample_type & PERF_SAMPLE_TRANSACTION)
|
|
|
size += sizeof(data->txn);
|
|
|
|
|
|
+ if (sample_type & PERF_SAMPLE_PHYS_ADDR)
|
|
|
+ size += sizeof(data->phys_addr);
|
|
|
+
|
|
|
event->header_size = size;
|
|
|
}
|
|
|
|
|
@@ -6017,6 +6020,9 @@ void perf_output_sample(struct perf_output_handle *handle,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if (sample_type & PERF_SAMPLE_PHYS_ADDR)
|
|
|
+ perf_output_put(handle, data->phys_addr);
|
|
|
+
|
|
|
if (!event->attr.watermark) {
|
|
|
int wakeup_events = event->attr.wakeup_events;
|
|
|
|
|
@@ -6032,6 +6038,38 @@ void perf_output_sample(struct perf_output_handle *handle,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static u64 perf_virt_to_phys(u64 virt)
|
|
|
+{
|
|
|
+ u64 phys_addr = 0;
|
|
|
+ struct page *p = NULL;
|
|
|
+
|
|
|
+ if (!virt)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (virt >= TASK_SIZE) {
|
|
|
+ /* If it's vmalloc()d memory, leave phys_addr as 0 */
|
|
|
+ if (virt_addr_valid((void *)(uintptr_t)virt) &&
|
|
|
+ !(virt >= VMALLOC_START && virt < VMALLOC_END))
|
|
|
+ phys_addr = (u64)virt_to_phys((void *)(uintptr_t)virt);
|
|
|
+ } else {
|
|
|
+ /*
|
|
|
+ * Walking the pages tables for user address.
|
|
|
+ * Interrupts are disabled, so it prevents any tear down
|
|
|
+ * of the page tables.
|
|
|
+ * Try IRQ-safe __get_user_pages_fast first.
|
|
|
+ * If failed, leave phys_addr as 0.
|
|
|
+ */
|
|
|
+ if ((current->mm != NULL) &&
|
|
|
+ (__get_user_pages_fast(virt, 1, 0, &p) == 1))
|
|
|
+ phys_addr = page_to_phys(p) + virt % PAGE_SIZE;
|
|
|
+
|
|
|
+ if (p)
|
|
|
+ put_page(p);
|
|
|
+ }
|
|
|
+
|
|
|
+ return phys_addr;
|
|
|
+}
|
|
|
+
|
|
|
void perf_prepare_sample(struct perf_event_header *header,
|
|
|
struct perf_sample_data *data,
|
|
|
struct perf_event *event,
|
|
@@ -6150,6 +6188,9 @@ void perf_prepare_sample(struct perf_event_header *header,
|
|
|
|
|
|
header->size += size;
|
|
|
}
|
|
|
+
|
|
|
+ if (sample_type & PERF_SAMPLE_PHYS_ADDR)
|
|
|
+ data->phys_addr = perf_virt_to_phys(data->addr);
|
|
|
}
|
|
|
|
|
|
static void __always_inline
|
|
@@ -9909,6 +9950,11 @@ SYSCALL_DEFINE5(perf_event_open,
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
+ /* Only privileged users can get physical addresses */
|
|
|
+ if ((attr.sample_type & PERF_SAMPLE_PHYS_ADDR) &&
|
|
|
+ perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN))
|
|
|
+ return -EACCES;
|
|
|
+
|
|
|
if (!attr.sample_max_stack)
|
|
|
attr.sample_max_stack = sysctl_perf_event_max_stack;
|
|
|
|