summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/amd64/amd64/efifb.c215
-rw-r--r--sys/arch/amd64/amd64/mainbus.c4
-rw-r--r--sys/arch/amd64/amd64/wscons_machdep.c6
-rw-r--r--sys/arch/amd64/include/efifbvar.h5
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_ */