vga_post.c revision 1.7
1/* $OpenBSD: vga_post.c,v 1.7 2014/07/12 18:44:41 tedu Exp $ */
2/* $NetBSD: vga_post.c,v 1.12 2009/03/15 21:32:36 cegger Exp $ */
3
4/*-
5 * Copyright (c) 2007 Joerg Sonnenberger <joerg@NetBSD.org>.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in
16 *    the documentation and/or other materials provided with the
17 *    distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/param.h>
34#include <sys/device.h>
35#include <sys/malloc.h>
36
37#include <uvm/uvm_extern.h>
38
39#include <machine/pio.h>
40#include <machine/vga_post.h>
41
42#include <dev/x86emu/x86emu.h>
43#include <dev/x86emu/x86emu_regs.h>
44
45#define	BASE_MEMORY	65536	/* How much memory to allocate in Real Mode */
46
47struct vga_post {
48	struct x86emu emu;
49	vaddr_t sys_image;
50	uint32_t initial_eax;
51	uint8_t bios_data[PAGE_SIZE];
52	struct pglist ram_backing;
53};
54
55#ifdef DDB
56static struct vga_post *ddb_vgapostp;
57void ddb_vgapost(void);
58#endif
59
60static uint8_t
61vm86_emu_inb(struct x86emu *emu, uint16_t port)
62{
63	if (port == 0xb2) /* APM scratch register */
64		return 0;
65
66	if (port >= 0x80 && port < 0x88) /* POST status register */
67		return 0;
68
69	return inb(port);
70}
71
72static uint16_t
73vm86_emu_inw(struct x86emu *emu, uint16_t port)
74{
75	if (port >= 0x80 && port < 0x88) /* POST status register */
76		return 0;
77
78	return inw(port);
79}
80
81static uint32_t
82vm86_emu_inl(struct x86emu *emu, uint16_t port)
83{
84	if (port >= 0x80 && port < 0x88) /* POST status register */
85		return 0;
86
87	return inl(port);
88}
89
90static void
91vm86_emu_outb(struct x86emu *emu, uint16_t port, uint8_t val)
92{
93	if (port == 0xb2) /* APM scratch register */
94		return;
95
96	if (port >= 0x80 && port < 0x88) /* POST status register */
97		return;
98
99	outb(port, val);
100}
101
102static void
103vm86_emu_outw(struct x86emu *emu, uint16_t port, uint16_t val)
104{
105	if (port >= 0x80 && port < 0x88) /* POST status register */
106		return;
107
108	outw(port, val);
109}
110
111static void
112vm86_emu_outl(struct x86emu *emu, uint16_t port, uint32_t val)
113{
114	if (port >= 0x80 && port < 0x88) /* POST status register */
115		return;
116
117	outl(port, val);
118}
119
120struct vga_post *
121vga_post_init(int bus, int device, int function)
122{
123	struct vga_post *sc;
124	vaddr_t iter;
125	struct vm_page *pg;
126	vaddr_t sys_image, sys_bios_data;
127	int err;
128
129	sys_bios_data = uvm_km_valloc(kernel_map, PAGE_SIZE);
130	if (sys_bios_data == 0)
131		return NULL;
132
133	sys_image = uvm_km_valloc(kernel_map, 1024 * 1024);
134	if (sys_image == 0) {
135		uvm_km_free(kernel_map, sys_bios_data, PAGE_SIZE);
136		return NULL;
137	}
138	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
139
140	TAILQ_INIT(&sc->ram_backing);
141	err = uvm_pglistalloc(BASE_MEMORY, 0, (paddr_t)-1, 0, 0,
142	    &sc->ram_backing, BASE_MEMORY/PAGE_SIZE, UVM_PLA_WAITOK);
143	if (err) {
144		uvm_km_free(kernel_map, sc->sys_image, 1024 * 1024);
145		free(sc, M_DEVBUF, 0);
146		return NULL;
147	}
148
149	sc->sys_image = sys_image;
150	sc->emu.sys_private = sc;
151
152	pmap_kenter_pa(sys_bios_data, 0, VM_PROT_READ);
153	pmap_update(pmap_kernel());
154	memcpy((void *)sc->bios_data, (void *)sys_bios_data, PAGE_SIZE);
155	pmap_kremove(sys_bios_data, PAGE_SIZE);
156	uvm_km_free(kernel_map, sys_bios_data, PAGE_SIZE);
157
158	iter = 0;
159	TAILQ_FOREACH(pg, &sc->ram_backing, pageq) {
160		pmap_kenter_pa(sc->sys_image + iter, VM_PAGE_TO_PHYS(pg),
161				VM_PROT_READ | VM_PROT_WRITE);
162		iter += PAGE_SIZE;
163	}
164	KASSERT(iter == BASE_MEMORY);
165
166	for (iter = 640 * 1024; iter < 1024 * 1024; iter += PAGE_SIZE)
167		pmap_kenter_pa(sc->sys_image + iter, iter,
168				VM_PROT_READ | VM_PROT_WRITE);
169	pmap_update(pmap_kernel());
170
171	memset(&sc->emu, 0, sizeof(sc->emu));
172	x86emu_init_default(&sc->emu);
173	sc->emu.emu_inb = vm86_emu_inb;
174	sc->emu.emu_inw = vm86_emu_inw;
175	sc->emu.emu_inl = vm86_emu_inl;
176	sc->emu.emu_outb = vm86_emu_outb;
177	sc->emu.emu_outw = vm86_emu_outw;
178	sc->emu.emu_outl = vm86_emu_outl;
179
180	sc->emu.mem_base = (char *)sc->sys_image;
181	sc->emu.mem_size = 1024 * 1024;
182
183	sc->initial_eax = bus * 256 + device * 8 + function;
184#ifdef DDB
185	ddb_vgapostp = sc;
186#endif
187	return sc;
188}
189
190void
191vga_post_call(struct vga_post *sc)
192{
193	sc->emu.x86.R_EAX = sc->initial_eax;
194	sc->emu.x86.R_EDX = 0x00000080;
195	sc->emu.x86.R_DS = 0x0040;
196	sc->emu.x86.register_flags = 0x3200;
197
198	memcpy((void *)sc->sys_image, sc->bios_data, PAGE_SIZE);
199
200	/* stack is at the end of the first 64KB */
201	sc->emu.x86.R_SS = 0;
202	sc->emu.x86.R_ESP = 0;
203
204	/* Jump straight into the VGA BIOS POST code */
205	x86emu_exec_call(&sc->emu, 0xc000, 0x0003);
206}
207
208void
209vga_post_free(struct vga_post *sc)
210{
211	uvm_pglistfree(&sc->ram_backing);
212	pmap_kremove(sc->sys_image, 1024 * 1024);
213	uvm_km_free(kernel_map, sc->sys_image, 1024 * 1024);
214	pmap_update(pmap_kernel());
215	free(sc, M_DEVBUF, 0);
216}
217
218#ifdef DDB
219void
220ddb_vgapost(void)
221{
222
223	if (ddb_vgapostp)
224		vga_post_call(ddb_vgapostp);
225	else
226		printf("ddb_vgapost: vga_post not initialized\n");
227}
228#endif
229