Path: blob/master/drivers/firmware/efi/ovmf-debug-log.c
26428 views
// SPDX-License-Identifier: GPL-2.012#include <linux/efi.h>3#include <linux/init.h>4#include <linux/io.h>5#include <linux/kernel.h>6#include <linux/kobject.h>7#include <linux/module.h>8#include <linux/platform_device.h>9#include <linux/sysfs.h>1011#define OVMF_DEBUG_LOG_MAGIC1 0x3167646d666d766f // "ovmfmdg1"12#define OVMF_DEBUG_LOG_MAGIC2 0x3267646d666d766f // "ovmfmdg2"1314struct ovmf_debug_log_header {15u64 magic1;16u64 magic2;17u64 hdr_size;18u64 log_size;19u64 lock; // edk2 spinlock20u64 head_off;21u64 tail_off;22u64 truncated;23u8 fw_version[128];24};2526static struct ovmf_debug_log_header *hdr;27static u8 *logbuf;28static u64 logbufsize;2930static ssize_t ovmf_log_read(struct file *filp, struct kobject *kobj,31const struct bin_attribute *attr, char *buf,32loff_t offset, size_t count)33{34u64 start, end;3536start = hdr->head_off + offset;37if (hdr->head_off > hdr->tail_off && start >= hdr->log_size)38start -= hdr->log_size;3940end = start + count;41if (start > hdr->tail_off) {42if (end > hdr->log_size)43end = hdr->log_size;44} else {45if (end > hdr->tail_off)46end = hdr->tail_off;47}4849if (start > logbufsize || end > logbufsize)50return 0;51if (start >= end)52return 0;5354memcpy(buf, logbuf + start, end - start);55return end - start;56}5758static struct bin_attribute ovmf_log_bin_attr = {59.attr = {60.name = "ovmf_debug_log",61.mode = 0444,62},63.read = ovmf_log_read,64};6566int __init ovmf_log_probe(unsigned long ovmf_debug_log_table)67{68int ret = -EINVAL;69u64 size;7071/* map + verify header */72hdr = memremap(ovmf_debug_log_table, sizeof(*hdr), MEMREMAP_WB);73if (!hdr) {74pr_err("OVMF debug log: header map failed\n");75return -EINVAL;76}7778if (hdr->magic1 != OVMF_DEBUG_LOG_MAGIC1 ||79hdr->magic2 != OVMF_DEBUG_LOG_MAGIC2) {80printk(KERN_ERR "OVMF debug log: magic mismatch\n");81goto err_unmap;82}8384size = hdr->hdr_size + hdr->log_size;85pr_info("OVMF debug log: firmware version: \"%s\"\n", hdr->fw_version);86pr_info("OVMF debug log: buffer size: %lluk\n", size / 1024);8788/* map complete log buffer */89memunmap(hdr);90hdr = memremap(ovmf_debug_log_table, size, MEMREMAP_WB);91if (!hdr) {92pr_err("OVMF debug log: buffer map failed\n");93return -EINVAL;94}95logbuf = (void *)hdr + hdr->hdr_size;96logbufsize = hdr->log_size;9798ovmf_log_bin_attr.size = size;99ret = sysfs_create_bin_file(efi_kobj, &ovmf_log_bin_attr);100if (ret != 0) {101pr_err("OVMF debug log: sysfs register failed\n");102goto err_unmap;103}104105return 0;106107err_unmap:108memunmap(hdr);109return ret;110}111112113