Subject: VGA_POST patch to replace "vbetool post"
To: None <current-users@netbsd.org>
From: Joerg Sonnenberger <joerg@britannica.bec.de>
List: current-users
Date: 12/21/2007 23:25:34
--JP+T4n/bALQSJXh8
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi all,
attached is a patch for x86 to use x86emu to reset vga(4) on resume.
Please test this by adding X86EMU and VGA_POST to your kernel config and
set machdep.acpi_vbios_reset=0. I am interested to hear on which systems
it works and doesn't work. I hope in the long term to replace that
sysctl with the VGA_POST option/code.

http://www.netbsd.org/~joerg/netbsd-amd64-vga_post.bz2 can be used as
well.

Joerg

--JP+T4n/bALQSJXh8
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="vga_post.diff"

Index: dev/pci/files.pci
===================================================================
RCS file: /data/repo/netbsd/src/sys/dev/pci/files.pci,v
retrieving revision 1.299
diff -u -p -r1.299 files.pci
--- dev/pci/files.pci	15 Dec 2007 05:46:21 -0000	1.299
+++ dev/pci/files.pci	18 Dec 2007 14:34:43 -0000
@@ -391,6 +391,7 @@ attach	esh at pci with esh_pci
 file	dev/pci/if_esh_pci.c		esh_pci
 
 # generic PCI VGA
+defflag	opt_vga.h	VGA_POST
 attach	vga at pci with vga_pci
 file	dev/pci/vga_pci.c		vga_pci			needs-flag
 
Index: dev/pci/vga_pci.c
===================================================================
RCS file: /data/repo/netbsd/src/sys/dev/pci/vga_pci.c,v
retrieving revision 1.37
diff -u -p -r1.37 vga_pci.c
--- dev/pci/vga_pci.c	9 Dec 2007 20:28:13 -0000	1.37
+++ dev/pci/vga_pci.c	21 Dec 2007 19:30:34 -0000
@@ -52,6 +52,12 @@ __KERNEL_RCSID(0, "$NetBSD: vga_pci.c,v 
 #include <dev/wscons/wsconsio.h>
 #include <dev/wscons/wsdisplayvar.h>
 
+#include "opt_vga.h"
+
+#ifdef VGA_POST
+#include <x86/vga_post.h>
+#endif
+
 #define	NBARS		6	/* number of PCI BARs */
 
 struct vga_bar {
@@ -70,7 +76,9 @@ struct vga_pci_softc {
 	struct vga_bar sc_bars[NBARS];
 	struct vga_bar sc_rom;
 
-	struct pci_conf_state sc_pciconf;
+#ifdef VGA_POST
+	struct vga_post *sc_posth;
+#endif
 };
 
 static int	vga_pci_match(struct device *, struct cfdata *, void *);
@@ -221,6 +229,12 @@ vga_pci_attach(struct device *parent, st
 	vga_common_attach(sc, pa->pa_iot, pa->pa_memt, WSDISPLAY_TYPE_PCIVGA,
 			  vga_pci_lookup_quirks(pa), &vga_pci_funcs);
 
+#ifdef VGA_POST
+	psc->sc_posth = vga_post_init(pa->pa_bus, pa->pa_device, pa->pa_function);
+	if (psc->sc_posth == NULL)
+		aprint_error_dev(self, "WARNING: could not prepare POST handler\n");
+#endif
+
 	/*
 	 * XXX Do not use the generic PCI framework for now as
 	 * XXX it would power down the device when the console
@@ -238,6 +252,11 @@ vga_pci_resume(device_t dv)
 
 	vga_resume(&sc->sc_vga);
 
+#ifdef VGA_POST
+	if (sc->sc_posth != NULL)
+		vga_post_call(sc->sc_posth);
+#endif
+
 	return true;
 }
 
Index: arch/x86/conf/files.x86
===================================================================
RCS file: /data/repo/netbsd/src/sys/arch/x86/conf/files.x86,v
retrieving revision 1.37
diff -u -p -r1.37 files.x86
--- arch/x86/conf/files.x86	18 Dec 2007 07:17:16 -0000	1.37
+++ arch/x86/conf/files.x86	18 Dec 2007 14:35:05 -0000
@@ -96,3 +96,5 @@ file	arch/x86/x86/coretemp.c 	intel_core
 device	ipmi: sysmon_envsys, sysmon_wdog
 attach	ipmi at ipmibus
 file	arch/x86/x86/ipmi.c		ipmi needs-flag
+
+file	arch/x86/x86/vga_post.c		vga_post
Index: arch/x86/include/vga_post.h
===================================================================
RCS file: arch/x86/include/vga_post.h
diff -N arch/x86/include/vga_post.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ arch/x86/include/vga_post.h	21 Dec 2007 19:50:42 -0000
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2007 Joerg Sonnenberger <joerg@NetBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 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.
+ */
+
+#ifndef _X86_VGA_POST_H_
+#define _X86_VGA_POST_H_
+
+#ifdef _KERNEL
+struct vga_post;
+
+struct vga_post	*vga_post_init(int, int, int);
+void		vga_post_free(struct vga_post *);
+void		vga_post_call(struct vga_post *);
+#endif
+#endif
Index: arch/x86/x86/vga_post.c
===================================================================
RCS file: arch/x86/x86/vga_post.c
diff -N arch/x86/x86/vga_post.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ arch/x86/x86/vga_post.c	21 Dec 2007 20:11:26 -0000
@@ -0,0 +1,182 @@
+/*-
+ * Copyright (c) 2007 Joerg Sonnenberger <joerg@NetBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 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/param.h>
+#include <sys/device.h>
+#include <sys/kmem.h>
+#include <uvm/uvm_extern.h>
+#include <uvm/uvm_page.h>
+
+#include <machine/pio.h>
+
+#include <x86/vga_post.h>
+
+#include <x86emu/x86emu.h>
+#include <x86emu/x86emu_i8254.h>
+#include <x86emu/x86emu_regs.h>
+
+struct vga_post {
+	struct X86EMU emu;
+	vaddr_t sys_image;
+	uint32_t initial_eax;
+	struct x86emu_i8254 i8254;
+};
+
+static uint8_t
+vm86_emu_inb(struct X86EMU *emu, uint16_t port)
+{
+	struct vga_post *sc = emu->sys_private;
+
+	if (port == 0xb2) /* APM scratch register */
+		return 0;
+
+	if (port >= 0x80 && port < 0x88) /* POST status register */
+		return 0;
+
+	if (x86emu_i8254_claim_port(&sc->i8254, port) && 0) {
+		return x86emu_i8254_inb(&sc->i8254, port);
+	} else
+		return inb(port);
+}
+
+static uint16_t
+vm86_emu_inw(struct X86EMU *emu, uint16_t port)
+{
+	if (port >= 0x80 && port < 0x88) /* POST status register */
+		return 0;
+
+	return inw(port);
+}
+
+static uint32_t
+vm86_emu_inl(struct X86EMU *emu, uint16_t port)
+{
+	if (port >= 0x80 && port < 0x88) /* POST status register */
+		return 0;
+
+	return inl(port);
+}
+
+static void
+vm86_emu_outb(struct X86EMU *emu, uint16_t port, uint8_t val)
+{
+	struct vga_post *sc = emu->sys_private;
+
+	if (port == 0xb2) /* APM scratch register */
+		return;
+
+	if (port >= 0x80 && port < 0x88) /* POST status register */
+		return;
+
+	if (x86emu_i8254_claim_port(&sc->i8254, port) && 0) {
+		x86emu_i8254_outb(&sc->i8254, port, val);
+	} else
+		outb(port, val);
+}
+
+static void
+vm86_emu_outw(struct X86EMU *emu, uint16_t port, uint16_t val)
+{
+	if (port >= 0x80 && port < 0x88) /* POST status register */
+		return;
+
+	outw(port, val);
+}
+
+static void
+vm86_emu_outl(struct X86EMU *emu, uint16_t port, uint32_t val)
+{
+	if (port >= 0x80 && port < 0x88) /* POST status register */
+		return;
+
+	outl(port, val);
+}
+
+struct vga_post *
+vga_post_init(int bus, int device, int function)
+{
+	struct vga_post *sc;
+	vaddr_t rom;
+	vaddr_t sys_image;
+
+	sys_image = uvm_km_alloc(kernel_map, 1024 * 1024, 0, UVM_KMF_VAONLY);
+	if (sys_image == 0)
+		return NULL;
+	sc = kmem_alloc(sizeof(*sc), KM_SLEEP);
+
+	sc->sys_image = sys_image;
+	sc->emu.sys_private = sc;
+
+	pmap_kenter_pa(sc->sys_image, 0, VM_PROT_READ | VM_PROT_WRITE);
+	for (rom = 640 * 1024; rom < 1024 * 1024; rom += 4096)
+		pmap_kenter_pa(sc->sys_image + rom, rom, VM_PROT_READ | VM_PROT_WRITE);
+	pmap_update(pmap_kernel());
+
+	memset(&sc->emu, 0, sizeof(sc->emu));
+	X86EMU_init_default(&sc->emu);
+	sc->emu.emu_inb = vm86_emu_inb;
+	sc->emu.emu_inw = vm86_emu_inw;
+	sc->emu.emu_inl = vm86_emu_inl;
+	sc->emu.emu_outb = vm86_emu_outb;
+	sc->emu.emu_outw = vm86_emu_outw;
+	sc->emu.emu_outl = vm86_emu_outl;
+
+	sc->emu.mem_base = (char *)sc->sys_image;
+	sc->emu.mem_size = 1024 * 1024;
+
+	sc->initial_eax = bus * 256 + device * 8 + function;
+
+	return sc;
+}
+
+void
+vga_post_call(struct vga_post *sc)
+{
+	sc->emu.x86.R_EAX = sc->initial_eax;
+	sc->emu.x86.R_EDX = 0x00000080;
+	sc->emu.x86.R_DS = 0x0040;
+	sc->emu.x86.register_flags = 0x3200;
+
+	/* stack is at the end of the first 4KB */
+	sc->emu.x86.R_SS = 0;
+	sc->emu.x86.R_ESP = 4096;
+
+	x86emu_i8254_init(&sc->i8254, nanotime);
+
+	/* Jump straight into the VGA BIOS POST code */
+	X86EMU_exec_call(&sc->emu, 0xc000, 0x0003);
+}
+
+void
+vga_post_free(struct vga_post *sc)
+{
+	pmap_kremove(sc->sys_image, 1024 * 1024);
+	pmap_update(pmap_kernel());
+	kmem_free(sc, sizeof(*sc));
+}

--JP+T4n/bALQSJXh8--