[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