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 15 struct 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 27 static struct ovmf_debug_log_header *hdr; 28 static u8 *logbuf; 29 static u64 logbufsize; 30 31 static 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 59 static 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 67 int __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 108 err_unmap: 109 memunmap(hdr); 110 return ret; 111 } 112