Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * memconsole-x86-legacy.c
0004  *
0005  * EBDA specific parts of the memory based BIOS console.
0006  *
0007  * Copyright 2017 Google Inc.
0008  */
0009 
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012 #include <linux/dmi.h>
0013 #include <linux/mm.h>
0014 #include <asm/bios_ebda.h>
0015 #include <linux/acpi.h>
0016 
0017 #include "memconsole.h"
0018 
0019 #define BIOS_MEMCONSOLE_V1_MAGIC    0xDEADBABE
0020 #define BIOS_MEMCONSOLE_V2_MAGIC    (('M')|('C'<<8)|('O'<<16)|('N'<<24))
0021 
0022 struct biosmemcon_ebda {
0023     u32 signature;
0024     union {
0025         struct {
0026             u8  enabled;
0027             u32 buffer_addr;
0028             u16 start;
0029             u16 end;
0030             u16 num_chars;
0031             u8  wrapped;
0032         } __packed v1;
0033         struct {
0034             u32 buffer_addr;
0035             /* Misdocumented as number of pages! */
0036             u16 num_bytes;
0037             u16 start;
0038             u16 end;
0039         } __packed v2;
0040     };
0041 } __packed;
0042 
0043 static char *memconsole_baseaddr;
0044 static size_t memconsole_length;
0045 
0046 static ssize_t memconsole_read(char *buf, loff_t pos, size_t count)
0047 {
0048     return memory_read_from_buffer(buf, count, &pos, memconsole_baseaddr,
0049                        memconsole_length);
0050 }
0051 
0052 static void found_v1_header(struct biosmemcon_ebda *hdr)
0053 {
0054     pr_info("memconsole: BIOS console v1 EBDA structure found at %p\n",
0055         hdr);
0056     pr_info("memconsole: BIOS console buffer at 0x%.8x, start = %d, end = %d, num = %d\n",
0057         hdr->v1.buffer_addr, hdr->v1.start,
0058         hdr->v1.end, hdr->v1.num_chars);
0059 
0060     memconsole_baseaddr = phys_to_virt(hdr->v1.buffer_addr);
0061     memconsole_length = hdr->v1.num_chars;
0062     memconsole_setup(memconsole_read);
0063 }
0064 
0065 static void found_v2_header(struct biosmemcon_ebda *hdr)
0066 {
0067     pr_info("memconsole: BIOS console v2 EBDA structure found at %p\n",
0068         hdr);
0069     pr_info("memconsole: BIOS console buffer at 0x%.8x, start = %d, end = %d, num_bytes = %d\n",
0070         hdr->v2.buffer_addr, hdr->v2.start,
0071         hdr->v2.end, hdr->v2.num_bytes);
0072 
0073     memconsole_baseaddr = phys_to_virt(hdr->v2.buffer_addr + hdr->v2.start);
0074     memconsole_length = hdr->v2.end - hdr->v2.start;
0075     memconsole_setup(memconsole_read);
0076 }
0077 
0078 /*
0079  * Search through the EBDA for the BIOS Memory Console, and
0080  * set the global variables to point to it.  Return true if found.
0081  */
0082 static bool memconsole_ebda_init(void)
0083 {
0084     unsigned int address;
0085     size_t length, cur;
0086 
0087     address = get_bios_ebda();
0088     if (!address) {
0089         pr_info("memconsole: BIOS EBDA non-existent.\n");
0090         return false;
0091     }
0092 
0093     /* EBDA length is byte 0 of EBDA (in KB) */
0094     length = *(u8 *)phys_to_virt(address);
0095     length <<= 10; /* convert to bytes */
0096 
0097     /*
0098      * Search through EBDA for BIOS memory console structure
0099      * note: signature is not necessarily dword-aligned
0100      */
0101     for (cur = 0; cur < length; cur++) {
0102         struct biosmemcon_ebda *hdr = phys_to_virt(address + cur);
0103 
0104         /* memconsole v1 */
0105         if (hdr->signature == BIOS_MEMCONSOLE_V1_MAGIC) {
0106             found_v1_header(hdr);
0107             return true;
0108         }
0109 
0110         /* memconsole v2 */
0111         if (hdr->signature == BIOS_MEMCONSOLE_V2_MAGIC) {
0112             found_v2_header(hdr);
0113             return true;
0114         }
0115     }
0116 
0117     pr_info("memconsole: BIOS console EBDA structure not found!\n");
0118     return false;
0119 }
0120 
0121 static const struct dmi_system_id memconsole_dmi_table[] __initconst = {
0122     {
0123         .ident = "Google Board",
0124         .matches = {
0125             DMI_MATCH(DMI_BOARD_VENDOR, "Google, Inc."),
0126         },
0127     },
0128     {}
0129 };
0130 MODULE_DEVICE_TABLE(dmi, memconsole_dmi_table);
0131 
0132 static bool __init memconsole_find(void)
0133 {
0134     if (!dmi_check_system(memconsole_dmi_table))
0135         return false;
0136 
0137     return memconsole_ebda_init();
0138 }
0139 
0140 static int __init memconsole_x86_init(void)
0141 {
0142     if (!memconsole_find())
0143         return -ENODEV;
0144 
0145     return memconsole_sysfs_init();
0146 }
0147 
0148 static void __exit memconsole_x86_exit(void)
0149 {
0150     memconsole_exit();
0151 }
0152 
0153 module_init(memconsole_x86_init);
0154 module_exit(memconsole_x86_exit);
0155 
0156 MODULE_AUTHOR("Google, Inc.");
0157 MODULE_LICENSE("GPL");