Path: blob/master/drivers/firmware/google/memconsole.c
15112 views
/*1* memconsole.c2*3* Infrastructure for importing the BIOS memory based console4* into the kernel log ringbuffer.5*6* Copyright 2010 Google Inc. All rights reserved.7*/89#include <linux/ctype.h>10#include <linux/init.h>11#include <linux/kernel.h>12#include <linux/string.h>13#include <linux/sysfs.h>14#include <linux/kobject.h>15#include <linux/module.h>16#include <linux/dmi.h>17#include <asm/bios_ebda.h>1819#define BIOS_MEMCONSOLE_V1_MAGIC 0xDEADBABE20#define BIOS_MEMCONSOLE_V2_MAGIC (('M')|('C'<<8)|('O'<<16)|('N'<<24))2122struct biosmemcon_ebda {23u32 signature;24union {25struct {26u8 enabled;27u32 buffer_addr;28u16 start;29u16 end;30u16 num_chars;31u8 wrapped;32} __packed v1;33struct {34u32 buffer_addr;35/* Misdocumented as number of pages! */36u16 num_bytes;37u16 start;38u16 end;39} __packed v2;40};41} __packed;4243static char *memconsole_baseaddr;44static size_t memconsole_length;4546static ssize_t memconsole_read(struct file *filp, struct kobject *kobp,47struct bin_attribute *bin_attr, char *buf,48loff_t pos, size_t count)49{50return memory_read_from_buffer(buf, count, &pos, memconsole_baseaddr,51memconsole_length);52}5354static struct bin_attribute memconsole_bin_attr = {55.attr = {.name = "log", .mode = 0444},56.read = memconsole_read,57};585960static void found_v1_header(struct biosmemcon_ebda *hdr)61{62printk(KERN_INFO "BIOS console v1 EBDA structure found at %p\n", hdr);63printk(KERN_INFO "BIOS console buffer at 0x%.8x, "64"start = %d, end = %d, num = %d\n",65hdr->v1.buffer_addr, hdr->v1.start,66hdr->v1.end, hdr->v1.num_chars);6768memconsole_length = hdr->v1.num_chars;69memconsole_baseaddr = phys_to_virt(hdr->v1.buffer_addr);70}7172static void found_v2_header(struct biosmemcon_ebda *hdr)73{74printk(KERN_INFO "BIOS console v2 EBDA structure found at %p\n", hdr);75printk(KERN_INFO "BIOS console buffer at 0x%.8x, "76"start = %d, end = %d, num_bytes = %d\n",77hdr->v2.buffer_addr, hdr->v2.start,78hdr->v2.end, hdr->v2.num_bytes);7980memconsole_length = hdr->v2.end - hdr->v2.start;81memconsole_baseaddr = phys_to_virt(hdr->v2.buffer_addr82+ hdr->v2.start);83}8485/*86* Search through the EBDA for the BIOS Memory Console, and87* set the global variables to point to it. Return true if found.88*/89static bool found_memconsole(void)90{91unsigned int address;92size_t length, cur;9394address = get_bios_ebda();95if (!address) {96printk(KERN_INFO "BIOS EBDA non-existent.\n");97return false;98}99100/* EBDA length is byte 0 of EBDA (in KB) */101length = *(u8 *)phys_to_virt(address);102length <<= 10; /* convert to bytes */103104/*105* Search through EBDA for BIOS memory console structure106* note: signature is not necessarily dword-aligned107*/108for (cur = 0; cur < length; cur++) {109struct biosmemcon_ebda *hdr = phys_to_virt(address + cur);110111/* memconsole v1 */112if (hdr->signature == BIOS_MEMCONSOLE_V1_MAGIC) {113found_v1_header(hdr);114return true;115}116117/* memconsole v2 */118if (hdr->signature == BIOS_MEMCONSOLE_V2_MAGIC) {119found_v2_header(hdr);120return true;121}122}123124printk(KERN_INFO "BIOS console EBDA structure not found!\n");125return false;126}127128static struct dmi_system_id memconsole_dmi_table[] __initdata = {129{130.ident = "Google Board",131.matches = {132DMI_MATCH(DMI_BOARD_VENDOR, "Google, Inc."),133},134},135{}136};137MODULE_DEVICE_TABLE(dmi, memconsole_dmi_table);138139static int __init memconsole_init(void)140{141int ret;142143if (!dmi_check_system(memconsole_dmi_table))144return -ENODEV;145146if (!found_memconsole())147return -ENODEV;148149memconsole_bin_attr.size = memconsole_length;150151ret = sysfs_create_bin_file(firmware_kobj, &memconsole_bin_attr);152153return ret;154}155156static void __exit memconsole_exit(void)157{158sysfs_remove_bin_file(firmware_kobj, &memconsole_bin_attr);159}160161module_init(memconsole_init);162module_exit(memconsole_exit);163164MODULE_AUTHOR("Google, Inc.");165MODULE_LICENSE("GPL");166167168