memconsole.c 4.0 KB

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