svn commit: r198251 - in head/sys: compat/x86bios conf contrib/x86emu dev/atkbdc dev/dpms dev/fb dev/pci modules/dpms modules/vesa modules/x86bios

Jung-uk Kim jkim at FreeBSD.org
Mon Oct 19 20:58:11 UTC 2009


Author: jkim
Date: Mon Oct 19 20:58:10 2009
New Revision: 198251
URL: http://svn.freebsd.org/changeset/base/198251

Log:
  Rewrite x86bios and update its dependent drivers.
  
  - Do not map entire real mode memory (1MB).  Instead, we map IVT/BDA and
  ROM area separately.  Most notably, ROM area is mapped as device memory
  (uncacheable) as it should be.  User memory is dynamically allocated and
  free'ed with contigmalloc(9) and contigfree(9).  Remove now redundant and
  potentially dangerous x86bios_alloc.c.  If this emulator ever grows to
  support non-PC hardware, we may implement it with rman(9) later.
  - Move all host-specific initializations from x86emu_util.c to x86bios.c and
  remove now unnecessary x86emu_util.c.  Currently, non-PC hardware is not
  supported.  We may use bus_space(9) later when the KPI is fixed.
  - Replace all bzero() calls for emulated registers with more obviously named
  x86bios_init_regs().  This function also initializes DS and SS properly.
  - Add x86bios_get_intr().  This function checks if the interrupt vector is
  available for the platform.  It is not necessary for PC-compatible hardware
  but it may be needed later. ;-)
  - Do not try turning off monitor if DPMS does not support the state.
  - Allocate stable memory for VESA OEM strings instead of just holding
  pointers to them.  They may or may not be accessible always.  Fix a memory
  leak of video mode table while I am here.
  - Add (experimental) BIOS POST call for vesa(4).  This function calls VGA
  BIOS POST code from the current VGA option ROM.  Some video controllers
  cannot save and restore the state properly even if it is claimed to be
  supported.  Usually the symptom is blank display after resuming from suspend
  state.  If the video mode does not match the previous mode after restoring,
  we try BIOS POST and force the known good initial state.  Some magic was
  taken from NetBSD (and it was taken from vbetool, I believe.)
  - Add a loader tunable for vgapci(4) to give a hint to dpms(4) and vesa(4)
  to identify who owns the VESA BIOS.  This is very useful for multi-display
  adapter setup.  By default, the POST video controller is automatically
  probed and the tunable "hw.pci.default_vgapci_unit" is set to corresponding
  vgapci unit number.  You may override it from loader but it is very unlikely
  to be necessary.  Unfortunately only AGP/PCI/PCI-E controllers can be
  matched because ISA controller does not have necessary device IDs.
  - Fix a long standing bug in state save/restore function.  The state buffer
  pointer should be ES:BX, not ES:DI according to VBE 3.0.  If it ever worked,
  that's because BX was always zero. :-)
  - Clean up register initializations more clearer per VBE 3.0.
  - Fix a lot of style issues with vesa(4).

Deleted:
  head/sys/compat/x86bios/x86bios_alloc.c
  head/sys/contrib/x86emu/x86emu_util.c
Modified:
  head/sys/compat/x86bios/x86bios.c
  head/sys/compat/x86bios/x86bios.h
  head/sys/conf/files.amd64
  head/sys/conf/files.i386
  head/sys/dev/atkbdc/atkbd.c
  head/sys/dev/dpms/dpms.c
  head/sys/dev/fb/vesa.c
  head/sys/dev/pci/vga_pci.c
  head/sys/modules/dpms/Makefile
  head/sys/modules/vesa/Makefile
  head/sys/modules/x86bios/Makefile

Modified: head/sys/compat/x86bios/x86bios.c
==============================================================================
--- head/sys/compat/x86bios/x86bios.c	Mon Oct 19 20:51:27 2009	(r198250)
+++ head/sys/compat/x86bios/x86bios.c	Mon Oct 19 20:58:10 2009	(r198251)
@@ -1,5 +1,6 @@
 /*-
  * Copyright (c) 2009 Alex Keda <admin at lissyara.su>
+ * Copyright (c) 2009 Jung-uk Kim <jkim at FreeBSD.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -22,7 +23,6 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- *
  */
 
 #include <sys/cdefs.h>
@@ -31,29 +31,153 @@ __FBSDID("$FreeBSD$");
 #include "opt_x86bios.h"
 
 #include <sys/param.h>
+#include <sys/bus.h>
 #include <sys/kernel.h>
 #include <sys/lock.h>
+#include <sys/malloc.h>
 #include <sys/module.h>
 #include <sys/mutex.h>
+#include <sys/proc.h>
+
+#include <contrib/x86emu/x86emu.h>
+#include <contrib/x86emu/x86emu_regs.h>
+#include <compat/x86bios/x86bios.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <machine/cpufunc.h>
 
 #include <vm/vm.h>
 #include <vm/pmap.h>
 
-#include <machine/cpufunc.h>
+#define	X86BIOS_PAGE_SIZE	0x00001000	/* 4K */
 
-#include <contrib/x86emu/x86emu.h>
-#include <contrib/x86emu/x86emu_regs.h>
-#include <compat/x86bios/x86bios.h>
+#define	X86BIOS_IVT_SIZE	0x00000500	/* 1K + 256 (BDA) */
+#define	X86BIOS_SEG_SIZE	0x00010000	/* 64K */
+#define	X86BIOS_MEM_SIZE	0x00100000	/* 1M */
+
+#define	X86BIOS_IVT_BASE	0x00000000
+#define	X86BIOS_RAM_BASE	0x00001000
+#define	X86BIOS_ROM_BASE	0x000a0000	/* XXX EBDA? */
 
-u_char *pbiosMem = NULL;
-static u_char *pbiosStack = NULL;
+#define	X86BIOS_ROM_SIZE	(X86BIOS_MEM_SIZE - X86BIOS_ROM_BASE)
 
-int busySegMap[5];
+#define	X86BIOS_PAGES		(X86BIOS_MEM_SIZE / X86BIOS_PAGE_SIZE)
+
+#define	X86BIOS_R_DS		_pad1
+#define	X86BIOS_R_SS		_pad2
 
 static struct x86emu x86bios_emu;
 
 static struct mtx x86bios_lock;
 
+static void *x86bios_ivt;
+static void *x86bios_rom;
+static void *x86bios_seg;
+
+static vm_offset_t *x86bios_map;
+
+static vm_paddr_t x86bios_seg_phys;
+
+static void *
+x86bios_get_pages(uint32_t offset, size_t size)
+{
+	int i;
+
+	if (offset + size > X86BIOS_MEM_SIZE)
+		return (NULL);
+
+	i = offset / X86BIOS_PAGE_SIZE;
+	if (x86bios_map[i] != 0)
+		return ((void *)(x86bios_map[i] + offset -
+		    i * X86BIOS_PAGE_SIZE));
+
+	return (NULL);
+}
+
+static void
+x86bios_set_pages(vm_offset_t va, vm_paddr_t pa, size_t size)
+{
+	int i, j;
+
+	for (i = pa / X86BIOS_PAGE_SIZE, j = 0;
+	    j < howmany(size, X86BIOS_PAGE_SIZE); i++, j++)
+		x86bios_map[i] = va + j * X86BIOS_PAGE_SIZE;
+}
+
+static uint8_t
+x86bios_emu_rdb(struct x86emu *emu, uint32_t addr)
+{
+	uint8_t *va;
+
+	va = x86bios_get_pages(addr, sizeof(*va));
+	if (va == NULL)
+		x86emu_halt_sys(emu);
+
+	return (*va);
+}
+
+static uint16_t
+x86bios_emu_rdw(struct x86emu *emu, uint32_t addr)
+{
+	uint16_t *va;
+
+	va = x86bios_get_pages(addr, sizeof(*va));
+	if (va == NULL)
+		x86emu_halt_sys(emu);
+
+	return (le16toh(*va));
+}
+
+static uint32_t
+x86bios_emu_rdl(struct x86emu *emu, uint32_t addr)
+{
+	uint32_t *va;
+
+	va = x86bios_get_pages(addr, sizeof(*va));
+	if (va == NULL)
+		x86emu_halt_sys(emu);
+
+	return (le32toh(*va));
+}
+
+static void
+x86bios_emu_wrb(struct x86emu *emu, uint32_t addr, uint8_t val)
+{
+	uint8_t *va;
+
+	va = x86bios_get_pages(addr, sizeof(*va));
+	if (va == NULL)
+		x86emu_halt_sys(emu);
+
+	*va = val;
+}
+
+static void
+x86bios_emu_wrw(struct x86emu *emu, uint32_t addr, uint16_t val)
+{
+	uint16_t *va;
+
+	va = x86bios_get_pages(addr, sizeof(*va));
+	if (va == NULL)
+		x86emu_halt_sys(emu);
+
+	*va = htole16(val);
+}
+
+static void
+x86bios_emu_wrl(struct x86emu *emu, uint32_t addr, uint32_t val)
+{
+	uint32_t *va;
+
+	va = x86bios_get_pages(addr, sizeof(*va));
+	if (va == NULL)
+		x86emu_halt_sys(emu);
+
+	*va = htole32(val);
+}
+
 static uint8_t
 x86bios_emu_inb(struct x86emu *emu, uint16_t port)
 {
@@ -62,6 +186,7 @@ x86bios_emu_inb(struct x86emu *emu, uint
 		return (0);
 	if (port >= 0x80 && port < 0x88) /* POST status register */
 		return (0);
+
 	return (inb(port));
 }
 
@@ -71,6 +196,7 @@ x86bios_emu_inw(struct x86emu *emu, uint
 
 	if (port >= 0x80 && port < 0x88) /* POST status register */
 		return (0);
+
 	return (inw(port));
 }
 
@@ -80,6 +206,7 @@ x86bios_emu_inl(struct x86emu *emu, uint
 
 	if (port >= 0x80 && port < 0x88) /* POST status register */
 		return (0);
+
 	return (inl(port));
 }
 
@@ -91,6 +218,7 @@ x86bios_emu_outb(struct x86emu *emu, uin
 		return;
 	if (port >= 0x80 && port < 0x88) /* POST status register */
 		return;
+
 	outb(port, val);
 }
 
@@ -100,6 +228,7 @@ x86bios_emu_outw(struct x86emu *emu, uin
 
 	if (port >= 0x80 && port < 0x88) /* POST status register */
 		return;
+
 	outw(port, val);
 }
 
@@ -109,9 +238,109 @@ x86bios_emu_outl(struct x86emu *emu, uin
 
 	if (port >= 0x80 && port < 0x88) /* POST status register */
 		return;
+
 	outl(port, val);
 }
 
+static void
+x86bios_emu_get_intr(struct x86emu *emu, int intno)
+{
+	uint16_t *sp;
+	uint32_t iv;
+
+	emu->x86.R_SP -= 6;
+
+	sp = (uint16_t *)((vm_offset_t)x86bios_seg + emu->x86.R_SP);
+	sp[0] = htole16(emu->x86.R_IP);
+	sp[1] = htole16(emu->x86.R_CS);
+	sp[2] = htole16(emu->x86.R_FLG);
+
+	iv = x86bios_get_intr(intno);
+	emu->x86.R_IP = iv & 0x000f;
+	emu->x86.R_CS = (iv >> 12) & 0xffff;
+	emu->x86.R_FLG &= ~(F_IF | F_TF);
+}
+
+void *
+x86bios_alloc(uint32_t *offset, size_t size)
+{
+	void *vaddr;
+
+	if (offset == NULL || size == 0)
+		return (NULL);
+
+	vaddr = contigmalloc(size, M_DEVBUF, M_NOWAIT, X86BIOS_RAM_BASE,
+	    X86BIOS_ROM_BASE, X86BIOS_PAGE_SIZE, 0);
+	if (vaddr != NULL) {
+		*offset = vtophys(vaddr);
+		x86bios_set_pages((vm_offset_t)vaddr, *offset, size);
+	}
+
+	return (vaddr);
+}
+
+void
+x86bios_free(void *addr, size_t size)
+{
+	vm_paddr_t paddr;
+
+	if (addr == NULL || size == 0)
+		return;
+
+	paddr = vtophys(addr);
+	if (paddr < X86BIOS_RAM_BASE || paddr >= X86BIOS_ROM_BASE ||
+	    paddr % X86BIOS_PAGE_SIZE != 0)
+		return;
+
+	bzero(x86bios_map + paddr / X86BIOS_PAGE_SIZE,
+	    sizeof(*x86bios_map) * howmany(size, X86BIOS_PAGE_SIZE));
+	contigfree(addr, size, M_DEVBUF);
+}
+
+void
+x86bios_init_regs(struct x86regs *regs)
+{
+
+	bzero(regs, sizeof(*regs));
+	regs->X86BIOS_R_DS = regs->X86BIOS_R_SS = x86bios_seg_phys >> 4;
+}
+
+void
+x86bios_call(struct x86regs *regs, uint16_t seg, uint16_t off)
+{
+
+	if (x86bios_map == NULL)
+		return;
+
+	if (bootverbose)
+		printf("Calling 0x%05x (ax=0x%04x bx=0x%04x "
+		    "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n",
+		    (seg << 4) + off, regs->R_AX, regs->R_BX, regs->R_CX,
+		    regs->R_DX, regs->R_ES, regs->R_DI);
+
+	mtx_lock_spin(&x86bios_lock);
+	memcpy(&x86bios_emu.x86, regs, sizeof(*regs));
+	x86emu_exec_call(&x86bios_emu, seg, off);
+	memcpy(regs, &x86bios_emu.x86, sizeof(*regs));
+	mtx_unlock_spin(&x86bios_lock);
+
+	if (bootverbose)
+		printf("Exiting 0x%05x (ax=0x%04x bx=0x%04x "
+		    "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n",
+		    (seg << 4) + off, regs->R_AX, regs->R_BX, regs->R_CX,
+		    regs->R_DX, regs->R_ES, regs->R_DI);
+}
+
+uint32_t
+x86bios_get_intr(int intno)
+{
+	uint32_t *iv;
+
+	iv = (uint32_t *)((vm_offset_t)x86bios_ivt + intno * 4);
+
+	return (le32toh(*iv));
+}
+
 void
 x86bios_intr(struct x86regs *regs, int intno)
 {
@@ -119,6 +348,9 @@ x86bios_intr(struct x86regs *regs, int i
 	if (intno < 0 || intno > 255)
 		return;
 
+	if (x86bios_map == NULL)
+		return;
+
 	if (bootverbose)
 		printf("Calling int 0x%x (ax=0x%04x bx=0x%04x "
 		    "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n",
@@ -126,11 +358,9 @@ x86bios_intr(struct x86regs *regs, int i
 		    regs->R_DX, regs->R_ES, regs->R_DI);
 
 	mtx_lock_spin(&x86bios_lock);
-
 	memcpy(&x86bios_emu.x86, regs, sizeof(*regs));
 	x86emu_exec_intr(&x86bios_emu, intno);
 	memcpy(regs, &x86bios_emu.x86, sizeof(*regs));
-
 	mtx_unlock_spin(&x86bios_lock);
 
 	if (bootverbose)
@@ -141,24 +371,112 @@ x86bios_intr(struct x86regs *regs, int i
 }
 
 void *
-x86bios_offset(uint32_t offs)
+x86bios_offset(uint32_t offset)
+{
+
+	return (x86bios_get_pages(offset, 1));
+}
+
+void *
+x86bios_get_orm(uint32_t offset)
 {
+	uint8_t *p;
+
+	/* Does the shadow ROM contain BIOS POST code for x86? */
+	p = x86bios_offset(offset);
+	if (p == NULL || p[0] != 0x55 || p[1] != 0xaa || p[3] != 0xe9)
+		return (NULL);
 
-	return (pbiosMem + offs);
+	return (p);
+}
+
+int
+x86bios_match_device(uint32_t offset, device_t dev)
+{
+	uint8_t *p;
+	uint16_t device, vendor;
+	uint8_t class, progif, subclass;
+
+	/* Does the shadow ROM contain BIOS POST code for x86? */
+	p = x86bios_get_orm(offset);
+	if (p == NULL)
+		return (0);
+
+	/* Does it contain PCI data structure? */
+	p += le16toh(*(uint16_t *)(p + 0x18));
+	if (bcmp(p, "PCIR", 4) != 0 ||
+	    le16toh(*(uint16_t *)(p + 0x0a)) < 0x18 || *(p + 0x14) != 0)
+		return (0);
+
+	/* Does it match the vendor, device, and classcode? */
+	vendor = le16toh(*(uint16_t *)(p + 0x04));
+	device = le16toh(*(uint16_t *)(p + 0x06));
+	progif = *(p + 0x0d);
+	subclass = *(p + 0x0e);
+	class = *(p + 0x0f);
+	if (vendor != pci_get_vendor(dev) || device != pci_get_device(dev) ||
+	    class != pci_get_class(dev) || subclass != pci_get_subclass(dev) ||
+	    progif != pci_get_progif(dev))
+		return (0);
+
+	return (1);
+}
+
+static __inline int
+x86bios_map_mem(void)
+{
+
+	x86bios_ivt = pmap_mapdev(X86BIOS_IVT_BASE, X86BIOS_IVT_SIZE);
+	if (x86bios_ivt == NULL)
+		return (1);
+	x86bios_rom = pmap_mapdev(X86BIOS_ROM_BASE, X86BIOS_ROM_SIZE);
+	if (x86bios_rom == NULL) {
+		pmap_unmapdev((vm_offset_t)x86bios_ivt, X86BIOS_IVT_SIZE);
+		return (1);
+	}
+	x86bios_seg = contigmalloc(X86BIOS_SEG_SIZE, M_DEVBUF, M_WAITOK,
+	    X86BIOS_RAM_BASE, X86BIOS_ROM_BASE, X86BIOS_PAGE_SIZE, 0);
+	x86bios_seg_phys = vtophys(x86bios_seg);
+
+	return (0);
+}
+
+static __inline void
+x86bios_unmap_mem(void)
+{
+
+	pmap_unmapdev((vm_offset_t)x86bios_ivt, X86BIOS_IVT_SIZE);
+	pmap_unmapdev((vm_offset_t)x86bios_rom, X86BIOS_ROM_SIZE);
+	contigfree(x86bios_seg, X86BIOS_SEG_SIZE, M_DEVBUF);
 }
 
 static void
 x86bios_init(void *arg __unused)
 {
-	int offs;
+	int i;
 
 	mtx_init(&x86bios_lock, "x86bios lock", NULL, MTX_SPIN);
 
-	/* Can pbiosMem be NULL here? */
-	pbiosMem = pmap_mapbios(0x0, MAPPED_MEMORY_SIZE);
+	if (x86bios_map_mem() != 0)
+		return;
 
-	memset(&x86bios_emu, 0, sizeof(x86bios_emu));
-	x86emu_init_default(&x86bios_emu);
+	x86bios_map = malloc(sizeof(*x86bios_map) * X86BIOS_PAGES, M_DEVBUF,
+	    M_WAITOK | M_ZERO);
+	x86bios_set_pages((vm_offset_t)x86bios_ivt, X86BIOS_IVT_BASE,
+	    X86BIOS_IVT_SIZE);
+	x86bios_set_pages((vm_offset_t)x86bios_rom, X86BIOS_ROM_BASE,
+	    X86BIOS_ROM_SIZE);
+	x86bios_set_pages((vm_offset_t)x86bios_seg, x86bios_seg_phys,
+	    X86BIOS_SEG_SIZE);
+
+	bzero(&x86bios_emu, sizeof(x86bios_emu));
+
+	x86bios_emu.emu_rdb = x86bios_emu_rdb;
+	x86bios_emu.emu_rdw = x86bios_emu_rdw;
+	x86bios_emu.emu_rdl = x86bios_emu_rdl;
+	x86bios_emu.emu_wrb = x86bios_emu_wrb;
+	x86bios_emu.emu_wrw = x86bios_emu_wrw;
+	x86bios_emu.emu_wrl = x86bios_emu_wrl;
 
 	x86bios_emu.emu_inb = x86bios_emu_inb;
 	x86bios_emu.emu_inw = x86bios_emu_inw;
@@ -167,23 +485,24 @@ x86bios_init(void *arg __unused)
 	x86bios_emu.emu_outw = x86bios_emu_outw;
 	x86bios_emu.emu_outl = x86bios_emu_outl;
 
-	x86bios_emu.mem_base = (char *)pbiosMem;
-	x86bios_emu.mem_size = MAPPED_MEMORY_SIZE;
-
-	memset(busySegMap, 0, sizeof(busySegMap));
-
-	pbiosStack = x86bios_alloc(1, &offs);
+	for (i = 0; i < 256; i++)
+		x86bios_emu._x86emu_intrTab[i] = x86bios_emu_get_intr;
 }
 
 static void
 x86bios_uninit(void *arg __unused)
 {
+	vm_offset_t *map = x86bios_map;
 
-	x86bios_free(pbiosStack, 1);
+	mtx_lock_spin(&x86bios_lock);
+	if (x86bios_map != NULL) {
+		free(x86bios_map, M_DEVBUF);
+		x86bios_map = NULL;
+	}
+	mtx_unlock_spin(&x86bios_lock);
 
-	if (pbiosMem)
-		pmap_unmapdev((vm_offset_t)pbiosMem,
-		    MAPPED_MEMORY_SIZE);
+	if (map != NULL)
+		x86bios_unmap_mem();
 
 	mtx_destroy(&x86bios_lock);
 }
@@ -191,7 +510,6 @@ x86bios_uninit(void *arg __unused)
 static int
 x86bios_modevent(module_t mod __unused, int type, void *data __unused)
 {
-	int err = 0;
 
 	switch (type) {
 	case MOD_LOAD:
@@ -201,11 +519,10 @@ x86bios_modevent(module_t mod __unused, 
 		x86bios_uninit(NULL);
 		break;
 	default:
-		err = ENOTSUP;
-		break;
+		return (ENOTSUP);
 	}
 
-	return (err);
+	return (0);
 }
 
 static moduledata_t x86bios_mod = {

Modified: head/sys/compat/x86bios/x86bios.h
==============================================================================
--- head/sys/compat/x86bios/x86bios.h	Mon Oct 19 20:51:27 2009	(r198250)
+++ head/sys/compat/x86bios/x86bios.h	Mon Oct 19 20:58:10 2009	(r198251)
@@ -23,49 +23,51 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
+ * $FreeBSD$
  */
 /*
  * x86 registers were borrowed from x86emu.h x86emu_regs.h
  * for compatability.
- *
- * $FreeBSD$
  */
 
 #ifndef _X86BIOS_H_
-#define _X86BIOS_H_
+#define	_X86BIOS_H_
 
-#include <sys/types.h>
 #include <sys/endian.h>
 #include <sys/systm.h>
+#include <sys/types.h>
 
 #ifdef	__BIG_ENDIAN__
 
 struct x86_register32 {
-	uint32_t e_reg;
+	uint32_t		e_reg;
 };
 
 struct x86_register16 {
-	uint16_t filler0;
-	uint16_t x_reg;
+	uint16_t		filler0;
+	uint16_t		x_reg;
 };
 
 struct x86_register8 {
-	uint8_t filler0, filler1;
-	uint8_t h_reg, l_reg;
+	uint8_t			filler0;
+	uint8_t			filler1;
+	uint8_t			h_reg;
+	uint8_t			l_reg;
 };
 
 #else /* !__BIG_ENDIAN__ */
 
 struct x86_register32 {
-	uint32_t e_reg;
+	uint32_t		e_reg;
 };
 
 struct x86_register16 {
-	uint16_t x_reg;
+	uint16_t		x_reg;
 };
 
 struct x86_register8 {
-	uint8_t l_reg, h_reg;
+	uint8_t			l_reg;
+	uint8_t			h_reg;
 };
 
 #endif /* __BIG_ENDIAN__ */
@@ -77,19 +79,19 @@ union x86_register {
 };
 
 struct x86regs {
-	uint16_t		padding;	/* CS is unused. */
-	uint16_t		register_ds;
+	uint16_t		_pad0;		/* CS */
+	uint16_t		_pad1;		/* DS */
 	uint16_t		register_es;
 	uint16_t		register_fs;
 	uint16_t		register_gs;
-	uint16_t		register_ss;
+	uint16_t		_pad2;		/* SS */
 	uint32_t		register_flags;
 	union x86_register	register_a;
 	union x86_register	register_b;
 	union x86_register	register_c;
 	union x86_register	register_d;
 
-	union x86_register	register_sp;
+	union x86_register	_pad3;		/* SP */
 	union x86_register	register_bp;
 	union x86_register	register_si;
 	union x86_register	register_di;
@@ -98,60 +100,57 @@ struct x86regs {
 typedef struct x86regs	x86regs_t;
 
 /* 8 bit registers */
-#define R_AH	register_a.I8_reg.h_reg
-#define R_AL	register_a.I8_reg.l_reg
-#define R_BH	register_b.I8_reg.h_reg
-#define R_BL	register_b.I8_reg.l_reg
-#define R_CH	register_c.I8_reg.h_reg
-#define R_CL	register_c.I8_reg.l_reg
-#define R_DH	register_d.I8_reg.h_reg
-#define R_DL	register_d.I8_reg.l_reg
+#define	R_AH		register_a.I8_reg.h_reg
+#define	R_AL		register_a.I8_reg.l_reg
+#define	R_BH		register_b.I8_reg.h_reg
+#define	R_BL		register_b.I8_reg.l_reg
+#define	R_CH		register_c.I8_reg.h_reg
+#define	R_CL		register_c.I8_reg.l_reg
+#define	R_DH		register_d.I8_reg.h_reg
+#define	R_DL		register_d.I8_reg.l_reg
 
 /* 16 bit registers */
-#define R_AX	register_a.I16_reg.x_reg
-#define R_BX	register_b.I16_reg.x_reg
-#define R_CX	register_c.I16_reg.x_reg
-#define R_DX	register_d.I16_reg.x_reg
+#define	R_AX		register_a.I16_reg.x_reg
+#define	R_BX		register_b.I16_reg.x_reg
+#define	R_CX		register_c.I16_reg.x_reg
+#define	R_DX		register_d.I16_reg.x_reg
 
 /* 32 bit extended registers */
-#define R_EAX	register_a.I32_reg.e_reg
-#define R_EBX	register_b.I32_reg.e_reg
-#define R_ECX	register_c.I32_reg.e_reg
-#define R_EDX	register_d.I32_reg.e_reg
+#define	R_EAX		register_a.I32_reg.e_reg
+#define	R_EBX		register_b.I32_reg.e_reg
+#define	R_ECX		register_c.I32_reg.e_reg
+#define	R_EDX		register_d.I32_reg.e_reg
 
 /* special registers */
-#define R_SP	register_sp.I16_reg.x_reg
-#define R_BP	register_bp.I16_reg.x_reg
-#define R_SI	register_si.I16_reg.x_reg
-#define R_DI	register_di.I16_reg.x_reg
-#define R_FLG	register_flags
+#define	R_BP		register_bp.I16_reg.x_reg
+#define	R_SI		register_si.I16_reg.x_reg
+#define	R_DI		register_di.I16_reg.x_reg
+#define	R_FLG		register_flags
 
 /* special registers */
-#define R_ESP	register_sp.I32_reg.e_reg
-#define R_EBP	register_bp.I32_reg.e_reg
-#define R_ESI	register_si.I32_reg.e_reg
-#define R_EDI	register_di.I32_reg.e_reg
-#define R_EFLG	register_flags
+#define	R_EBP		register_bp.I32_reg.e_reg
+#define	R_ESI		register_si.I32_reg.e_reg
+#define	R_EDI		register_di.I32_reg.e_reg
+#define	R_EFLG		register_flags
 
 /* segment registers */
-#define R_DS	register_ds
-#define R_SS	register_ss
-#define R_ES	register_es
-#define R_FS	register_fs
-#define R_GS	register_gs
-
-#define SEG_ADDR(x)	(((x) >> 4) & 0x00F000)
-#define SEG_OFF(x)	((x) & 0x0FFFF)
-#define FARP(x)		((le32toh(x) & 0xffff) + ((le32toh(x) >> 12) & 0xffff00))
+#define	R_ES		register_es
+#define	R_FS		register_fs
+#define	R_GS		register_gs
 
-#define MAPPED_MEMORY_SIZE	(1024 * 1024)
-#define PAGE_RESERV		(4096 * 5)
+#define	X86BIOS_PHYSTOSEG(x)	(((x) >> 4) & 0xffff)
+#define	X86BIOS_PHYSTOOFF(x)	((x) & 0x000f)
 
 __BEGIN_DECLS
-void *x86bios_alloc(int count, int *segs);
-void  x86bios_free(void *pbuf, int count);
-void  x86bios_intr(struct x86regs *regs, int intno);
-void *x86bios_offset(uint32_t offs);
+void	*x86bios_alloc(uint32_t *offset, size_t size);
+void	 x86bios_call(struct x86regs *regs, uint16_t seg, uint16_t off);
+void	 x86bios_free(void *addr, size_t size);
+uint32_t x86bios_get_intr(int intno);
+void	*x86bios_get_orm(uint32_t offset);
+void	 x86bios_init_regs(struct x86regs *regs);
+void	 x86bios_intr(struct x86regs *regs, int intno);
+int	 x86bios_match_device(uint32_t offset, device_t dev);
+void	*x86bios_offset(uint32_t offset);
 __END_DECLS
 
 #endif /* !_X86BIOS_H_ */

Modified: head/sys/conf/files.amd64
==============================================================================
--- head/sys/conf/files.amd64	Mon Oct 19 20:51:27 2009	(r198250)
+++ head/sys/conf/files.amd64	Mon Oct 19 20:58:10 2009	(r198251)
@@ -301,6 +301,4 @@ libkern/memset.c		standard
 # x86 real mode BIOS emulator, required by atkbdc/dpms/vesa
 #
 compat/x86bios/x86bios.c	optional x86bios | atkbd | dpms | vesa
-compat/x86bios/x86bios_alloc.c	optional x86bios | atkbd | dpms | vesa
 contrib/x86emu/x86emu.c		optional x86bios | atkbd | dpms | vesa
-contrib/x86emu/x86emu_util.c	optional x86bios | atkbd | dpms | vesa

Modified: head/sys/conf/files.i386
==============================================================================
--- head/sys/conf/files.i386	Mon Oct 19 20:51:27 2009	(r198250)
+++ head/sys/conf/files.i386	Mon Oct 19 20:58:10 2009	(r198251)
@@ -385,6 +385,4 @@ i386/xbox/pic16l.s		optional xbox
 # x86 real mode BIOS emulator, required by atkbdc/dpms/vesa
 #
 compat/x86bios/x86bios.c	optional x86bios | atkbd | dpms | vesa
-compat/x86bios/x86bios_alloc.c	optional x86bios | atkbd | dpms | vesa
 contrib/x86emu/x86emu.c		optional x86bios | atkbd | dpms | vesa
-contrib/x86emu/x86emu_util.c	optional x86bios | atkbd | dpms | vesa

Modified: head/sys/dev/atkbdc/atkbd.c
==============================================================================
--- head/sys/dev/atkbdc/atkbd.c	Mon Oct 19 20:51:27 2009	(r198250)
+++ head/sys/dev/atkbdc/atkbd.c	Mon Oct 19 20:58:10 2009	(r198251)
@@ -1091,32 +1091,35 @@ get_typematic(keyboard_t *kbd)
 {
 #if defined(__i386__) || defined(__amd64__)
 	/*
-	 * Only some systems allow us to retrieve the keyboard repeat 
+	 * Only some systems allow us to retrieve the keyboard repeat
 	 * rate previously set via the BIOS...
 	 */
 	x86regs_t regs;
 	uint8_t *p;
 
+	if (x86bios_get_intr(0x15) == 0 || x86bios_get_intr(0x16) == 0)
+		return (ENODEV);
+
 	/* Is BIOS system configuration table supported? */
-	bzero(&regs, sizeof(regs));
+	x86bios_init_regs(&regs);
 	regs.R_AH = 0xc0;
 	x86bios_intr(&regs, 0x15);
 	if ((regs.R_FLG & PSL_C) != 0 || regs.R_AH != 0)
 		return (ENODEV);
 
-	/* Is int 16, function 0x09 supported? */
+	/* Is int 0x16, function 0x09 supported? */
 	p = x86bios_offset((regs.R_ES << 4) + regs.R_BX);
 	if (readw(p) < 5 || (readb(p + 6) & 0x40) == 0)
 		return (ENODEV);
 
-	/* Is int 16, function 0x0306 supported? */
-	bzero(&regs, sizeof(regs));
+	/* Is int 0x16, function 0x0306 supported? */
+	x86bios_init_regs(&regs);
 	regs.R_AH = 0x09;
 	x86bios_intr(&regs, 0x16);
 	if ((regs.R_AL & 0x08) == 0)
 		return (ENODEV);
 
-	bzero(&regs, sizeof(regs));
+	x86bios_init_regs(&regs);
 	regs.R_AX = 0x0306;
 	x86bios_intr(&regs, 0x16);
 	kbd->kb_delay1 = typematic_delay(regs.R_BH << 5);

Modified: head/sys/dev/dpms/dpms.c
==============================================================================
--- head/sys/dev/dpms/dpms.c	Mon Oct 19 20:51:27 2009	(r198250)
+++ head/sys/dev/dpms/dpms.c	Mon Oct 19 20:58:10 2009	(r198251)
@@ -125,13 +125,13 @@ static void
 dpms_identify(driver_t *driver, device_t parent)
 {
 
-	/*
-	 * XXX: The DPMS VBE only allows for manipulating a single
-	 * monitor, but we don't know which one.  Just attach to the
-	 * first vgapci(4) device we encounter and hope it is the
-	 * right one.
-	 */
-	if (devclass_get_device(dpms_devclass, 0) == NULL)
+	/* The DPMS VBE only allows for manipulating a single monitor. */
+	if (devclass_get_device(dpms_devclass, 0) != NULL)
+		return;
+
+	if ((x86bios_match_device(0xc0000, parent) &&
+	    device_get_flags(parent) != 0) ||
+	    x86bios_get_orm(0xc0000) != NULL)
 		device_add_child(parent, "dpms", 0);
 }
 
@@ -172,8 +172,11 @@ dpms_detach(device_t dev)
 static int
 dpms_suspend(device_t dev)
 {
+	struct dpms_softc *sc;
 
-	dpms_set_state(DPMS_OFF);
+	sc = device_get_softc(dev);
+	if ((sc->dpms_supported_states & DPMS_OFF) != 0)
+		dpms_set_state(DPMS_OFF);
 	return (0);
 }
 
@@ -192,15 +195,16 @@ dpms_call_bios(int subfunction, int *bh)
 {
 	x86regs_t regs;
 
-	bzero(&regs, sizeof(regs));
+	if (x86bios_get_intr(0x10) == 0)
+		return (ENXIO);
+
+	x86bios_init_regs(&regs);
 	regs.R_AX = VBE_DPMS_FUNCTION;
 	regs.R_BL = subfunction;
 	regs.R_BH = *bh;
-	regs.R_ES = 0;
-	regs.R_DI = 0;
 	x86bios_intr(&regs, 0x10);
 
-	if ((regs.R_EAX & 0xffff) != 0x004f)
+	if (regs.R_AX != 0x004f)
 		return (ENXIO);
 
 	*bh = regs.R_BH;

Modified: head/sys/dev/fb/vesa.c
==============================================================================
--- head/sys/dev/fb/vesa.c	Mon Oct 19 20:51:27 2009	(r198250)
+++ head/sys/dev/fb/vesa.c	Mon Oct 19 20:58:10 2009	(r198251)
@@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$");
 #ifndef VGA_NO_MODE_CHANGE
 
 #include <sys/param.h>
+#include <sys/bus.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/module.h>
@@ -51,6 +52,8 @@ __FBSDID("$FreeBSD$");
 #include <dev/fb/fbreg.h>
 #include <dev/fb/vgareg.h>
 
+#include <dev/pci/pcivar.h>
+
 #include <isa/isareg.h>
 
 #include <compat/x86bios/x86bios.h>
@@ -160,7 +163,9 @@ static char *vesa_revstr = NULL;
 #define BIOS_SADDRTOLADDR(p) ((((p) & 0xffff0000) >> 12) + ((p) & 0x0000ffff))
 
 static int int10_set_mode(int mode);
+static int vesa_bios_post(void);
 static int vesa_bios_get_mode(int mode, struct vesa_mode *vmode);
+static int vesa_bios_get_current_mode(void);
 static int vesa_bios_set_mode(int mode);
 static int vesa_bios_get_dac(void);
 static int vesa_bios_set_dac(int bits);
@@ -222,12 +227,62 @@ int10_set_mode(int mode)
 {
 	x86regs_t regs;
 
-	bzero(&regs, sizeof(regs));
-	regs.R_EAX = 0x0000 | mode;
+	x86bios_init_regs(&regs);
+	regs.R_AL = mode;
 
 	x86bios_intr(&regs, 0x10);
 
-	return 0;
+	return (0);
+}
+
+static int
+vesa_bios_post(void)
+{
+	x86regs_t regs;
+	devclass_t dc;
+	device_t *devs;
+	device_t dev;
+	int count, i, is_pci;
+
+	if (x86bios_get_orm(0xc0000) == NULL)
+		return (1);
+
+	dev = NULL;
+	is_pci = 0;
+
+	/* Find the matching PCI video controller. */
+	dc = devclass_find("vgapci");
+	if (dc != NULL && devclass_get_devices(dc, &devs, &count) == 0) {
+		for (dev = NULL, i = 0; dev == NULL && i < count; devs++, i++)
+			if (x86bios_match_device(0xc0000, *devs) &&
+			    device_get_flags(*devs) != 0) {
+				dev = *devs;
+				is_pci = 1;
+				break;
+			}
+		free(devs, M_TEMP);
+	}
+
+	/* Try VGA if a PCI device is not found. */
+	if (dev == NULL) {
+		dc = devclass_find(VGA_DRIVER_NAME);
+		if (dc != NULL)
+			dev = devclass_get_device(dc, 0);
+	}
+
+	if (bootverbose)
+		printf("%s: calling BIOS POST\n",
+		    dev == NULL ? "VESA" : device_get_nameunit(dev));
+
+	x86bios_init_regs(&regs);
+	if (is_pci) {
+		regs.R_AH = pci_get_bus(dev);
+		regs.R_AL = (pci_get_slot(dev) << 3) |
+		    (pci_get_function(dev) & 0x07);
+	}
+	regs.R_DL = 0x80;
+	x86bios_call(&regs, 0xc000, 0x0003);
+	return (0);
 }
 
 /* VESA BIOS calls */
@@ -235,30 +290,47 @@ static int
 vesa_bios_get_mode(int mode, struct vesa_mode *vmode)
 {
 	x86regs_t regs;
-	int offs;
-	u_char *buf;
+	uint32_t offs;
+	void *buf;
 
-	bzero(&regs, sizeof(regs));
-	regs.R_EAX = 0x4f01;
-	regs.R_ECX = mode;
+	buf = x86bios_alloc(&offs, sizeof(*vmode));
+	if (buf == NULL)
+		return (1);
 
-	buf = (u_char *)x86bios_alloc(1, &offs);
+	x86bios_init_regs(&regs);
+	regs.R_AX = 0x4f01;
+	regs.R_CX = mode;
 
-	regs.R_ES = SEG_ADDR(offs);
-	regs.R_DI = SEG_OFF(offs);
+	regs.R_ES = X86BIOS_PHYSTOSEG(offs);
+	regs.R_DI = X86BIOS_PHYSTOOFF(offs);
 
 	x86bios_intr(&regs, 0x10);
 
-	if ((regs.R_AX & 0xff) != 0x4f)
-	{
-		x86bios_free(buf, 1);
-		return 1;
+	if (regs.R_AX != 0x004f) {
+		x86bios_free(buf, sizeof(*vmode));
+		return (1);
 	}
 
 	bcopy(buf, vmode, sizeof(*vmode));
-	x86bios_free(buf, 1);
+	x86bios_free(buf, sizeof(*vmode));
 
-	return 0;
+	return (0);
+}
+
+static int
+vesa_bios_get_current_mode(void)
+{
+	x86regs_t regs;
+
+	x86bios_init_regs(&regs);
+	regs.R_AX = 0x4f03;
+
+	x86bios_intr(&regs, 0x10);
+
+	if (regs.R_AX != 0x004f)
+		return (-1);
+
+	return (regs.R_BX);
 }
 
 static int
@@ -266,13 +338,13 @@ vesa_bios_set_mode(int mode)
 {
 	x86regs_t regs;
 
-	bzero(&regs, sizeof(regs));
-	regs.R_EAX = 0x4f02;
-	regs.R_EBX = mode;
+	x86bios_init_regs(&regs);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list