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.
This commit is contained in:
jkim 2010-08-25 22:09:02 +00:00
parent 4cbbeb5cda
commit fbe278c343

View File

@ -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)