0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012 #include <linux/dmi.h>
0013 #include <linux/mm.h>
0014 #include <asm/bios_ebda.h>
0015 #include <linux/acpi.h>
0016
0017 #include "memconsole.h"
0018
0019 #define BIOS_MEMCONSOLE_V1_MAGIC 0xDEADBABE
0020 #define BIOS_MEMCONSOLE_V2_MAGIC (('M')|('C'<<8)|('O'<<16)|('N'<<24))
0021
0022 struct biosmemcon_ebda {
0023 u32 signature;
0024 union {
0025 struct {
0026 u8 enabled;
0027 u32 buffer_addr;
0028 u16 start;
0029 u16 end;
0030 u16 num_chars;
0031 u8 wrapped;
0032 } __packed v1;
0033 struct {
0034 u32 buffer_addr;
0035
0036 u16 num_bytes;
0037 u16 start;
0038 u16 end;
0039 } __packed v2;
0040 };
0041 } __packed;
0042
0043 static char *memconsole_baseaddr;
0044 static size_t memconsole_length;
0045
0046 static ssize_t memconsole_read(char *buf, loff_t pos, size_t count)
0047 {
0048 return memory_read_from_buffer(buf, count, &pos, memconsole_baseaddr,
0049 memconsole_length);
0050 }
0051
0052 static void found_v1_header(struct biosmemcon_ebda *hdr)
0053 {
0054 pr_info("memconsole: BIOS console v1 EBDA structure found at %p\n",
0055 hdr);
0056 pr_info("memconsole: BIOS console buffer at 0x%.8x, start = %d, end = %d, num = %d\n",
0057 hdr->v1.buffer_addr, hdr->v1.start,
0058 hdr->v1.end, hdr->v1.num_chars);
0059
0060 memconsole_baseaddr = phys_to_virt(hdr->v1.buffer_addr);
0061 memconsole_length = hdr->v1.num_chars;
0062 memconsole_setup(memconsole_read);
0063 }
0064
0065 static void found_v2_header(struct biosmemcon_ebda *hdr)
0066 {
0067 pr_info("memconsole: BIOS console v2 EBDA structure found at %p\n",
0068 hdr);
0069 pr_info("memconsole: BIOS console buffer at 0x%.8x, start = %d, end = %d, num_bytes = %d\n",
0070 hdr->v2.buffer_addr, hdr->v2.start,
0071 hdr->v2.end, hdr->v2.num_bytes);
0072
0073 memconsole_baseaddr = phys_to_virt(hdr->v2.buffer_addr + hdr->v2.start);
0074 memconsole_length = hdr->v2.end - hdr->v2.start;
0075 memconsole_setup(memconsole_read);
0076 }
0077
0078
0079
0080
0081
0082 static bool memconsole_ebda_init(void)
0083 {
0084 unsigned int address;
0085 size_t length, cur;
0086
0087 address = get_bios_ebda();
0088 if (!address) {
0089 pr_info("memconsole: BIOS EBDA non-existent.\n");
0090 return false;
0091 }
0092
0093
0094 length = *(u8 *)phys_to_virt(address);
0095 length <<= 10;
0096
0097
0098
0099
0100
0101 for (cur = 0; cur < length; cur++) {
0102 struct biosmemcon_ebda *hdr = phys_to_virt(address + cur);
0103
0104
0105 if (hdr->signature == BIOS_MEMCONSOLE_V1_MAGIC) {
0106 found_v1_header(hdr);
0107 return true;
0108 }
0109
0110
0111 if (hdr->signature == BIOS_MEMCONSOLE_V2_MAGIC) {
0112 found_v2_header(hdr);
0113 return true;
0114 }
0115 }
0116
0117 pr_info("memconsole: BIOS console EBDA structure not found!\n");
0118 return false;
0119 }
0120
0121 static const struct dmi_system_id memconsole_dmi_table[] __initconst = {
0122 {
0123 .ident = "Google Board",
0124 .matches = {
0125 DMI_MATCH(DMI_BOARD_VENDOR, "Google, Inc."),
0126 },
0127 },
0128 {}
0129 };
0130 MODULE_DEVICE_TABLE(dmi, memconsole_dmi_table);
0131
0132 static bool __init memconsole_find(void)
0133 {
0134 if (!dmi_check_system(memconsole_dmi_table))
0135 return false;
0136
0137 return memconsole_ebda_init();
0138 }
0139
0140 static int __init memconsole_x86_init(void)
0141 {
0142 if (!memconsole_find())
0143 return -ENODEV;
0144
0145 return memconsole_sysfs_init();
0146 }
0147
0148 static void __exit memconsole_x86_exit(void)
0149 {
0150 memconsole_exit();
0151 }
0152
0153 module_init(memconsole_x86_init);
0154 module_exit(memconsole_x86_exit);
0155
0156 MODULE_AUTHOR("Google, Inc.");
0157 MODULE_LICENSE("GPL");