diff options
-rw-r--r-- | sys/arch/amd64/amd64/efifb.c | 215 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/mainbus.c | 4 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/wscons_machdep.c | 6 | ||||
-rw-r--r-- | sys/arch/amd64/include/efifbvar.h | 5 |
4 files changed, 195 insertions, 35 deletions
diff --git a/sys/arch/amd64/amd64/efifb.c b/sys/arch/amd64/amd64/efifb.c index efc7334936a..2cd59e122f2 100644 --- a/sys/arch/amd64/amd64/efifb.c +++ b/sys/arch/amd64/amd64/efifb.c @@ -1,7 +1,8 @@ -/* $OpenBSD: efifb.c,v 1.8 2015/12/01 18:42:56 yasuoka Exp $ */ +/* $OpenBSD: efifb.c,v 1.9 2016/06/21 15:24:55 jcs Exp $ */ /* * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net> + * Copyright (c) 2016 joshua stein <jcs@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -30,11 +31,56 @@ #include <machine/biosvar.h> #include <machine/efifbvar.h> +/* coreboot tables */ + +struct cb_header { + union { + uint8_t signature[4]; /* "LBIO" */ + uint32_t signature32; + }; + uint32_t header_bytes; + uint32_t header_checksum; + uint32_t table_bytes; + uint32_t table_checksum; + uint32_t table_entries; +}; + +struct cb_framebuffer { + uint64_t physical_address; + uint32_t x_resolution; + uint32_t y_resolution; + uint32_t bytes_per_line; + uint8_t bits_per_pixel; + uint8_t red_mask_pos; + uint8_t red_mask_size; + uint8_t green_mask_pos; + uint8_t green_mask_size; + uint8_t blue_mask_pos; + uint8_t blue_mask_size; + uint8_t reserved_mask_pos; + uint8_t reserved_mask_size; +}; + +struct cb_entry { + uint32_t tag; +#define CB_TAG_VERSION 0x0004 +#define CB_TAG_FORWARD 0x0011 +#define CB_TAG_FRAMEBUFFER 0x0012 + uint32_t size; + union { + char string[0]; + uint64_t forward; + struct cb_framebuffer fb; + } u; +}; + struct efifb { struct rasops_info rinfo; int depth; paddr_t paddr; psize_t psize; + + struct cb_framebuffer cb_table_fb; }; struct efifb_softc { @@ -45,6 +91,7 @@ struct efifb_softc { int efifb_match(struct device *, void *, void *); void efifb_attach(struct device *, struct device *, void *); void efifb_rasops_preinit(struct efifb *); +void efifb_rasops_init(void); int efifb_ioctl(void *, u_long, caddr_t, int, struct proc *); paddr_t efifb_mmap(void *, off_t, int); int efifb_alloc_screen(void *, const struct wsscreen_descr *, void **, @@ -55,7 +102,9 @@ int efifb_show_screen(void *, void *, int, void (*cb) (void *, int, int), int efifb_list_font(void *, struct wsdisplay_font *); int efifb_load_font(void *, void *, struct wsdisplay_font *); -struct cfattach efifb_ca = { +struct cb_framebuffer *cb_find_fb(paddr_t); + +const struct cfattach efifb_ca = { sizeof(struct efifb_softc), efifb_match, efifb_attach, NULL }; @@ -112,7 +161,8 @@ efifb_attach(struct device *parent, struct device *self, void *aux) bus_space_handle_t ioh; long defattr; - printf("\n"); + printf(": %dx%d, %dbpp\n", efifb_console.rinfo.ri_width, + efifb_console.rinfo.ri_height, efifb_console.rinfo.ri_depth); if (1) { /* XXX console */ aa.console = 1; @@ -151,16 +201,29 @@ efifb_rasops_preinit(struct efifb *fb) #define bmpos(_x) (ffs(_x) - 1) struct rasops_info *ri = &fb->rinfo; - ri->ri_width = bios_efiinfo->fb_width; - ri->ri_height = bios_efiinfo->fb_height; - ri->ri_depth = fb->depth; - ri->ri_stride = bios_efiinfo->fb_pixpsl * (fb->depth / 8); - ri->ri_rnum = bmnum(bios_efiinfo->fb_red_mask); - ri->ri_rpos = bmpos(bios_efiinfo->fb_red_mask); - ri->ri_gnum = bmnum(bios_efiinfo->fb_green_mask); - ri->ri_gpos = bmpos(bios_efiinfo->fb_green_mask); - ri->ri_bnum = bmnum(bios_efiinfo->fb_blue_mask); - ri->ri_bpos = bmpos(bios_efiinfo->fb_blue_mask); + if (efifb_console.cb_table_fb.x_resolution) { + ri->ri_width = efifb_console.cb_table_fb.x_resolution; + ri->ri_height = efifb_console.cb_table_fb.y_resolution; + ri->ri_depth = fb->depth; + ri->ri_stride = efifb_console.cb_table_fb.bytes_per_line; + ri->ri_rnum = efifb_console.cb_table_fb.red_mask_size; + ri->ri_rpos = efifb_console.cb_table_fb.red_mask_pos; + ri->ri_gnum = efifb_console.cb_table_fb.green_mask_size; + ri->ri_gpos = efifb_console.cb_table_fb.green_mask_pos; + ri->ri_bnum = efifb_console.cb_table_fb.blue_mask_size; + ri->ri_bpos = efifb_console.cb_table_fb.blue_mask_pos; + } else { + ri->ri_width = bios_efiinfo->fb_width; + ri->ri_height = bios_efiinfo->fb_height; + ri->ri_depth = fb->depth; + ri->ri_stride = bios_efiinfo->fb_pixpsl * (fb->depth / 8); + ri->ri_rnum = bmnum(bios_efiinfo->fb_red_mask); + ri->ri_rpos = bmpos(bios_efiinfo->fb_red_mask); + ri->ri_gnum = bmnum(bios_efiinfo->fb_green_mask); + ri->ri_gpos = bmpos(bios_efiinfo->fb_green_mask); + ri->ri_bnum = bmnum(bios_efiinfo->fb_blue_mask); + ri->ri_bpos = bmpos(bios_efiinfo->fb_blue_mask); + } } int @@ -285,8 +348,6 @@ int efifb_cnattach(void) { struct efifb *fb = &efifb_console; - struct rasops_info *ri = &fb->rinfo; - long defattr = 0; if (bios_efiinfo == NULL || bios_efiinfo->fb_addr == 0) return (-1); @@ -302,22 +363,7 @@ efifb_cnattach(void) fb->psize = bios_efiinfo->fb_height * bios_efiinfo->fb_pixpsl * (fb->depth / 8); - ri->ri_bits = (u_char *)PMAP_DIRECT_MAP(fb->paddr); - - efifb_rasops_preinit(fb); - - ri->ri_bs = efifb_bs; - ri->ri_flg = RI_CLEAR | RI_CENTER | RI_WRONLY; - rasops_init(ri, EFIFB_HEIGHT, EFIFB_WIDTH); - efifb_std_descr.ncols = ri->ri_cols; - efifb_std_descr.nrows = ri->ri_rows; - efifb_std_descr.textops = &ri->ri_ops; - efifb_std_descr.fontwidth = ri->ri_font->fontwidth; - efifb_std_descr.fontheight = ri->ri_font->fontheight; - efifb_std_descr.capabilities = ri->ri_caps; - - ri->ri_ops.alloc_attr(ri, 0, 0, 0, &defattr); - wsdisplay_cnattach(&efifb_std_descr, ri, 0, 0, defattr); + efifb_rasops_init(); return (0); } @@ -358,3 +404,110 @@ efifb_cndetach(void) { efifb_console.paddr = 0; } + +void +efifb_rasops_init(void) +{ + struct efifb *fb = &efifb_console; + struct rasops_info *ri = &fb->rinfo; + long defattr = 0; + + ri->ri_bits = (u_char *)PMAP_DIRECT_MAP(fb->paddr); + + efifb_rasops_preinit(fb); + + ri->ri_bs = efifb_bs; + ri->ri_flg = RI_CLEAR | RI_CENTER | RI_WRONLY; + rasops_init(ri, EFIFB_HEIGHT, EFIFB_WIDTH); + efifb_std_descr.ncols = ri->ri_cols; + efifb_std_descr.nrows = ri->ri_rows; + efifb_std_descr.textops = &ri->ri_ops; + efifb_std_descr.fontwidth = ri->ri_font->fontwidth; + efifb_std_descr.fontheight = ri->ri_font->fontheight; + efifb_std_descr.capabilities = ri->ri_caps; + + ri->ri_ops.alloc_attr(ri, 0, 0, 0, &defattr); + wsdisplay_cnattach(&efifb_std_descr, ri, 0, 0, defattr); +} + +int +efifb_cb_cnattach(void) +{ + struct cb_framebuffer *cb_fb = cb_find_fb((paddr_t)0x0); + + if (cb_fb == NULL || !cb_fb->x_resolution) + return (-1); + + memset(&efifb_console, 0, sizeof(efifb_console)); + memcpy(&efifb_console.cb_table_fb, cb_fb, + sizeof(struct cb_framebuffer)); + + efifb_console.paddr = cb_fb->physical_address; + efifb_console.depth = cb_fb->bits_per_pixel; + efifb_console.psize = cb_fb->y_resolution * cb_fb->bytes_per_line; + + efifb_rasops_init(); + + return (0); +} + +int +efifb_cb_found(void) +{ + return (efifb_console.paddr && efifb_console.cb_table_fb.x_resolution); +} + +static uint16_t +cb_checksum(const void *addr, unsigned size) +{ + const uint16_t *p = addr; + unsigned i, n = size / 2; + uint32_t sum = 0; + + for (i = 0; i < n; i++) + sum += p[i]; + + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + sum = ~sum & 0xffff; + + return (uint16_t)sum; +} + +struct cb_framebuffer * +cb_find_fb(paddr_t addr) +{ + int i, j; + + for (i = 0; i < (4 * 1024); i += 16) { + struct cb_header *cbh; + struct cb_entry *cbe; + paddr_t cbtable; + + cbh = (struct cb_header *)(PMAP_DIRECT_MAP(addr + i)); + if (memcmp(cbh->signature, "LBIO", 4) != 0) + continue; + + if (!cbh->header_bytes) + continue; + + if (cb_checksum(cbh, sizeof(*cbh)) != 0) + return NULL; + + cbtable = PMAP_DIRECT_MAP(addr + i + cbh->header_bytes); + + for (j = 0; j < cbh->table_bytes; j += cbe->size) { + cbe = (struct cb_entry *)((char *)cbtable + j); + + switch (cbe->tag) { + case CB_TAG_FORWARD: + return cb_find_fb(cbe->u.forward); + + case CB_TAG_FRAMEBUFFER: + return &cbe->u.fb; + } + } + } + + return NULL; +} diff --git a/sys/arch/amd64/amd64/mainbus.c b/sys/arch/amd64/amd64/mainbus.c index 5018938ff8c..4afbae1b39f 100644 --- a/sys/arch/amd64/amd64/mainbus.c +++ b/sys/arch/amd64/amd64/mainbus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mainbus.c,v 1.36 2015/12/12 12:33:49 reyk Exp $ */ +/* $OpenBSD: mainbus.c,v 1.37 2016/06/21 15:24:55 jcs Exp $ */ /* $NetBSD: mainbus.c,v 1.1 2003/04/26 18:39:29 fvdl Exp $ */ /* @@ -253,7 +253,7 @@ mainbus_attach(struct device *parent, struct device *self, void *aux) #endif /* NVMM > 0 */ #if NEFIFB > 0 - if (bios_efiinfo != NULL) { + if (bios_efiinfo != NULL || efifb_cb_found()) { mba.mba_eaa.eaa_name = "efifb"; config_found(self, &mba, mainbus_print); } diff --git a/sys/arch/amd64/amd64/wscons_machdep.c b/sys/arch/amd64/amd64/wscons_machdep.c index 9f1f8a6a041..461441c4d43 100644 --- a/sys/arch/amd64/amd64/wscons_machdep.c +++ b/sys/arch/amd64/amd64/wscons_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: wscons_machdep.c,v 1.12 2016/03/06 22:41:24 naddy Exp $ */ +/* $OpenBSD: wscons_machdep.c,v 1.13 2016/06/21 15:24:55 jcs Exp $ */ /* * Copyright (c) 2001 Aaron Campbell @@ -147,6 +147,10 @@ wscn_video_init(void) if (vga_cnattach(X86_BUS_SPACE_IO, X86_BUS_SPACE_MEM, -1, 1) == 0) return (0); #endif +#if (NEFIFB > 0) + if (efifb_cb_cnattach() == 0) + return (0); +#endif #if (NPCDISPLAY > 0) if (pcdisplay_cnattach(X86_BUS_SPACE_IO, X86_BUS_SPACE_MEM) == 0) return (0); diff --git a/sys/arch/amd64/include/efifbvar.h b/sys/arch/amd64/include/efifbvar.h index 67bfdb33ecd..f5e2bb26cae 100644 --- a/sys/arch/amd64/include/efifbvar.h +++ b/sys/arch/amd64/include/efifbvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: efifbvar.h,v 1.3 2015/10/30 11:21:01 kettenis Exp $ */ +/* $OpenBSD: efifbvar.h,v 1.4 2016/06/21 15:24:55 jcs Exp $ */ /* * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net> @@ -29,4 +29,7 @@ int efifb_cnattach(void); int efifb_is_console(struct pci_attach_args *); void efifb_cndetach(void); +int efifb_cb_found(void); +int efifb_cb_cnattach(void); + #endif /* _MACHINE_EFIFB_H_ */ |