4 * Infrastructure for importing the BIOS memory based console
5 * into the kernel log ringbuffer.
7 * Copyright 2010 Google Inc. All rights reserved.
10 #include <linux/ctype.h>
11 #include <linux/init.h>
12 #include <linux/kernel.h>
13 #include <linux/string.h>
14 #include <linux/sysfs.h>
15 #include <linux/kobject.h>
16 #include <linux/module.h>
17 #include <linux/dmi.h>
19 #include <asm/bios_ebda.h>
21 #define BIOS_MEMCONSOLE_V1_MAGIC 0xDEADBABE
22 #define BIOS_MEMCONSOLE_V2_MAGIC (('M')|('C'<<8)|('O'<<16)|('N'<<24))
24 struct biosmemcon_ebda
{
37 /* Misdocumented as number of pages! */
45 static u32 memconsole_baseaddr
;
46 static size_t memconsole_length
;
48 static ssize_t
memconsole_read(struct file
*filp
, struct kobject
*kobp
,
49 struct bin_attribute
*bin_attr
, char *buf
,
50 loff_t pos
, size_t count
)
55 memconsole
= ioremap_cache(memconsole_baseaddr
, memconsole_length
);
57 pr_err("memconsole: ioremap_cache failed\n");
60 ret
= memory_read_from_buffer(buf
, count
, &pos
, memconsole
,
66 static struct bin_attribute memconsole_bin_attr
= {
67 .attr
= {.name
= "log", .mode
= 0444},
68 .read
= memconsole_read
,
72 static void __init
found_v1_header(struct biosmemcon_ebda
*hdr
)
74 pr_info("BIOS console v1 EBDA structure found at %p\n", hdr
);
75 pr_info("BIOS console buffer at 0x%.8x, "
76 "start = %d, end = %d, num = %d\n",
77 hdr
->v1
.buffer_addr
, hdr
->v1
.start
,
78 hdr
->v1
.end
, hdr
->v1
.num_chars
);
80 memconsole_length
= hdr
->v1
.num_chars
;
81 memconsole_baseaddr
= hdr
->v1
.buffer_addr
;
84 static void __init
found_v2_header(struct biosmemcon_ebda
*hdr
)
86 pr_info("BIOS console v2 EBDA structure found at %p\n", hdr
);
87 pr_info("BIOS console buffer at 0x%.8x, "
88 "start = %d, end = %d, num_bytes = %d\n",
89 hdr
->v2
.buffer_addr
, hdr
->v2
.start
,
90 hdr
->v2
.end
, hdr
->v2
.num_bytes
);
92 memconsole_length
= hdr
->v2
.end
- hdr
->v2
.start
;
93 memconsole_baseaddr
= hdr
->v2
.buffer_addr
+ hdr
->v2
.start
;
97 * Search through the EBDA for the BIOS Memory Console, and
98 * set the global variables to point to it. Return true if found.
100 static bool __init
found_memconsole(void)
102 unsigned int address
;
105 address
= get_bios_ebda();
107 pr_info("BIOS EBDA non-existent.\n");
111 /* EBDA length is byte 0 of EBDA (in KB) */
112 length
= *(u8
*)phys_to_virt(address
);
113 length
<<= 10; /* convert to bytes */
116 * Search through EBDA for BIOS memory console structure
117 * note: signature is not necessarily dword-aligned
119 for (cur
= 0; cur
< length
; cur
++) {
120 struct biosmemcon_ebda
*hdr
= phys_to_virt(address
+ cur
);
123 if (hdr
->signature
== BIOS_MEMCONSOLE_V1_MAGIC
) {
124 found_v1_header(hdr
);
129 if (hdr
->signature
== BIOS_MEMCONSOLE_V2_MAGIC
) {
130 found_v2_header(hdr
);
135 pr_info("BIOS console EBDA structure not found!\n");
139 static struct dmi_system_id memconsole_dmi_table
[] __initdata
= {
141 .ident
= "Google Board",
143 DMI_MATCH(DMI_BOARD_VENDOR
, "Google, Inc."),
148 MODULE_DEVICE_TABLE(dmi
, memconsole_dmi_table
);
150 static int __init
memconsole_init(void)
152 if (!dmi_check_system(memconsole_dmi_table
))
155 if (!found_memconsole())
158 memconsole_bin_attr
.size
= memconsole_length
;
159 return sysfs_create_bin_file(firmware_kobj
, &memconsole_bin_attr
);
162 static void __exit
memconsole_exit(void)
164 sysfs_remove_bin_file(firmware_kobj
, &memconsole_bin_attr
);
167 module_init(memconsole_init
);
168 module_exit(memconsole_exit
);
170 MODULE_AUTHOR("Google, Inc.");
171 MODULE_LICENSE("GPL");