Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v6.17 111 lines 2.6 kB view raw
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}