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 <kra...@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); >
signature.asc
Description: OpenPGP digital signature
-- coreboot mailing list: coreboot@coreboot.org http://www.coreboot.org/mailman/listinfo/coreboot