memconsole.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /*
  2. * memconsole.c
  3. *
  4. * Infrastructure for importing the BIOS memory based console
  5. * into the kernel log ringbuffer.
  6. *
  7. * Copyright 2010 Google Inc. All rights reserved.
  8. */
  9. #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>
  18. #define BIOS_MEMCONSOLE_V1_MAGIC 0xDEADBABE
  19. #define BIOS_MEMCONSOLE_V2_MAGIC (('M')|('C'<<8)|('O'<<16)|('N'<<24))
  20. struct biosmemcon_ebda {
  21. u32 signature;
  22. union {
  23. struct {
  24. u8 enabled;
  25. u32 buffer_addr;
  26. u16 start;
  27. u16 end;
  28. u16 num_chars;
  29. u8 wrapped;
  30. } __packed v1;
  31. struct {
  32. u32 buffer_addr;
  33. /* Misdocumented as number of pages! */
  34. u16 num_bytes;
  35. u16 start;
  36. u16 end;
  37. } __packed v2;
  38. };
  39. } __packed;
  40. static char *memconsole_baseaddr;
  41. static size_t memconsole_length;
  42. static ssize_t memconsole_read(struct file *filp, struct kobject *kobp,
  43. struct bin_attribute *bin_attr, char *buf,
  44. loff_t pos, size_t count)
  45. {
  46. return memory_read_from_buffer(buf, count, &pos, memconsole_baseaddr,
  47. memconsole_length);
  48. }
  49. static struct bin_attribute memconsole_bin_attr = {
  50. .attr = {.name = "log", .mode = 0444},
  51. .read = memconsole_read,
  52. };
  53. static void found_v1_header(struct biosmemcon_ebda *hdr)
  54. {
  55. printk(KERN_INFO "BIOS console v1 EBDA structure found at %p\n", hdr);
  56. printk(KERN_INFO "BIOS console buffer at 0x%.8x, "
  57. "start = %d, end = %d, num = %d\n",
  58. hdr->v1.buffer_addr, hdr->v1.start,
  59. hdr->v1.end, hdr->v1.num_chars);
  60. memconsole_length = hdr->v1.num_chars;
  61. memconsole_baseaddr = phys_to_virt(hdr->v1.buffer_addr);
  62. }
  63. static void found_v2_header(struct biosmemcon_ebda *hdr)
  64. {
  65. printk(KERN_INFO "BIOS console v2 EBDA structure found at %p\n", hdr);
  66. printk(KERN_INFO "BIOS console buffer at 0x%.8x, "
  67. "start = %d, end = %d, num_bytes = %d\n",
  68. hdr->v2.buffer_addr, hdr->v2.start,
  69. hdr->v2.end, hdr->v2.num_bytes);
  70. memconsole_length = hdr->v2.end - hdr->v2.start;
  71. memconsole_baseaddr = phys_to_virt(hdr->v2.buffer_addr
  72. + hdr->v2.start);
  73. }
  74. /*
  75. * Search through the EBDA for the BIOS Memory Console, and
  76. * set the global variables to point to it. Return true if found.
  77. */
  78. static bool found_memconsole(void)
  79. {
  80. unsigned int address;
  81. size_t length, cur;
  82. address = get_bios_ebda();
  83. if (!address) {
  84. printk(KERN_INFO "BIOS EBDA non-existent.\n");
  85. return false;
  86. }
  87. /* EBDA length is byte 0 of EBDA (in KB) */
  88. length = *(u8 *)phys_to_virt(address);
  89. length <<= 10; /* convert to bytes */
  90. /*
  91. * Search through EBDA for BIOS memory console structure
  92. * note: signature is not necessarily dword-aligned
  93. */
  94. for (cur = 0; cur < length; cur++) {
  95. struct biosmemcon_ebda *hdr = phys_to_virt(address + cur);
  96. /* memconsole v1 */
  97. if (hdr->signature == BIOS_MEMCONSOLE_V1_MAGIC) {
  98. found_v1_header(hdr);
  99. return true;
  100. }
  101. /* memconsole v2 */
  102. if (hdr->signature == BIOS_MEMCONSOLE_V2_MAGIC) {
  103. found_v2_header(hdr);
  104. return true;
  105. }
  106. }
  107. printk(KERN_INFO "BIOS console EBDA structure not found!\n");
  108. return false;
  109. }
  110. static struct dmi_system_id memconsole_dmi_table[] __initdata = {
  111. {
  112. .ident = "Google Board",
  113. .matches = {
  114. DMI_MATCH(DMI_BOARD_VENDOR, "Google, Inc."),
  115. },
  116. },
  117. {}
  118. };
  119. MODULE_DEVICE_TABLE(dmi, memconsole_dmi_table);
  120. static int __init memconsole_init(void)
  121. {
  122. int ret;
  123. if (!dmi_check_system(memconsole_dmi_table))
  124. return -ENODEV;
  125. if (!found_memconsole())
  126. return -ENODEV;
  127. memconsole_bin_attr.size = memconsole_length;
  128. ret = sysfs_create_bin_file(firmware_kobj, &memconsole_bin_attr);
  129. return ret;
  130. }
  131. static void __exit memconsole_exit(void)
  132. {
  133. sysfs_remove_bin_file(firmware_kobj, &memconsole_bin_attr);
  134. }
  135. module_init(memconsole_init);
  136. module_exit(memconsole_exit);
  137. MODULE_AUTHOR("Google, Inc.");
  138. MODULE_LICENSE("GPL");