mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-09-18 22:14:16 +00:00 
			
		
		
		
	* Add support for earlyprintk=efi which uses the EFI framebuffer. Very
useful for debugging boot issues.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.13 (GNU/Linux)
 
 iQIcBAABAgAGBQJSbrJgAAoJEC84WcCNIz1VOW8P/RswRdNAKrOsOwh2HIQJZ8yz
 +or3ZSINTsMURR7nswcJrBmwPA5+XGM4rnijdlzIP6L4kgeIjd++C0uzv2F+HmX7
 cInTpy23dNg1wZMPbX/c9ZLFzuoRx3Mod4Pw8+ChHEwtm0VDQKoktrEWhdYx/0Zi
 5c5+ahCN7EH42J2dqyvgcn9/BuFYH3P3MGNl2iPOBIJZp3J805gYIEQIibFhOed4
 Q1EqhUTC2dh32JuKM2IQNMcTPkNTTuN4ul1WpA4vaoO7zkN0tOOYSK7+hfcHDsga
 5E/goa/Zi94C+T8EccfQ8CbdModrcXhiPQXLJHKL5zvrzcBPuuaw2Sd1lvxg/M4a
 sKfiYcyXTgLk6BG4YvFSoHNpmht9HtHuGoshbMDlCNTRSnUYKozhU4OfuF/RZBwQ
 Wbv10RwTRpAqnmJzSjHpctdw+MnEpx/EhAYqbrZY85RDNuoeJXy+OClSfya4lVII
 i2sQYZKJWNaTxUu9uN6BxZIqs/Atx/DeQdspY9Yk4PMRNPWm1QB6ELmPjVvmoPTI
 iQ9SW/ErU3jMWkJv7OSf/GfW7pOcwWQMThQ0it6lJOEY8azlt2I6XyTvg7rDybfE
 hlx9OkIF5YCMM6ZzGBeoIjY+SSqINNx/p8715HpQ68N+tuWlrlUJNIw2FB5Sz0d0
 2rfrn291vGF/Cnrpq+Jf
 =qzH6
 -----END PGP SIGNATURE-----
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>
			
			
This commit is contained in:
		
						commit
						88392e9dd5
					
				
					 6 changed files with 216 additions and 3 deletions
				
			
		|  | @ -792,6 +792,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | ||||||
| 
 | 
 | ||||||
| 	earlyprintk=	[X86,SH,BLACKFIN,ARM] | 	earlyprintk=	[X86,SH,BLACKFIN,ARM] | ||||||
| 			earlyprintk=vga | 			earlyprintk=vga | ||||||
|  | 			earlyprintk=efi | ||||||
| 			earlyprintk=xen | 			earlyprintk=xen | ||||||
| 			earlyprintk=serial[,ttySn[,baudrate]] | 			earlyprintk=serial[,ttySn[,baudrate]] | ||||||
| 			earlyprintk=serial[,0x...[,baudrate]] | 			earlyprintk=serial[,0x...[,baudrate]] | ||||||
|  | @ -805,7 +806,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | ||||||
| 			Append ",keep" to not disable it when the real console | 			Append ",keep" to not disable it when the real console | ||||||
| 			takes over. | 			takes over. | ||||||
| 
 | 
 | ||||||
| 			Only vga or serial or usb debug port at a time. | 			Only one of vga, efi, serial, or usb debug port can | ||||||
|  | 			be used at a time. | ||||||
| 
 | 
 | ||||||
| 			Currently only ttyS0 and ttyS1 may be specified by | 			Currently only ttyS0 and ttyS1 may be specified by | ||||||
| 			name.  Other I/O ports may be explicitly specified | 			name.  Other I/O ports may be explicitly specified | ||||||
|  | @ -819,8 +821,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | ||||||
| 			Interaction with the standard serial driver is not | 			Interaction with the standard serial driver is not | ||||||
| 			very good. | 			very good. | ||||||
| 
 | 
 | ||||||
| 			The VGA output is eventually overwritten by the real | 			The VGA and EFI output is eventually overwritten by | ||||||
| 			console. | 			the real console. | ||||||
| 
 | 
 | ||||||
| 			The xen output can only be used by Xen PV guests. | 			The xen output can only be used by Xen PV guests. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -59,6 +59,16 @@ config EARLY_PRINTK_DBGP | ||||||
| 	  with klogd/syslogd or the X server. You should normally N here, | 	  with klogd/syslogd or the X server. You should normally N here, | ||||||
| 	  unless you want to debug such a crash. You need usb debug device. | 	  unless you want to debug such a crash. You need usb debug device. | ||||||
| 
 | 
 | ||||||
|  | config EARLY_PRINTK_EFI | ||||||
|  | 	bool "Early printk via the EFI framebuffer" | ||||||
|  | 	depends on EFI && EARLY_PRINTK | ||||||
|  | 	select FONT_SUPPORT | ||||||
|  | 	---help--- | ||||||
|  | 	  Write kernel log output directly into the EFI framebuffer. | ||||||
|  | 
 | ||||||
|  | 	  This is useful for kernel debugging when your machine crashes very | ||||||
|  | 	  early before the console code is initialized. | ||||||
|  | 
 | ||||||
| config X86_PTDUMP | config X86_PTDUMP | ||||||
| 	bool "Export kernel pagetable layout to userspace via debugfs" | 	bool "Export kernel pagetable layout to userspace via debugfs" | ||||||
| 	depends on DEBUG_KERNEL | 	depends on DEBUG_KERNEL | ||||||
|  |  | ||||||
|  | @ -109,6 +109,8 @@ static inline bool efi_is_native(void) | ||||||
| 	return IS_ENABLED(CONFIG_X86_64) == efi_enabled(EFI_64BIT); | 	return IS_ENABLED(CONFIG_X86_64) == efi_enabled(EFI_64BIT); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | extern struct console early_efi_console; | ||||||
|  | 
 | ||||||
| #else | #else | ||||||
| /*
 | /*
 | ||||||
|  * IF EFI is not configured, have the EFI calls return -ENOSYS. |  * IF EFI is not configured, have the EFI calls return -ENOSYS. | ||||||
|  |  | ||||||
|  | @ -17,6 +17,8 @@ | ||||||
| #include <asm/mrst.h> | #include <asm/mrst.h> | ||||||
| #include <asm/pgtable.h> | #include <asm/pgtable.h> | ||||||
| #include <linux/usb/ehci_def.h> | #include <linux/usb/ehci_def.h> | ||||||
|  | #include <linux/efi.h> | ||||||
|  | #include <asm/efi.h> | ||||||
| 
 | 
 | ||||||
| /* Simple VGA output */ | /* Simple VGA output */ | ||||||
| #define VGABASE		(__ISA_IO_base + 0xb8000) | #define VGABASE		(__ISA_IO_base + 0xb8000) | ||||||
|  | @ -234,6 +236,11 @@ static int __init setup_early_printk(char *buf) | ||||||
| 			early_console_register(&early_hsu_console, keep); | 			early_console_register(&early_hsu_console, keep); | ||||||
| 		} | 		} | ||||||
| #endif | #endif | ||||||
|  | #ifdef CONFIG_EARLY_PRINTK_EFI | ||||||
|  | 		if (!strncmp(buf, "efi", 3)) | ||||||
|  | 			early_console_register(&early_efi_console, keep); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| 		buf++; | 		buf++; | ||||||
| 	} | 	} | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -1,2 +1,3 @@ | ||||||
| obj-$(CONFIG_EFI) 		+= efi.o efi_$(BITS).o efi_stub_$(BITS).o | obj-$(CONFIG_EFI) 		+= efi.o efi_$(BITS).o efi_stub_$(BITS).o | ||||||
| obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o | obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o | ||||||
|  | obj-$(CONFIG_EARLY_PRINTK_EFI)	+= early_printk.o | ||||||
|  |  | ||||||
							
								
								
									
										191
									
								
								arch/x86/platform/efi/early_printk.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								arch/x86/platform/efi/early_printk.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,191 @@ | ||||||
|  | /*
 | ||||||
|  |  * Copyright (C) 2013 Intel Corporation; author Matt Fleming | ||||||
|  |  * | ||||||
|  |  *  This file is part of the Linux kernel, and is made available under | ||||||
|  |  *  the terms of the GNU General Public License version 2. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <linux/console.h> | ||||||
|  | #include <linux/efi.h> | ||||||
|  | #include <linux/font.h> | ||||||
|  | #include <linux/io.h> | ||||||
|  | #include <linux/kernel.h> | ||||||
|  | #include <asm/setup.h> | ||||||
|  | 
 | ||||||
|  | static const struct font_desc *font; | ||||||
|  | static u32 efi_x, efi_y; | ||||||
|  | 
 | ||||||
|  | static __init void early_efi_clear_scanline(unsigned int y) | ||||||
|  | { | ||||||
|  | 	unsigned long base, *dst; | ||||||
|  | 	u16 len; | ||||||
|  | 
 | ||||||
|  | 	base = boot_params.screen_info.lfb_base; | ||||||
|  | 	len = boot_params.screen_info.lfb_linelength; | ||||||
|  | 
 | ||||||
|  | 	dst = early_ioremap(base + y*len, len); | ||||||
|  | 	if (!dst) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	memset(dst, 0, len); | ||||||
|  | 	early_iounmap(dst, len); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __init void early_efi_scroll_up(void) | ||||||
|  | { | ||||||
|  | 	unsigned long base, *dst, *src; | ||||||
|  | 	u16 len; | ||||||
|  | 	u32 i, height; | ||||||
|  | 
 | ||||||
|  | 	base = boot_params.screen_info.lfb_base; | ||||||
|  | 	len = boot_params.screen_info.lfb_linelength; | ||||||
|  | 	height = boot_params.screen_info.lfb_height; | ||||||
|  | 
 | ||||||
|  | 	for (i = 0; i < height - font->height; i++) { | ||||||
|  | 		dst = early_ioremap(base + i*len, len); | ||||||
|  | 		if (!dst) | ||||||
|  | 			return; | ||||||
|  | 
 | ||||||
|  | 		src = early_ioremap(base + (i + font->height) * len, len); | ||||||
|  | 		if (!src) { | ||||||
|  | 			early_iounmap(dst, len); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		memmove(dst, src, len); | ||||||
|  | 
 | ||||||
|  | 		early_iounmap(src, len); | ||||||
|  | 		early_iounmap(dst, len); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void early_efi_write_char(u32 *dst, unsigned char c, unsigned int h) | ||||||
|  | { | ||||||
|  | 	const u32 color_black = 0x00000000; | ||||||
|  | 	const u32 color_white = 0x00ffffff; | ||||||
|  | 	const u8 *src; | ||||||
|  | 	u8 s8; | ||||||
|  | 	int m; | ||||||
|  | 
 | ||||||
|  | 	src = font->data + c * font->height; | ||||||
|  | 	s8 = *(src + h); | ||||||
|  | 
 | ||||||
|  | 	for (m = 0; m < 8; m++) { | ||||||
|  | 		if ((s8 >> (7 - m)) & 1) | ||||||
|  | 			*dst = color_white; | ||||||
|  | 		else | ||||||
|  | 			*dst = color_black; | ||||||
|  | 		dst++; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __init void | ||||||
|  | early_efi_write(struct console *con, const char *str, unsigned int num) | ||||||
|  | { | ||||||
|  | 	struct screen_info *si; | ||||||
|  | 	unsigned long base; | ||||||
|  | 	unsigned int len; | ||||||
|  | 	const char *s; | ||||||
|  | 	void *dst; | ||||||
|  | 
 | ||||||
|  | 	base = boot_params.screen_info.lfb_base; | ||||||
|  | 	si = &boot_params.screen_info; | ||||||
|  | 	len = si->lfb_linelength; | ||||||
|  | 
 | ||||||
|  | 	while (num) { | ||||||
|  | 		unsigned int linemax; | ||||||
|  | 		unsigned int h, count = 0; | ||||||
|  | 
 | ||||||
|  | 		for (s = str; *s && *s != '\n'; s++) { | ||||||
|  | 			if (count == num) | ||||||
|  | 				break; | ||||||
|  | 			count++; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		linemax = (si->lfb_width - efi_x) / font->width; | ||||||
|  | 		if (count > linemax) | ||||||
|  | 			count = linemax; | ||||||
|  | 
 | ||||||
|  | 		for (h = 0; h < font->height; h++) { | ||||||
|  | 			unsigned int n, x; | ||||||
|  | 
 | ||||||
|  | 			dst = early_ioremap(base + (efi_y + h) * len, len); | ||||||
|  | 			if (!dst) | ||||||
|  | 				return; | ||||||
|  | 
 | ||||||
|  | 			s = str; | ||||||
|  | 			n = count; | ||||||
|  | 			x = efi_x; | ||||||
|  | 
 | ||||||
|  | 			while (n-- > 0) { | ||||||
|  | 				early_efi_write_char(dst + x*4, *s, h); | ||||||
|  | 				x += font->width; | ||||||
|  | 				s++; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			early_iounmap(dst, len); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		num -= count; | ||||||
|  | 		efi_x += count * font->width; | ||||||
|  | 		str += count; | ||||||
|  | 
 | ||||||
|  | 		if (num > 0 && *s == '\n') { | ||||||
|  | 			efi_x = 0; | ||||||
|  | 			efi_y += font->height; | ||||||
|  | 			str++; | ||||||
|  | 			num--; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (efi_x >= si->lfb_width) { | ||||||
|  | 			efi_x = 0; | ||||||
|  | 			efi_y += font->height; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (efi_y + font->height >= si->lfb_height) { | ||||||
|  | 			u32 i; | ||||||
|  | 
 | ||||||
|  | 			efi_y -= font->height; | ||||||
|  | 			early_efi_scroll_up(); | ||||||
|  | 
 | ||||||
|  | 			for (i = 0; i < font->height; i++) | ||||||
|  | 				early_efi_clear_scanline(efi_y + i); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __init int early_efi_setup(struct console *con, char *options) | ||||||
|  | { | ||||||
|  | 	struct screen_info *si; | ||||||
|  | 	u16 xres, yres; | ||||||
|  | 	u32 i; | ||||||
|  | 
 | ||||||
|  | 	si = &boot_params.screen_info; | ||||||
|  | 	xres = si->lfb_width; | ||||||
|  | 	yres = si->lfb_height; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * early_efi_write_char() implicitly assumes a framebuffer with | ||||||
|  | 	 * 32-bits per pixel. | ||||||
|  | 	 */ | ||||||
|  | 	if (si->lfb_depth != 32) | ||||||
|  | 		return -ENODEV; | ||||||
|  | 
 | ||||||
|  | 	font = get_default_font(xres, yres, -1, -1); | ||||||
|  | 	if (!font) | ||||||
|  | 		return -ENODEV; | ||||||
|  | 
 | ||||||
|  | 	efi_y = rounddown(yres, font->height) - font->height; | ||||||
|  | 	for (i = 0; i < (yres - efi_y) / font->height; i++) | ||||||
|  | 		early_efi_scroll_up(); | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct console early_efi_console = { | ||||||
|  | 	.name =		"earlyefi", | ||||||
|  | 	.write =	early_efi_write, | ||||||
|  | 	.setup =	early_efi_setup, | ||||||
|  | 	.flags =	CON_PRINTBUFFER, | ||||||
|  | 	.index =	-1, | ||||||
|  | }; | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Ingo Molnar
						Ingo Molnar