1 /*
2  * memconsole-coreboot.c
3  *
4  * Memory based BIOS console accessed through coreboot table.
5  *
6  * Copyright 2017 Google Inc.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License v2.0 as published by
10  * the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  */
17 
18 #include <linux/kernel.h>
19 #include <linux/module.h>
20 #include <linux/platform_device.h>
21 
22 #include "memconsole.h"
23 #include "coreboot_table.h"
24 
25 #define CB_TAG_CBMEM_CONSOLE	0x17
26 
27 /* CBMEM firmware console log descriptor. */
28 struct cbmem_cons {
29 	u32 buffer_size;
30 	u32 buffer_cursor;
31 	u8  buffer_body[0];
32 } __packed;
33 
34 static struct cbmem_cons __iomem *cbmem_console;
35 
36 static int memconsole_coreboot_init(phys_addr_t physaddr)
37 {
38 	struct cbmem_cons __iomem *tmp_cbmc;
39 
40 	tmp_cbmc = memremap(physaddr, sizeof(*tmp_cbmc), MEMREMAP_WB);
41 
42 	if (!tmp_cbmc)
43 		return -ENOMEM;
44 
45 	cbmem_console = memremap(physaddr,
46 				 tmp_cbmc->buffer_size + sizeof(*cbmem_console),
47 				 MEMREMAP_WB);
48 	memunmap(tmp_cbmc);
49 
50 	if (!cbmem_console)
51 		return -ENOMEM;
52 
53 	memconsole_setup(cbmem_console->buffer_body,
54 		min(cbmem_console->buffer_cursor, cbmem_console->buffer_size));
55 
56 	return 0;
57 }
58 
59 static int memconsole_probe(struct platform_device *pdev)
60 {
61 	int ret;
62 	struct lb_cbmem_ref entry;
63 
64 	ret = coreboot_table_find(CB_TAG_CBMEM_CONSOLE, &entry, sizeof(entry));
65 	if (ret)
66 		return ret;
67 
68 	ret = memconsole_coreboot_init(entry.cbmem_addr);
69 	if (ret)
70 		return ret;
71 
72 	return memconsole_sysfs_init();
73 }
74 
75 static int memconsole_remove(struct platform_device *pdev)
76 {
77 	memconsole_exit();
78 
79 	if (cbmem_console)
80 		memunmap(cbmem_console);
81 
82 	return 0;
83 }
84 
85 static struct platform_driver memconsole_driver = {
86 	.probe = memconsole_probe,
87 	.remove = memconsole_remove,
88 	.driver = {
89 		.name = "memconsole",
90 	},
91 };
92 
93 static int __init platform_memconsole_init(void)
94 {
95 	struct platform_device *pdev;
96 
97 	pdev = platform_device_register_simple("memconsole", -1, NULL, 0);
98 	if (IS_ERR(pdev))
99 		return PTR_ERR(pdev);
100 
101 	platform_driver_register(&memconsole_driver);
102 
103 	return 0;
104 }
105 
106 module_init(platform_memconsole_init);
107 
108 MODULE_AUTHOR("Google, Inc.");
109 MODULE_LICENSE("GPL");
110