aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/platform
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 /arch/x86/platform
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>
Diffstat (limited to 'arch/x86/platform')
-rw-r--r--arch/x86/platform/efi/Makefile1
-rw-r--r--arch/x86/platform/efi/early_printk.c191
2 files changed, 192 insertions, 0 deletions
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};