Path: blob/master/drivers/firmware/google/memconsole-x86-legacy.c
26428 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* memconsole-x86-legacy.c3*4* EBDA specific parts of the memory based BIOS console.5*6* Copyright 2017 Google Inc.7*/89#include <linux/kernel.h>10#include <linux/module.h>11#include <linux/dmi.h>12#include <linux/mm.h>13#include <asm/bios_ebda.h>14#include <linux/acpi.h>1516#include "memconsole.h"1718#define BIOS_MEMCONSOLE_V1_MAGIC 0xDEADBABE19#define BIOS_MEMCONSOLE_V2_MAGIC (('M')|('C'<<8)|('O'<<16)|('N'<<24))2021struct biosmemcon_ebda {22u32 signature;23union {24struct {25u8 enabled;26u32 buffer_addr;27u16 start;28u16 end;29u16 num_chars;30u8 wrapped;31} __packed v1;32struct {33u32 buffer_addr;34/* Misdocumented as number of pages! */35u16 num_bytes;36u16 start;37u16 end;38} __packed v2;39};40} __packed;4142static char *memconsole_baseaddr;43static size_t memconsole_length;4445static ssize_t memconsole_read(char *buf, loff_t pos, size_t count)46{47return memory_read_from_buffer(buf, count, &pos, memconsole_baseaddr,48memconsole_length);49}5051static void found_v1_header(struct biosmemcon_ebda *hdr)52{53pr_info("memconsole: BIOS console v1 EBDA structure found at %p\n",54hdr);55pr_info("memconsole: BIOS console buffer at 0x%.8x, start = %d, end = %d, num = %d\n",56hdr->v1.buffer_addr, hdr->v1.start,57hdr->v1.end, hdr->v1.num_chars);5859memconsole_baseaddr = phys_to_virt(hdr->v1.buffer_addr);60memconsole_length = hdr->v1.num_chars;61memconsole_setup(memconsole_read);62}6364static void found_v2_header(struct biosmemcon_ebda *hdr)65{66pr_info("memconsole: BIOS console v2 EBDA structure found at %p\n",67hdr);68pr_info("memconsole: BIOS console buffer at 0x%.8x, start = %d, end = %d, num_bytes = %d\n",69hdr->v2.buffer_addr, hdr->v2.start,70hdr->v2.end, hdr->v2.num_bytes);7172memconsole_baseaddr = phys_to_virt(hdr->v2.buffer_addr + hdr->v2.start);73memconsole_length = hdr->v2.end - hdr->v2.start;74memconsole_setup(memconsole_read);75}7677/*78* Search through the EBDA for the BIOS Memory Console, and79* set the global variables to point to it. Return true if found.80*/81static bool memconsole_ebda_init(void)82{83unsigned int address;84size_t length, cur;8586address = get_bios_ebda();87if (!address) {88pr_info("memconsole: BIOS EBDA non-existent.\n");89return false;90}9192/* EBDA length is byte 0 of EBDA (in KB) */93length = *(u8 *)phys_to_virt(address);94length <<= 10; /* convert to bytes */9596/*97* Search through EBDA for BIOS memory console structure98* note: signature is not necessarily dword-aligned99*/100for (cur = 0; cur < length; cur++) {101struct biosmemcon_ebda *hdr = phys_to_virt(address + cur);102103/* memconsole v1 */104if (hdr->signature == BIOS_MEMCONSOLE_V1_MAGIC) {105found_v1_header(hdr);106return true;107}108109/* memconsole v2 */110if (hdr->signature == BIOS_MEMCONSOLE_V2_MAGIC) {111found_v2_header(hdr);112return true;113}114}115116pr_info("memconsole: BIOS console EBDA structure not found!\n");117return false;118}119120static const struct dmi_system_id memconsole_dmi_table[] __initconst = {121{122.ident = "Google Board",123.matches = {124DMI_MATCH(DMI_BOARD_VENDOR, "Google, Inc."),125},126},127{}128};129MODULE_DEVICE_TABLE(dmi, memconsole_dmi_table);130131static bool __init memconsole_find(void)132{133if (!dmi_check_system(memconsole_dmi_table))134return false;135136return memconsole_ebda_init();137}138139static int __init memconsole_x86_init(void)140{141if (!memconsole_find())142return -ENODEV;143144return memconsole_sysfs_init();145}146147static void __exit memconsole_x86_exit(void)148{149memconsole_exit();150}151152module_init(memconsole_x86_init);153module_exit(memconsole_x86_exit);154155MODULE_AUTHOR("Google, Inc.");156MODULE_DESCRIPTION("EBDA specific parts of the memory based BIOS console.");157MODULE_LICENSE("GPL");158159160