[coreboot] [PATCH] x86: add coreboot framebuffer support

Vladimir 'φ-coder/phcoder' Serbinenko phcoder at gmail.com
Thu Sep 4 22:09:11 CEST 2014


This code assumes that payload didn't change video mode which is
improper assumption if you're not a payload.
On 04.09.2014 12:25, Gerd Hoffmann wrote:
> Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
> ---
>  arch/x86/Kconfig           |  12 +++
>  arch/x86/kernel/Makefile   |   1 +
>  arch/x86/kernel/coreboot.c | 232 +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 245 insertions(+)
>  create mode 100644 arch/x86/kernel/coreboot.c
> 
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index 778178f..3aeb038 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -2372,6 +2372,18 @@ config X86_SYSFB
>  
>  	  If unsure, say Y.
>  
> +config COREBOOT
> +	bool "coreboot"
> +	depends on X86_SYSFB
> +	depends on FB_SIMPLE
> +	help
> +	  Add coreboot framebuffer support to the linux kernel.	 Say Y here
> +	  if you want the linux kernel find and use the firmware framebuffer
> +	  initialized by coreboot.  Useful when using the linux kernel as
> +	  coreboot payload.
> +
> +	  If unsure, or if you don't know what coreboot is, say N.
> +
>  endmenu
>  
>  
> diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
> index ada2e2d..4b30b0e 100644
> --- a/arch/x86/kernel/Makefile
> +++ b/arch/x86/kernel/Makefile
> @@ -103,6 +103,7 @@ obj-$(CONFIG_UPROBES)			+= uprobes.o
>  obj-y					+= sysfb.o
>  obj-$(CONFIG_X86_SYSFB)			+= sysfb_simplefb.o
>  obj-$(CONFIG_EFI)			+= sysfb_efi.o
> +obj-$(CONFIG_COREBOOT)			+= coreboot.o
>  
>  obj-$(CONFIG_PERF_EVENTS)		+= perf_regs.o
>  obj-$(CONFIG_TRACING)			+= tracepoint.o
> diff --git a/arch/x86/kernel/coreboot.c b/arch/x86/kernel/coreboot.c
> new file mode 100644
> index 0000000..44ed3fa
> --- /dev/null
> +++ b/arch/x86/kernel/coreboot.c
> @@ -0,0 +1,232 @@
> +/*
> + * Find and parse coreboot tables.  Register framebuffer if present.
> + * See src/include/boot/coreboot_tables.h in coreboot source tree.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/mm.h>
> +#include <linux/screen_info.h>
> +#include <linux/platform_device.h>
> +#include <linux/platform_data/simplefb.h>
> +#include <video/vga.h>
> +
> +#include <asm/checksum.h>
> +#include <asm/io.h>
> +#include <asm/sysfb.h>
> +
> +struct cb_header {
> +	u32     signature;
> +	u32     header_bytes;
> +	u32     header_checksum;
> +	u32     table_bytes;
> +	u32     table_checksum;
> +	u32     table_entries;
> +};
> +
> +#define CB_TAG_MAINBOARD        0x0003
> +#define CB_TAG_VERSION          0x0004
> +#define CB_TAG_FORWARD          0x0011
> +#define CB_TAG_FRAMEBUFFER      0x0012
> +
> +struct cb_mainboard {
> +	u8      vendor_idx;
> +	u8      part_idx;
> +	char    strings[0];
> +};
> +
> +struct cb_framebuffer {
> +	u64     physical_address;
> +	u32     x_resolution;
> +	u32     y_resolution;
> +	u32     bytes_per_line;
> +	u8      bits_per_pixel;
> +	u8      red_mask_pos;
> +	u8      red_mask_size;
> +	u8      green_mask_pos;
> +	u8      green_mask_size;
> +	u8      blue_mask_pos;
> +	u8      blue_mask_size;
> +	u8      reserved_mask_pos;
> +	u8      reserved_mask_size;
> +};
> +
> +struct cb_entry {
> +	u32     tag;
> +	u32     size;
> +	union {
> +		char    string[0];
> +		u64     forward;
> +		struct cb_mainboard   mb;
> +		struct cb_framebuffer fb;
> +	} u;
> +};
> +
> +#define CB_SIGNATURE 0x4f49424C  /* "LBIO" */
> +
> +/* Try to locate the coreboot header in a given address range. */
> +static __init struct cb_header *coreboot_find_header(u32 addr, int len)
> +{
> +	struct cb_header *cbh, *copy;
> +	int offset;
> +	void *map;
> +
> +	map = ioremap(addr, len);
> +	for (offset = 0; offset < len; offset += 16) {
> +		cbh = map + offset;
> +		if (!cbh)
> +			continue;
> +		if (cbh->signature != CB_SIGNATURE)
> +			continue;
> +		if (!cbh->table_bytes)
> +			continue;
> +		if (ip_compute_csum(cbh, sizeof(*cbh)) != 0)
> +			continue;
> +		if (ip_compute_csum(cbh + 1, cbh->table_bytes)
> +		    != cbh->table_checksum)
> +			continue;
> +		pr_debug("coreboot: header found at 0x%x\n",
> +			 addr + offset);
> +		copy = kzalloc(sizeof(*cbh) + cbh->table_bytes, GFP_KERNEL);
> +		memcpy(copy, cbh, sizeof(*cbh) + cbh->table_bytes);
> +		iounmap(map);
> +		return copy;
> +	}
> +	iounmap(map);
> +	return NULL;
> +}
> +
> +static __init bool check_vga_text_mode(void)
> +{
> +	uint8_t reg;
> +
> +	if (screen_info.orig_video_isVGA != 1)
> +		return false;
> +
> +	reg = inb(VGA_GFX_I);
> +	if (reg == 0xff)
> +		/* no vga present */
> +		return false;
> +
> +	outb(VGA_GFX_MISC, VGA_GFX_I);
> +	reg = inb(VGA_GFX_D);
> +	if (reg & 0x01)
> +		/* vga is in gfx mode */
> +		return false;
> +
> +	return true;
> +}
> +
> +static __init void coreboot_fb_init(struct cb_framebuffer *fb)
> +{
> +	const char *reason = "";
> +	struct simplefb_platform_data mode;
> +	struct screen_info si;
> +	struct resource res;
> +
> +	pr_info("coreboot: framebuffer: %dx%d, %d bpp, at %llx\n",
> +		fb->x_resolution,
> +		fb->y_resolution,
> +		fb->bits_per_pixel,
> +		fb->physical_address);
> +
> +	if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB) {
> +		reason = "have vesa lfb";
> +		goto skip;
> +	}
> +	if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI) {
> +		reason = "have efi gop";
> +		goto skip;
> +	}
> +	if (check_vga_text_mode()) {
> +		reason = "vga is in text mode";
> +		goto skip;
> +	}
> +
> +	memset(&si, 0, sizeof(si));
> +	si.orig_video_isVGA = VIDEO_TYPE_VLFB;
> +	si.lfb_width        = fb->x_resolution;
> +	si.lfb_height       = fb->y_resolution;
> +	si.lfb_depth        = fb->bits_per_pixel;
> +	si.lfb_base         = fb->physical_address;
> +	si.lfb_linelength   = fb->bytes_per_line;
> +	si.lfb_size         =
> +		(fb->y_resolution * fb->bytes_per_line + 65535) / 65536;
> +	si.pages            = 1;
> +	si.red_size         = fb->red_mask_size;
> +	si.red_pos          = fb->red_mask_pos;
> +	si.green_size       = fb->green_mask_size;
> +	si.green_pos        = fb->green_mask_pos;
> +	si.blue_size        = fb->blue_mask_size;
> +	si.blue_pos         = fb->blue_mask_pos;
> +	si.rsvd_size        = fb->reserved_mask_size;
> +	si.rsvd_pos         = fb->reserved_mask_pos;
> +	if (!parse_mode(&si, &mode)) {
> +		reason = "mode not compatible";
> +		goto skip;
> +	}
> +
> +	memset(&res, 0, sizeof(res));
> +	res.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
> +	res.name = "coreboot-fb";
> +	res.start = si.lfb_base;
> +	res.end = si.lfb_base + si.lfb_size * 65536 - 1;
> +
> +	pr_info("coreboot: setting up simplefb\n");
> +	platform_device_register_resndata(NULL, "simple-framebuffer", 0,
> +					  &res, 1, &mode, sizeof(mode));
> +	return;
> +
> +skip:
> +	pr_info("coreboot: skipping framebuffer setup (%s)\n", reason);
> +	return;
> +}
> +
> +static __init int coreboot_detect(void)
> +{
> +	struct cb_header *cbh;
> +	struct cb_entry *cbe;
> +	u64 addr = 0;
> +	void *next;
> +	int i;
> +
> +newheader:
> +	cbh = coreboot_find_header(addr, 0x1000);
> +	if (!cbh)
> +		return 0;
> +
> +	next = cbh + 1;
> +	for (i = 0; i < cbh->table_entries; i++) {
> +		cbe = next;
> +		next += cbe->size;
> +		switch (cbe->tag) {
> +		case CB_TAG_MAINBOARD:
> +			pr_info("coreboot: mainboard: %s / %s\n",
> +				cbe->u.mb.strings + cbe->u.mb.vendor_idx,
> +				cbe->u.mb.strings + cbe->u.mb.part_idx);
> +			break;
> +		case CB_TAG_VERSION:
> +			pr_info("coreboot: version: %s\n",
> +				cbe->u.string);
> +			break;
> +		case CB_TAG_FORWARD:
> +			pr_debug("coreboot: forward to 0x%llx\n",
> +				 cbe->u.forward);
> +			addr = cbe->u.forward;
> +			kfree(cbh);
> +			goto newheader;
> +		case CB_TAG_FRAMEBUFFER:
> +			coreboot_fb_init(&cbe->u.fb);
> +			break;
> +		default:
> +			pr_debug("%s: unhandled tag 0x%x (size %d)\n",
> +				 __func__, cbe->tag, cbe->size);
> +			break;
> +		}
> +	}
> +
> +	kfree(cbh);
> +	return 0;
> +}
> +
> +device_initcall(coreboot_detect);
> 


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 213 bytes
Desc: OpenPGP digital signature
URL: <http://www.coreboot.org/pipermail/coreboot/attachments/20140904/7e0b948b/attachment-0001.asc>


More information about the coreboot mailing list