aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/fb/vesa.c
diff options
context:
space:
mode:
authorJung-uk Kim <jkim@FreeBSD.org>2010-08-25 22:09:02 +0000
committerJung-uk Kim <jkim@FreeBSD.org>2010-08-25 22:09:02 +0000
commita73f383ee91d6e75879bc16d7dd2a91a0630b369 (patch)
tree19563808acf680cdd390790a0ed75c27f962905f /sys/dev/fb/vesa.c
parent81f6480d42b7f4ee008398fcc839c489bc1a140f (diff)
downloadsrc-a73f383ee91d6e75879bc16d7dd2a91a0630b369.tar.gz
src-a73f383ee91d6e75879bc16d7dd2a91a0630b369.zip
Add an experimental feature to shadow video BIOS. Long ago, this trick was
supported by many BIOSes to improve performance of VESA BIOS calls for real mode OSes but it is not our intention here. However, this may help some platforms where the video ROMs are inaccessible after suspend, for example. Note it may consume up to 64K bytes of contiguous memory depending on video controller model when it is enabled. This feature can be disabled by setting zero to 'debug.vesa.shadow_rom' loader tunable via loader(8) or loader.conf(5). The default is 1 (enabled), for now.
Notes
Notes: svn path=/head/; revision=211827
Diffstat (limited to 'sys/dev/fb/vesa.c')
-rw-r--r--sys/dev/fb/vesa.c67
1 files changed, 57 insertions, 10 deletions
diff --git a/sys/dev/fb/vesa.c b/sys/dev/fb/vesa.c
index d369175bb92b..96a8aaa8c928 100644
--- a/sys/dev/fb/vesa.c
+++ b/sys/dev/fb/vesa.c
@@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/fbio.h>
+#include <sys/sysctl.h>
#include <vm/vm.h>
#include <vm/vm_extern.h>
@@ -61,6 +62,8 @@ __FBSDID("$FreeBSD$");
#include <compat/x86bios/x86bios.h>
+#define VESA_BIOS_OFFSET 0xc0000
+#define VESA_PALETTE_SIZE (256 * 4)
#define VESA_VIA_CLE266 "VIA CLE266\r\n"
#ifndef VESA_DEBUG
@@ -83,11 +86,21 @@ static ssize_t vesa_state_buf_size = 0;
static u_char *vesa_palette = NULL;
static uint32_t vesa_palette_offs = 0;
-#define VESA_PALETTE_SIZE (256 * 4)
+
+static void *vesa_bios = NULL;
+static uint32_t vesa_bios_offs = VESA_BIOS_OFFSET;
+static uint32_t vesa_bios_int10 = 0;
+static size_t vesa_bios_size = 0;
/* VESA video adapter */
static video_adapter_t *vesa_adp = NULL;
+SYSCTL_NODE(_debug, OID_AUTO, vesa, CTLFLAG_RD, NULL, "VESA debugging");
+static int vesa_shadow_rom = 1;
+TUNABLE_INT("debug.vesa.shadow_rom", &vesa_shadow_rom);
+SYSCTL_INT(_debug_vesa, OID_AUTO, shadow_rom, CTLFLAG_RDTUN, &vesa_shadow_rom,
+ 1, "Enable video BIOS shadow");
+
/* VESA functions */
#if 0
static int vesa_nop(void);
@@ -242,7 +255,7 @@ vesa_bios_post(void)
device_t dev;
int count, i, is_pci;
- if (x86bios_get_orm(0xc0000) == NULL)
+ if (x86bios_get_orm(vesa_bios_offs) == NULL)
return (1);
dev = NULL;
@@ -253,7 +266,7 @@ vesa_bios_post(void)
if (dc != NULL && devclass_get_devices(dc, &devs, &count) == 0) {
for (i = 0; i < count; i++)
if (device_get_flags(devs[i]) != 0 &&
- x86bios_match_device(0xc0000, devs[i])) {
+ x86bios_match_device(vesa_bios_offs, devs[i])) {
dev = devs[i];
is_pci = 1;
break;
@@ -279,7 +292,8 @@ vesa_bios_post(void)
(pci_get_function(dev) & 0x07);
}
regs.R_DL = 0x80;
- x86bios_call(&regs, 0xc000, 0x0003);
+ x86bios_call(&regs, X86BIOS_PHYSTOSEG(vesa_bios_offs + 3),
+ X86BIOS_PHYSTOOFF(vesa_bios_offs + 3));
if (x86bios_get_intr(0x10) == 0)
return (1);
@@ -754,6 +768,7 @@ vesa_bios_init(void)
size_t bsize;
size_t msize;
void *vmbuf;
+ uint8_t *vbios;
uint32_t offs;
uint16_t vers;
int is_via_cle266;
@@ -765,22 +780,44 @@ vesa_bios_init(void)
has_vesa_bios = FALSE;
vesa_adp_info = NULL;
+ vesa_bios_offs = VESA_BIOS_OFFSET;
vesa_vmode_max = 0;
vesa_vmode[0].vi_mode = EOT;
/*
* If the VBE real mode interrupt vector is not found, try BIOS POST.
*/
- if (x86bios_get_intr(0x10) == 0) {
+ vesa_bios_int10 = x86bios_get_intr(0x10);
+ if (vesa_bios_int10 == 0) {
if (vesa_bios_post() != 0)
return (1);
- if (bootverbose) {
- offs = x86bios_get_intr(0x10);
- printf("VESA: interrupt vector installed (0x%x)\n",
- BIOS_SADDRTOLADDR(offs));
- }
+ vesa_bios_int10 = x86bios_get_intr(0x10);
+ if (vesa_bios_int10 == 0)
+ return (1);
}
+ /*
+ * Shadow video ROM.
+ */
+ offs = BIOS_SADDRTOLADDR(vesa_bios_int10);
+ if (vesa_shadow_rom) {
+ vbios = x86bios_get_orm(vesa_bios_offs);
+ if (vbios != NULL) {
+ vesa_bios_size = vbios[2] * 512;
+ vesa_bios = x86bios_alloc(&vesa_bios_offs,
+ vesa_bios_size, M_WAITOK);
+ memcpy(vesa_bios, vbios, vesa_bios_size);
+ offs = offs - VESA_BIOS_OFFSET + vesa_bios_offs;
+ offs = (X86BIOS_PHYSTOSEG(offs) << 16) +
+ X86BIOS_PHYSTOOFF(offs);
+ x86bios_set_intr(0x10, offs);
+ } else
+ printf("VESA: failed to shadow video ROM\n");
+ }
+ if (bootverbose)
+ printf("VESA: INT 0x10 vector 0x%04x:0x%04x\n",
+ X86BIOS_PHYSTOSEG(offs), X86BIOS_PHYSTOOFF(offs));
+
x86bios_init_regs(&regs);
regs.R_AX = 0x4f00;
@@ -1011,6 +1048,12 @@ vesa_bios_init(void)
return (0);
fail:
+ if (vesa_bios != NULL) {
+ x86bios_set_intr(0x10, vesa_bios_int10);
+ vesa_bios_offs = VESA_BIOS_OFFSET;
+ x86bios_free(vesa_bios, vesa_bios_size);
+ vesa_bios = NULL;
+ }
if (vmbuf != NULL)
x86bios_free(vmbuf, sizeof(buf));
if (vesa_adp_info != NULL) {
@@ -1862,6 +1905,10 @@ vesa_unload(void)
}
}
+ if (vesa_bios != NULL) {
+ x86bios_set_intr(0x10, vesa_bios_int10);
+ x86bios_free(vesa_bios, vesa_bios_size);
+ }
if (vesa_adp_info != NULL)
free(vesa_adp_info, M_DEVBUF);
if (vesa_oemstr != NULL)