ANDROID: KVM: arm64: add hyp_trace_printk to redirect hyp tracing to printk This option is the hypervisor equivalent of tp_printk. This intends for debug only and can't be disabled once set in the command line. Bug: 357781595 Change-Id: I101985288d79dc8988f9599dcb7c50e4902f9a79 Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
diff --git a/arch/arm64/include/asm/kvm_hyptrace.h b/arch/arm64/include/asm/kvm_hyptrace.h index 7b66bd0..09b7b08 100644 --- a/arch/arm64/include/asm/kvm_hyptrace.h +++ b/arch/arm64/include/asm/kvm_hyptrace.h
@@ -8,7 +8,7 @@ #include <linux/workqueue.h> struct ht_iterator { - struct trace_buffer *trace_buffer; + struct hyp_trace_buffer *hyp_buffer; int cpu; struct hyp_entry_hdr *ent; unsigned long lost_events;
diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c index 5e39e92..cca2e4c 100644 --- a/arch/arm64/kvm/hyp_trace.c +++ b/arch/arm64/kvm/hyp_trace.c
@@ -46,6 +46,8 @@ static struct hyp_trace_buffer { int nr_readers; struct mutex lock; struct hyp_trace_clock clock; + struct ht_iterator *printk_iter; + bool printk_on; } hyp_trace_buffer = { .lock = __MUTEX_INITIALIZER(hyp_trace_buffer.lock), }; @@ -92,6 +94,15 @@ bpage_backing_free(struct hyp_buffer_pages_backing *bpage_backing) free_pages_exact((void *)bpage_backing->start, bpage_backing->size); } +static int set_ht_printk_on(char *str) +{ + if ((strcmp(str, "=0") != 0 && strcmp(str, "=off") != 0)) + hyp_trace_buffer.printk_on = true; + + return 1; +} +__setup("hyp_trace_printk", set_ht_printk_on); + static void __hyp_clock_work(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); @@ -582,16 +593,17 @@ static int ht_print_trace_fmt(struct ht_iterator *iter) static struct ring_buffer_event *__ht_next_pipe_event(struct ht_iterator *iter) { + struct trace_buffer *trace_buffer = iter->hyp_buffer->trace_buffer; struct ring_buffer_event *evt = NULL; int cpu = iter->cpu; if (cpu != RING_BUFFER_ALL_CPUS) { - if (ring_buffer_empty_cpu(iter->trace_buffer, cpu)) + if (ring_buffer_empty_cpu(trace_buffer, cpu)) return NULL; iter->ent_cpu = cpu; - return ring_buffer_peek(iter->trace_buffer, cpu, &iter->ts, + return ring_buffer_peek(trace_buffer, cpu, &iter->ts, &iter->lost_events); } @@ -601,10 +613,10 @@ static struct ring_buffer_event *__ht_next_pipe_event(struct ht_iterator *iter) unsigned long lost_events; u64 ts; - if (ring_buffer_empty_cpu(iter->trace_buffer, cpu)) + if (ring_buffer_empty_cpu(trace_buffer, cpu)) continue; - _evt = ring_buffer_peek(iter->trace_buffer, cpu, &ts, + _evt = ring_buffer_peek(trace_buffer, cpu, &ts, &lost_events); if (!_evt) continue; @@ -640,6 +652,7 @@ hyp_trace_pipe_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->hyp_buffer->trace_buffer; int ret; copy_to_user: @@ -649,7 +662,7 @@ hyp_trace_pipe_read(struct file *file, char __user *ubuf, trace_seq_init(&iter->seq); - ret = ring_buffer_wait(iter->trace_buffer, iter->cpu, 0, NULL, NULL); + ret = ring_buffer_wait(trace_buffer, iter->cpu, 0, NULL, NULL); if (ret < 0) return ret; @@ -661,13 +674,14 @@ hyp_trace_pipe_read(struct file *file, char __user *ubuf, break; } - ring_buffer_consume(iter->trace_buffer, iter->ent_cpu, NULL, - NULL); + ring_buffer_consume(trace_buffer, iter->ent_cpu, NULL, NULL); } goto copy_to_user; } +static void hyp_trace_buffer_printk(struct hyp_trace_buffer *hyp_buffer); + static void __poll_writer(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); @@ -675,20 +689,21 @@ static void __poll_writer(struct work_struct *work) iter = container_of(dwork, struct ht_iterator, poll_work); - ring_buffer_poll_writer(iter->trace_buffer, iter->cpu); + ring_buffer_poll_writer(iter->hyp_buffer->trace_buffer, iter->cpu); + + hyp_trace_buffer_printk(iter->hyp_buffer); schedule_delayed_work((struct delayed_work *)work, msecs_to_jiffies(RB_POLL_MS)); } -static int hyp_trace_pipe_open(struct inode *inode, struct file *file) +static struct ht_iterator * +ht_iterator_create(struct hyp_trace_buffer *hyp_buffer, int cpu) { - struct hyp_trace_buffer *hyp_buffer = &hyp_trace_buffer; - int cpu = (s64)inode->i_private; struct ht_iterator *iter = NULL; int ret; - mutex_lock(&hyp_buffer->lock); + WARN_ON(!mutex_is_locked(&hyp_buffer->lock)); if (hyp_buffer->nr_readers == INT_MAX) { ret = -EBUSY; @@ -704,10 +719,9 @@ static int hyp_trace_pipe_open(struct inode *inode, struct file *file) ret = -ENOMEM; goto unlock; } - iter->trace_buffer = hyp_buffer->trace_buffer; + iter->hyp_buffer = hyp_buffer; iter->cpu = cpu; trace_seq_init(&iter->seq); - file->private_data = iter; ret = ring_buffer_poll_writer(hyp_buffer->trace_buffer, cpu); if (ret) @@ -722,11 +736,24 @@ static int hyp_trace_pipe_open(struct inode *inode, struct file *file) if (ret) { hyp_trace_buffer_teardown(hyp_buffer); kfree(iter); + iter = NULL; } + return iter; +} + +static int hyp_trace_pipe_open(struct inode *inode, struct file *file) +{ + struct hyp_trace_buffer *hyp_buffer = &hyp_trace_buffer; + int cpu = (s64)inode->i_private; + + mutex_lock(&hyp_buffer->lock); + + file->private_data = ht_iterator_create(hyp_buffer, cpu); + mutex_unlock(&hyp_buffer->lock); - return ret; + return file->private_data ? 0 : -EINVAL; } static int hyp_trace_pipe_release(struct inode *inode, struct file *file) @@ -768,15 +795,16 @@ hyp_trace_raw_read(struct file *file, char __user *ubuf, goto read; again: - ret = ring_buffer_read_page(iter->trace_buffer, + ret = ring_buffer_read_page(iter->hyp_buffer->trace_buffer, (struct buffer_data_read_page *)iter->spare, cnt, iter->cpu, 0); if (ret < 0) { - if (!ring_buffer_empty_cpu(iter->trace_buffer, iter->cpu)) + if (!ring_buffer_empty_cpu(iter->hyp_buffer->trace_buffer, + iter->cpu)) return 0; - ret = ring_buffer_wait(iter->trace_buffer, iter->cpu, 0, NULL, - NULL); + ret = ring_buffer_wait(iter->hyp_buffer->trace_buffer, + iter->cpu, 0, NULL, NULL); if (ret < 0) return ret; @@ -810,7 +838,8 @@ static int hyp_trace_raw_open(struct inode *inode, struct file *file) return ret; iter = file->private_data; - iter->spare = ring_buffer_alloc_read_page(iter->trace_buffer, iter->cpu); + iter->spare = ring_buffer_alloc_read_page(iter->hyp_buffer->trace_buffer, + iter->cpu); if (IS_ERR(iter->spare)) { ret = PTR_ERR(iter->spare); iter->spare = NULL; @@ -824,7 +853,8 @@ 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); + ring_buffer_free_read_page(iter->hyp_buffer->trace_buffer, iter->cpu, + iter->spare); return hyp_trace_pipe_release(inode, file); } @@ -917,6 +947,49 @@ static void hyp_trace_init_testing_tracefs(struct dentry *root) static void hyp_trace_init_testing_tracefs(struct dentry *root) { } #endif +static int hyp_trace_buffer_printk_init(struct hyp_trace_buffer *hyp_buffer) +{ + int ret = 0; + + mutex_lock(&hyp_buffer->lock); + + if (hyp_buffer->printk_iter) + goto unlock; + + hyp_buffer->printk_iter = ht_iterator_create(hyp_buffer, + RING_BUFFER_ALL_CPUS); + if (!hyp_buffer->printk_iter) + ret = -EINVAL; +unlock: + mutex_unlock(&hyp_buffer->lock); + + return ret; +} + +static void hyp_trace_buffer_printk(struct hyp_trace_buffer *hyp_buffer) +{ + struct ht_iterator *ht_iter = hyp_buffer->printk_iter; + + if (!hyp_trace_buffer.printk_on) + return; + + trace_seq_init(&ht_iter->seq); + while (ht_next_pipe_event(ht_iter)) { + ht_print_trace_fmt(ht_iter); + + /* Nothing has been written in the seq_buf */ + if (!ht_iter->seq.seq.len) + return; + + ht_iter->seq.buffer[ht_iter->seq.seq.len] = '\0'; + printk("%s", ht_iter->seq.buffer); + + ht_iter->seq.seq.len = 0; + ring_buffer_consume(hyp_buffer->trace_buffer, ht_iter->ent_cpu, + NULL, NULL); + } +} + int hyp_trace_init_tracefs(void) { struct dentry *root, *per_cpu_root; @@ -978,6 +1051,10 @@ int hyp_trace_init_tracefs(void) hyp_trace_init_event_tracefs(root); hyp_trace_init_testing_tracefs(root); + if (hyp_trace_buffer.printk_on && + hyp_trace_buffer_printk_init(&hyp_trace_buffer)) + pr_warn("Failed to init ht_printk"); + if (hyp_trace_init_event_early()) { err = hyp_trace_start(); if (err)