aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2013-10-29 04:21:37 -0400
committerIngo Molnar <mingo@kernel.org>2013-10-29 04:21:37 -0400
commit88392e9dd5a524b8194f1045369c7d0eb16d9f32 (patch)
tree2eead15738f173ed08ecbedc88adbb0bf2937022
parent564c39701c8c52f2310a425223a04d175ed287c4 (diff)
parent72548e836b0c4abbb652e791dee9c91203a9a4c6 (diff)
Merge tag 'efi-next' of git://git.kernel.org/pub/scm/linux/kernel/git/mfleming/efi into x86/efi
Pull EFI earlyprintk support from Matt Fleming: " * Add support for earlyprintk=efi which uses the EFI framebuffer. Very useful for debugging boot issues. " Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--Documentation/kernel-parameters.txt8
-rw-r--r--arch/x86/Kconfig.debug10
-rw-r--r--arch/x86/include/asm/efi.h2
-rw-r--r--arch/x86/kernel/early_printk.c7
-rw-r--r--arch/x86/platform/efi/Makefile1
-rw-r--r--arch/x86/platform/efi/early_printk.c191
6 files changed, 216 insertions, 3 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 7f9d4f53882c..7a0f202d482e 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -792,6 +792,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
792 792
793 earlyprintk= [X86,SH,BLACKFIN,ARM] 793 earlyprintk= [X86,SH,BLACKFIN,ARM]
794 earlyprintk=vga 794 earlyprintk=vga
795 earlyprintk=efi
795 earlyprintk=xen 796 earlyprintk=xen
796 earlyprintk=serial[,ttySn[,baudrate]] 797 earlyprintk=serial[,ttySn[,baudrate]]
797 earlyprintk=serial[,0x...[,baudrate]] 798 earlyprintk=serial[,0x...[,baudrate]]
@@ -805,7 +806,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
805 Append ",keep" to not disable it when the real console 806 Append ",keep" to not disable it when the real console
806 takes over. 807 takes over.
807 808
808 Only vga or serial or usb debug port at a time. 809 Only one of vga, efi, serial, or usb debug port can
810 be used at a time.
809 811
810 Currently only ttyS0 and ttyS1 may be specified by 812 Currently only ttyS0 and ttyS1 may be specified by
811 name. Other I/O ports may be explicitly specified 813 name. Other I/O ports may be explicitly specified
@@ -819,8 +821,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
819 Interaction with the standard serial driver is not 821 Interaction with the standard serial driver is not
820 very good. 822 very good.
821 823
822 The VGA output is eventually overwritten by the real 824 The VGA and EFI output is eventually overwritten by
823 console. 825 the real console.
824 826
825 The xen output can only be used by Xen PV guests. 827 The xen output can only be used by Xen PV guests.
826 828
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 78d91afb8e50..0f3621ed1db6 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -59,6 +59,16 @@ config EARLY_PRINTK_DBGP
59 with klogd/syslogd or the X server. You should normally N here, 59 with klogd/syslogd or the X server. You should normally N here,
60 unless you want to debug such a crash. You need usb debug device. 60 unless you want to debug such a crash. You need usb debug device.
61 61
62config EARLY_PRINTK_EFI
63 bool "Early printk via the EFI framebuffer"
64 depends on EFI && EARLY_PRINTK
65 select FONT_SUPPORT
66 ---help---
67 Write kernel log output directly into the EFI framebuffer.
68
69 This is useful for kernel debugging when your machine crashes very
70 early before the console code is initialized.
71
62config X86_PTDUMP 72config X86_PTDUMP
63 bool "Export kernel pagetable layout to userspace via debugfs" 73 bool "Export kernel pagetable layout to userspace via debugfs"
64 depends on DEBUG_KERNEL 74 depends on DEBUG_KERNEL
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 0062a0125041..65c6e6e3a552 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -109,6 +109,8 @@ static inline bool efi_is_native(void)
109 return IS_ENABLED(CONFIG_X86_64) == efi_enabled(EFI_64BIT); 109 return IS_ENABLED(CONFIG_X86_64) == efi_enabled(EFI_64BIT);
110} 110}
111 111
112extern struct console early_efi_console;
113
112#else 114#else
113/* 115/*
114 * IF EFI is not configured, have the EFI calls return -ENOSYS. 116 * IF EFI is not configured, have the EFI calls return -ENOSYS.
diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c
index d15f575a861b..6d3d20073615 100644
--- a/arch/x86/kernel/early_printk.c
+++ b/arch/x86/kernel/early_printk.c
@@ -17,6 +17,8 @@
17#include <asm/mrst.h> 17#include <asm/mrst.h>
18#include <asm/pgtable.h> 18#include <asm/pgtable.h>
19#include <linux/usb/ehci_def.h> 19#include <linux/usb/ehci_def.h>
20#include <linux/efi.h>
21#include <asm/efi.h>
20 22
21/* Simple VGA output */ 23/* Simple VGA output */
22#define VGABASE (__ISA_IO_base + 0xb8000) 24#define VGABASE (__ISA_IO_base + 0xb8000)
@@ -234,6 +236,11 @@ static int __init setup_early_printk(char *buf)
234 early_console_register(&early_hsu_console, keep); 236 early_console_register(&early_hsu_console, keep);
235 } 237 }
236#endif 238#endif
239#ifdef CONFIG_EARLY_PRINTK_EFI
240 if (!strncmp(buf, "efi", 3))
241 early_console_register(&early_efi_console, keep);
242#endif
243
237 buf++; 244 buf++;
238 } 245 }
239 return 0; 246 return 0;
diff --git a/arch/x86/platform/efi/Makefile b/arch/x86/platform/efi/Makefile
index 6db1cc4c7534..b7b0b35c1981 100644
--- a/arch/x86/platform/efi/Makefile
+++ b/arch/x86/platform/efi/Makefile
@@ -1,2 +1,3 @@
1obj-$(CONFIG_EFI) += efi.o efi_$(BITS).o efi_stub_$(BITS).o 1obj-$(CONFIG_EFI) += efi.o efi_$(BITS).o efi_stub_$(BITS).o
2obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o 2obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o
3obj-$(CONFIG_EARLY_PRINTK_EFI) += early_printk.o
diff --git a/arch/x86/platform/efi/early_printk.c b/arch/x86/platform/efi/early_printk.c
new file mode 100644
index 000000000000..6599a0027b76
--- /dev/null
+++ b/arch/x86/platform/efi/early_printk.c
@@ -0,0 +1,191 @@
1/*
2 * Copyright (C) 2013 Intel Corporation; author Matt Fleming
3 *
4 * This file is part of the Linux kernel, and is made available under
5 * the terms of the GNU General Public License version 2.
6 */
7
8#include <linux/console.h>
9#include <linux/efi.h>
10#include <linux/font.h>
11#include <linux/io.h>
12#include <linux/kernel.h>
13#include <asm/setup.h>
14
15static const struct font_desc *font;
16static u32 efi_x, efi_y;
17
18static __init void early_efi_clear_scanline(unsigned int y)
19{
20 unsigned long base, *dst;
21 u16 len;
22
23 base = boot_params.screen_info.lfb_base;
24 len = boot_params.screen_info.lfb_linelength;
25
26 dst = early_ioremap(base + y*len, len);
27 if (!dst)
28 return;
29
30 memset(dst, 0, len);
31 early_iounmap(dst, len);
32}
33
34static __init void early_efi_scroll_up(void)
35{
36 unsigned long base, *dst, *src;
37 u16 len;
38 u32 i, height;
39
40 base = boot_params.screen_info.lfb_base;
41 len = boot_params.screen_info.lfb_linelength;
42 height = boot_params.screen_info.lfb_height;
43
44 for (i = 0; i < height - font->height; i++) {
45 dst = early_ioremap(base + i*len, len);
46 if (!dst)
47 return;
48
49 src = early_ioremap(base + (i + font->height) * len, len);
50 if (!src) {
51 early_iounmap(dst, len);
52 return;
53 }
54
55 memmove(dst, src, len);
56
57 early_iounmap(src, len);
58 early_iounmap(dst, len);
59 }
60}
61
62static void early_efi_write_char(u32 *dst, unsigned char c, unsigned int h)
63{
64 const u32 color_black = 0x00000000;
65 const u32 color_white = 0x00ffffff;
66 const u8 *src;
67 u8 s8;
68 int m;
69
70 src = font->data + c * font->height;
71 s8 = *(src + h);
72
73 for (m = 0; m < 8; m++) {
74 if ((s8 >> (7 - m)) & 1)
75 *dst = color_white;
76 else
77 *dst = color_black;
78 dst++;
79 }
80}
81
82static __init void
83early_efi_write(struct console *con, const char *str, unsigned int num)
84{
85 struct screen_info *si;
86 unsigned long base;
87 unsigned int len;
88 const char *s;
89 void *dst;
90
91 base = boot_params.screen_info.lfb_base;
92 si = &boot_params.screen_info;
93 len = si->lfb_linelength;
94
95 while (num) {
96 unsigned int linemax;
97 unsigned int h, count = 0;
98
99 for (s = str; *s && *s != '\n'; s++) {
100 if (count == num)
101 break;
102 count++;
103 }
104
105 linemax = (si->lfb_width - efi_x) / font->width;
106 if (count > linemax)
107 count = linemax;
108
109 for (h = 0; h < font->height; h++) {
110 unsigned int n, x;
111
112 dst = early_ioremap(base + (efi_y + h) * len, len);
113 if (!dst)
114 return;
115
116 s = str;
117 n = count;
118 x = efi_x;
119
120 while (n-- > 0) {
121 early_efi_write_char(dst + x*4, *s, h);
122 x += font->width;
123 s++;
124 }
125
126 early_iounmap(dst, len);
127 }
128
129 num -= count;
130 efi_x += count * font->width;
131 str += count;
132
133 if (num > 0 && *s == '\n') {
134 efi_x = 0;
135 efi_y += font->height;
136 str++;
137 num--;
138 }
139
140 if (efi_x >= si->lfb_width) {
141 efi_x = 0;
142 efi_y += font->height;
143 }
144
145 if (efi_y + font->height >= si->lfb_height) {
146 u32 i;
147
148 efi_y -= font->height;
149 early_efi_scroll_up();
150
151 for (i = 0; i < font->height; i++)
152 early_efi_clear_scanline(efi_y + i);
153 }
154 }
155}
156
157static __init int early_efi_setup(struct console *con, char *options)
158{
159 struct screen_info *si;
160 u16 xres, yres;
161 u32 i;
162
163 si = &boot_params.screen_info;
164 xres = si->lfb_width;
165 yres = si->lfb_height;
166
167 /*
168 * early_efi_write_char() implicitly assumes a framebuffer with
169 * 32-bits per pixel.
170 */
171 if (si->lfb_depth != 32)
172 return -ENODEV;
173
174 font = get_default_font(xres, yres, -1, -1);
175 if (!font)
176 return -ENODEV;
177
178 efi_y = rounddown(yres, font->height) - font->height;
179 for (i = 0; i < (yres - efi_y) / font->height; i++)
180 early_efi_scroll_up();
181
182 return 0;
183}
184
185struct console early_efi_console = {
186 .name = "earlyefi",
187 .write = early_efi_write,
188 .setup = early_efi_setup,
189 .flags = CON_PRINTBUFFER,
190 .index = -1,
191};