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>
18 #include <asm/bios_ebda.h>
20 #define BIOS_MEMCONSOLE_V1_MAGIC 0xDEADBABE
21 #define BIOS_MEMCONSOLE_V2_MAGIC (('M')|('C'<<8)|('O'<<16)|('N'<<24))
23 struct biosmemcon_ebda
{
36 /* Misdocumented as number of pages! */
44 static char *memconsole_baseaddr
;
45 static size_t memconsole_length
;
47 static ssize_t
memconsole_read(struct file
*filp
, struct kobject
*kobp
,
48 struct bin_attribute
*bin_attr
, char *buf
,
49 loff_t pos
, size_t count
)
51 return memory_read_from_buffer(buf
, count
, &pos
, memconsole_baseaddr
,
55 static struct bin_attribute memconsole_bin_attr
= {
56 .attr
= {.name
= "log", .mode
= 0444},
57 .read
= memconsole_read
,
61 static void found_v1_header(struct biosmemcon_ebda
*hdr
)
63 printk(KERN_INFO
"BIOS console v1 EBDA structure found at %p\n", hdr
);
64 printk(KERN_INFO
"BIOS console buffer at 0x%.8x, "
65 "start = %d, end = %d, num = %d\n",
66 hdr
->v1
.buffer_addr
, hdr
->v1
.start
,
67 hdr
->v1
.end
, hdr
->v1
.num_chars
);
69 memconsole_length
= hdr
->v1
.num_chars
;
70 memconsole_baseaddr
= phys_to_virt(hdr
->v1
.buffer_addr
);
73 static void found_v2_header(struct biosmemcon_ebda
*hdr
)
75 printk(KERN_INFO
"BIOS console v2 EBDA structure found at %p\n", hdr
);
76 printk(KERN_INFO
"BIOS console buffer at 0x%.8x, "
77 "start = %d, end = %d, num_bytes = %d\n",
78 hdr
->v2
.buffer_addr
, hdr
->v2
.start
,
79 hdr
->v2
.end
, hdr
->v2
.num_bytes
);
81 memconsole_length
= hdr
->v2
.end
- hdr
->v2
.start
;
82 memconsole_baseaddr
= phys_to_virt(hdr
->v2
.buffer_addr
87 * Search through the EBDA for the BIOS Memory Console, and
88 * set the global variables to point to it. Return true if found.
90 static bool found_memconsole(void)
95 address
= get_bios_ebda();
97 printk(KERN_INFO
"BIOS EBDA non-existent.\n");
101 /* EBDA length is byte 0 of EBDA (in KB) */
102 length
= *(u8
*)phys_to_virt(address
);
103 length
<<= 10; /* convert to bytes */
106 * Search through EBDA for BIOS memory console structure
107 * note: signature is not necessarily dword-aligned
109 for (cur
= 0; cur
< length
; cur
++) {
110 struct biosmemcon_ebda
*hdr
= phys_to_virt(address
+ cur
);
113 if (hdr
->signature
== BIOS_MEMCONSOLE_V1_MAGIC
) {
114 found_v1_header(hdr
);
119 if (hdr
->signature
== BIOS_MEMCONSOLE_V2_MAGIC
) {
120 found_v2_header(hdr
);
125 printk(KERN_INFO
"BIOS console EBDA structure not found!\n");
129 static struct dmi_system_id memconsole_dmi_table
[] __initdata
= {
131 .ident
= "Google Board",
133 DMI_MATCH(DMI_BOARD_VENDOR
, "Google, Inc."),
138 MODULE_DEVICE_TABLE(dmi
, memconsole_dmi_table
);
140 static int __init
memconsole_init(void)
144 if (!dmi_check_system(memconsole_dmi_table
))
147 if (!found_memconsole())
150 memconsole_bin_attr
.size
= memconsole_length
;
152 ret
= sysfs_create_bin_file(firmware_kobj
, &memconsole_bin_attr
);
157 static void __exit
memconsole_exit(void)
159 sysfs_remove_bin_file(firmware_kobj
, &memconsole_bin_attr
);
162 module_init(memconsole_init
);
163 module_exit(memconsole_exit
);
165 MODULE_AUTHOR("Google, Inc.");
166 MODULE_LICENSE("GPL");