File Index
Files and directories
Sign in
FILE

ovmf-debug-log.c

File preview with syntax highlighting.

linux-6.19.14/drivers/firmware/efi/ovmf-debug-log.c C
  1// SPDX-License-Identifier: GPL-2.0
  2
  3#include <linux/efi.h>
  4#include <linux/init.h>
  5#include <linux/io.h>
  6#include <linux/kernel.h>
  7#include <linux/kobject.h>
  8#include <linux/module.h>
  9#include <linux/platform_device.h>
 10#include <linux/sysfs.h>
 11
 12#define OVMF_DEBUG_LOG_MAGIC1  0x3167646d666d766f  // "ovmfmdg1"
 13#define OVMF_DEBUG_LOG_MAGIC2  0x3267646d666d766f  // "ovmfmdg2"
 14
 15struct ovmf_debug_log_header {
 16	u64    magic1;
 17	u64    magic2;
 18	u64    hdr_size;
 19	u64    log_size;
 20	u64    lock; // edk2 spinlock
 21	u64    head_off;
 22	u64    tail_off;
 23	u64    truncated;
 24	u8     fw_version[128];
 25};
 26
 27static struct ovmf_debug_log_header *hdr;
 28static u8 *logbuf;
 29static u64 logbufsize;
 30
 31static ssize_t ovmf_log_read(struct file *filp, struct kobject *kobj,
 32			     const struct bin_attribute *attr, char *buf,
 33			     loff_t offset, size_t count)
 34{
 35	u64 start, end;
 36
 37	start = hdr->head_off + offset;
 38	if (hdr->head_off > hdr->tail_off && start >= hdr->log_size)
 39		start -= hdr->log_size;
 40
 41	end = start + count;
 42	if (start > hdr->tail_off) {
 43		if (end > hdr->log_size)
 44			end = hdr->log_size;
 45	} else {
 46		if (end > hdr->tail_off)
 47			end = hdr->tail_off;
 48	}
 49
 50	if (start > logbufsize || end > logbufsize)
 51		return 0;
 52	if (start >= end)
 53		return 0;
 54
 55	memcpy(buf, logbuf + start, end - start);
 56	return end - start;
 57}
 58
 59static struct bin_attribute ovmf_log_bin_attr = {
 60	.attr = {
 61		.name = "ovmf_debug_log",
 62		.mode = 0444,
 63	},
 64	.read = ovmf_log_read,
 65};
 66
 67int __init ovmf_log_probe(unsigned long ovmf_debug_log_table)
 68{
 69	int ret = -EINVAL;
 70	u64 size;
 71
 72	/* map + verify header */
 73	hdr = memremap(ovmf_debug_log_table, sizeof(*hdr), MEMREMAP_WB);
 74	if (!hdr) {
 75		pr_err("OVMF debug log: header map failed\n");
 76		return -EINVAL;
 77	}
 78
 79	if (hdr->magic1 != OVMF_DEBUG_LOG_MAGIC1 ||
 80	    hdr->magic2 != OVMF_DEBUG_LOG_MAGIC2) {
 81		printk(KERN_ERR "OVMF debug log: magic mismatch\n");
 82		goto err_unmap;
 83	}
 84
 85	size = hdr->hdr_size + hdr->log_size;
 86	pr_info("OVMF debug log: firmware version: \"%s\"\n", hdr->fw_version);
 87	pr_info("OVMF debug log: buffer size: %lluk\n", size / 1024);
 88
 89	/* map complete log buffer */
 90	memunmap(hdr);
 91	hdr = memremap(ovmf_debug_log_table, size, MEMREMAP_WB);
 92	if (!hdr) {
 93		pr_err("OVMF debug log: buffer map failed\n");
 94		return -EINVAL;
 95	}
 96	logbuf = (void *)hdr + hdr->hdr_size;
 97	logbufsize = hdr->log_size;
 98
 99	ovmf_log_bin_attr.size = size;
100	ret = sysfs_create_bin_file(efi_kobj, &ovmf_log_bin_attr);
101	if (ret != 0) {
102		pr_err("OVMF debug log: sysfs register failed\n");
103		goto err_unmap;
104	}
105
106	return 0;
107
108err_unmap:
109	memunmap(hdr);
110	return ret;
111}
~/ Read-only file preview.