1 /* 2 * memconsole-x86-legacy.c 3 * 4 * EBDA specific parts of the memory based BIOS console. 5 * 6 * Copyright 2017 Google Inc. 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License v2.0 as published by 10 * the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 */ 17 18 #include <linux/kernel.h> 19 #include <linux/module.h> 20 #include <linux/dmi.h> 21 #include <linux/mm.h> 22 #include <asm/bios_ebda.h> 23 #include <linux/acpi.h> 24 25 #include "memconsole.h" 26 27 #define BIOS_MEMCONSOLE_V1_MAGIC 0xDEADBABE 28 #define BIOS_MEMCONSOLE_V2_MAGIC (('M')|('C'<<8)|('O'<<16)|('N'<<24)) 29 30 struct biosmemcon_ebda { 31 u32 signature; 32 union { 33 struct { 34 u8 enabled; 35 u32 buffer_addr; 36 u16 start; 37 u16 end; 38 u16 num_chars; 39 u8 wrapped; 40 } __packed v1; 41 struct { 42 u32 buffer_addr; 43 /* Misdocumented as number of pages! */ 44 u16 num_bytes; 45 u16 start; 46 u16 end; 47 } __packed v2; 48 }; 49 } __packed; 50 51 static char *memconsole_baseaddr; 52 static size_t memconsole_length; 53 54 static ssize_t memconsole_read(char *buf, loff_t pos, size_t count) 55 { 56 return memory_read_from_buffer(buf, count, &pos, memconsole_baseaddr, 57 memconsole_length); 58 } 59 60 static void found_v1_header(struct biosmemcon_ebda *hdr) 61 { 62 pr_info("memconsole: BIOS console v1 EBDA structure found at %p\n", 63 hdr); 64 pr_info("memconsole: BIOS console buffer at 0x%.8x, start = %d, end = %d, num = %d\n", 65 hdr->v1.buffer_addr, hdr->v1.start, 66 hdr->v1.end, hdr->v1.num_chars); 67 68 memconsole_baseaddr = phys_to_virt(hdr->v1.buffer_addr); 69 memconsole_length = hdr->v1.num_chars; 70 memconsole_setup(memconsole_read); 71 } 72 73 static void found_v2_header(struct biosmemcon_ebda *hdr) 74 { 75 pr_info("memconsole: BIOS console v2 EBDA structure found at %p\n", 76 hdr); 77 pr_info("memconsole: BIOS console buffer at 0x%.8x, start = %d, end = %d, num_bytes = %d\n", 78 hdr->v2.buffer_addr, hdr->v2.start, 79 hdr->v2.end, hdr->v2.num_bytes); 80 81 memconsole_baseaddr = phys_to_virt(hdr->v2.buffer_addr + hdr->v2.start); 82 memconsole_length = hdr->v2.end - hdr->v2.start; 83 memconsole_setup(memconsole_read); 84 } 85 86 /* 87 * Search through the EBDA for the BIOS Memory Console, and 88 * set the global variables to point to it. Return true if found. 89 */ 90 static bool memconsole_ebda_init(void) 91 { 92 unsigned int address; 93 size_t length, cur; 94 95 address = get_bios_ebda(); 96 if (!address) { 97 pr_info("memconsole: BIOS EBDA non-existent.\n"); 98 return false; 99 } 100 101 /* EBDA length is byte 0 of EBDA (in KB) */ 102 length = *(u8 *)phys_to_virt(address); 103 length <<= 10; /* convert to bytes */ 104 105 /* 106 * Search through EBDA for BIOS memory console structure 107 * note: signature is not necessarily dword-aligned 108 */ 109 for (cur = 0; cur < length; cur++) { 110 struct biosmemcon_ebda *hdr = phys_to_virt(address + cur); 111 112 /* memconsole v1 */ 113 if (hdr->signature == BIOS_MEMCONSOLE_V1_MAGIC) { 114 found_v1_header(hdr); 115 return true; 116 } 117 118 /* memconsole v2 */ 119 if (hdr->signature == BIOS_MEMCONSOLE_V2_MAGIC) { 120 found_v2_header(hdr); 121 return true; 122 } 123 } 124 125 pr_info("memconsole: BIOS console EBDA structure not found!\n"); 126 return false; 127 } 128 129 static const struct dmi_system_id memconsole_dmi_table[] __initconst = { 130 { 131 .ident = "Google Board", 132 .matches = { 133 DMI_MATCH(DMI_BOARD_VENDOR, "Google, Inc."), 134 }, 135 }, 136 {} 137 }; 138 MODULE_DEVICE_TABLE(dmi, memconsole_dmi_table); 139 140 static bool __init memconsole_find(void) 141 { 142 if (!dmi_check_system(memconsole_dmi_table)) 143 return false; 144 145 return memconsole_ebda_init(); 146 } 147 148 static int __init memconsole_x86_init(void) 149 { 150 if (!memconsole_find()) 151 return -ENODEV; 152 153 return memconsole_sysfs_init(); 154 } 155 156 static void __exit memconsole_x86_exit(void) 157 { 158 memconsole_exit(); 159 } 160 161 module_init(memconsole_x86_init); 162 module_exit(memconsole_x86_exit); 163 164 MODULE_AUTHOR("Google, Inc."); 165 MODULE_LICENSE("GPL"); 166