ANDROID: KVM: arm64: RAW interface to the nVHE hyp tracing

This interface intends to be used by userspace tools to store raw
version of events. In such case, the kernel does not decode anything.

Bug: 229972309
Change-Id: Ib1fca21a34a308ad1361240ef598033ecab3b4ad
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
This commit is contained in:
Vincent Donnefort
2022-10-17 13:50:45 +01:00
parent 089c9082c2
commit a7640ce6cf
3 changed files with 98 additions and 14 deletions

View File

@@ -641,6 +641,85 @@ static const struct file_operations hyp_trace_pipe_fops = {
.llseek = no_llseek,
};
static ssize_t
hyp_trace_raw_read(struct file *file, char __user *ubuf,
size_t cnt, loff_t *ppos)
{
struct ht_iterator *iter = (struct ht_iterator *)file->private_data;
struct trace_buffer *trace_buffer = iter->trace_buffer;
size_t size;
int ret;
if (iter->copy_leftover)
goto read;
again:
hyp_trace_read_start(iter->cpu);
ret = ring_buffer_read_page(trace_buffer, &iter->spare,
cnt, iter->cpu, 0);
hyp_trace_read_stop(iter->cpu);
if (ret < 0) {
if (!ring_buffer_empty_cpu(iter->trace_buffer, iter->cpu))
return 0;
ret = ring_buffer_wait(trace_buffer, iter->cpu, 0);
if (ret < 0)
return ret;
goto again;
}
iter->copy_leftover = 0;
read:
size = PAGE_SIZE - iter->copy_leftover;
if (size > cnt)
size = cnt;
ret = copy_to_user(ubuf, iter->spare + PAGE_SIZE - size, size);
if (ret == size)
return -EFAULT;
size -= ret;
*ppos += size;
iter->copy_leftover = ret;
return size;
}
static int hyp_trace_raw_open(struct inode *inode, struct file *file)
{
int ret = hyp_trace_pipe_open(inode, file);
struct ht_iterator *iter;
if (ret)
return ret;
iter = file->private_data;
iter->spare = ring_buffer_alloc_read_page(iter->trace_buffer, iter->cpu);
if (IS_ERR(iter->spare)) {
ret = PTR_ERR(iter->spare);
iter->spare = NULL;
return ret;
}
return 0;
}
static int hyp_trace_raw_release(struct inode *inode, struct file *file)
{
struct ht_iterator *iter = file->private_data;
ring_buffer_free_read_page(iter->trace_buffer, iter->cpu, iter->spare);
return hyp_trace_pipe_release(inode, file);
}
static const struct file_operations hyp_trace_raw_fops = {
.open = hyp_trace_raw_open,
.read = hyp_trace_raw_read,
.release = hyp_trace_raw_release,
.llseek = no_llseek,
};
static void hyp_tracefs_create_cpu_file(const char *file_name,
unsigned long cpu,
const struct file_operations *fops,
@@ -700,6 +779,8 @@ int init_hyp_tracefs(void)
hyp_tracefs_create_cpu_file("trace", cpu, &hyp_trace_fops, dir);
hyp_tracefs_create_cpu_file("trace_pipe", cpu,
&hyp_trace_pipe_fops, dir);
hyp_tracefs_create_cpu_file("trace_pipe_raw", cpu,
&hyp_trace_raw_fops, dir);
}
kvm_hyp_init_events_tracefs(root_dir);

View File

@@ -12,6 +12,8 @@ struct ht_iterator {
struct hyp_entry_hdr *ent;
struct trace_seq seq;
u64 ts;
void *spare;
size_t copy_leftover;
size_t ent_size;
struct delayed_work poke_work;
unsigned long lost_events;

View File

@@ -5729,9 +5729,6 @@ void *ring_buffer_alloc_read_page(struct trace_buffer *buffer, int cpu)
unsigned long flags;
struct page *page;
if (unlikely(has_ext_writer(buffer)))
return ERR_PTR(-EINVAL);
if (!cpumask_test_cpu(cpu, buffer->cpumask))
return ERR_PTR(-ENODEV);
@@ -5846,9 +5843,6 @@ int ring_buffer_read_page(struct trace_buffer *buffer,
u64 save_timestamp;
int ret = -1;
if (unlikely(has_ext_writer(buffer)))
goto out;
if (!cpumask_test_cpu(cpu, buffer->cpumask))
goto out;
@@ -5955,14 +5949,21 @@ int ring_buffer_read_page(struct trace_buffer *buffer,
cpu_buffer->read += rb_page_entries(reader);
cpu_buffer->read_bytes += BUF_PAGE_SIZE;
/* swap the pages */
rb_init_page(bpage);
bpage = reader->page;
reader->page = *data_page;
local_set(&reader->write, 0);
local_set(&reader->entries, 0);
reader->read = 0;
*data_page = bpage;
if (unlikely(has_ext_writer(buffer))) {
u64 commit = local_read(&reader->page->commit);
memcpy(bpage, reader->page,
BUF_PAGE_HDR_SIZE + commit);
} else {
/* swap the pages */
rb_init_page(bpage);
bpage = reader->page;
reader->page = *data_page;
local_set(&reader->write, 0);
local_set(&reader->entries, 0);
reader->read = 0;
*data_page = bpage;
}
/*
* Use the real_end for the data size,