^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * memconsole-x86-legacy.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * EBDA specific parts of the memory based BIOS console.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright 2017 Google Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/dmi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <asm/bios_ebda.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include "memconsole.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define BIOS_MEMCONSOLE_V1_MAGIC 0xDEADBABE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define BIOS_MEMCONSOLE_V2_MAGIC (('M')|('C'<<8)|('O'<<16)|('N'<<24))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct biosmemcon_ebda {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) u32 signature;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) union {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) u8 enabled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) u32 buffer_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) u16 start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) u16 end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) u16 num_chars;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) u8 wrapped;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) } __packed v1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) u32 buffer_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) /* Misdocumented as number of pages! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) u16 num_bytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) u16 start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) u16 end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) } __packed v2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) } __packed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static char *memconsole_baseaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) static size_t memconsole_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static ssize_t memconsole_read(char *buf, loff_t pos, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) return memory_read_from_buffer(buf, count, &pos, memconsole_baseaddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) memconsole_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) static void found_v1_header(struct biosmemcon_ebda *hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) pr_info("memconsole: BIOS console v1 EBDA structure found at %p\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) pr_info("memconsole: BIOS console buffer at 0x%.8x, start = %d, end = %d, num = %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) hdr->v1.buffer_addr, hdr->v1.start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) hdr->v1.end, hdr->v1.num_chars);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) memconsole_baseaddr = phys_to_virt(hdr->v1.buffer_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) memconsole_length = hdr->v1.num_chars;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) memconsole_setup(memconsole_read);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static void found_v2_header(struct biosmemcon_ebda *hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) pr_info("memconsole: BIOS console v2 EBDA structure found at %p\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) pr_info("memconsole: BIOS console buffer at 0x%.8x, start = %d, end = %d, num_bytes = %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) hdr->v2.buffer_addr, hdr->v2.start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) hdr->v2.end, hdr->v2.num_bytes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) memconsole_baseaddr = phys_to_virt(hdr->v2.buffer_addr + hdr->v2.start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) memconsole_length = hdr->v2.end - hdr->v2.start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) memconsole_setup(memconsole_read);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * Search through the EBDA for the BIOS Memory Console, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * set the global variables to point to it. Return true if found.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) static bool memconsole_ebda_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) unsigned int address;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) size_t length, cur;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) address = get_bios_ebda();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (!address) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) pr_info("memconsole: BIOS EBDA non-existent.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) /* EBDA length is byte 0 of EBDA (in KB) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) length = *(u8 *)phys_to_virt(address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) length <<= 10; /* convert to bytes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * Search through EBDA for BIOS memory console structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * note: signature is not necessarily dword-aligned
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) for (cur = 0; cur < length; cur++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) struct biosmemcon_ebda *hdr = phys_to_virt(address + cur);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) /* memconsole v1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) if (hdr->signature == BIOS_MEMCONSOLE_V1_MAGIC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) found_v1_header(hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) /* memconsole v2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (hdr->signature == BIOS_MEMCONSOLE_V2_MAGIC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) found_v2_header(hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) pr_info("memconsole: BIOS console EBDA structure not found!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) static const struct dmi_system_id memconsole_dmi_table[] __initconst = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) .ident = "Google Board",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) DMI_MATCH(DMI_BOARD_VENDOR, "Google, Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) MODULE_DEVICE_TABLE(dmi, memconsole_dmi_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) static bool __init memconsole_find(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) if (!dmi_check_system(memconsole_dmi_table))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) return memconsole_ebda_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) static int __init memconsole_x86_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) if (!memconsole_find())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) return memconsole_sysfs_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) static void __exit memconsole_x86_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) memconsole_exit();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) module_init(memconsole_x86_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) module_exit(memconsole_x86_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) MODULE_AUTHOR("Google, Inc.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) MODULE_LICENSE("GPL");