x86bios.c revision 197571
1/*-
2 * Copyright (c) 2009 Alex Keda <admin@lissyara.su>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: head/sys/compat/x86bios/x86bios.c 197571 2009-09-28 08:14:15Z delphij $");
30
31#include "opt_x86bios.h"
32
33#include <sys/param.h>
34#include <sys/kernel.h>
35#include <sys/lock.h>
36#include <sys/module.h>
37#include <sys/mutex.h>
38
39#include <vm/vm.h>
40#include <vm/pmap.h>
41
42#include <machine/cpufunc.h>
43
44#include <contrib/x86emu/x86emu.h>
45#include <contrib/x86emu/x86emu_regs.h>
46#include <compat/x86bios/x86bios.h>
47
48u_char *pbiosMem = NULL;
49static u_char *pbiosStack = NULL;
50
51int busySegMap[5];
52
53static struct x86emu x86bios_emu;
54
55static struct mtx x86bios_lock;
56
57static uint8_t
58x86bios_emu_inb(struct x86emu *emu, uint16_t port)
59{
60
61	if (port == 0xb2) /* APM scratch register */
62		return (0);
63	if (port >= 0x80 && port < 0x88) /* POST status register */
64		return (0);
65	return (inb(port));
66}
67
68static uint16_t
69x86bios_emu_inw(struct x86emu *emu, uint16_t port)
70{
71
72	if (port >= 0x80 && port < 0x88) /* POST status register */
73		return (0);
74	return (inw(port));
75}
76
77static uint32_t
78x86bios_emu_inl(struct x86emu *emu, uint16_t port)
79{
80
81	if (port >= 0x80 && port < 0x88) /* POST status register */
82		return (0);
83	return (inl(port));
84}
85
86static void
87x86bios_emu_outb(struct x86emu *emu, uint16_t port, uint8_t val)
88{
89
90	if (port == 0xb2) /* APM scratch register */
91		return;
92	if (port >= 0x80 && port < 0x88) /* POST status register */
93		return;
94	outb(port, val);
95}
96
97static void
98x86bios_emu_outw(struct x86emu *emu, uint16_t port, uint16_t val)
99{
100
101	if (port >= 0x80 && port < 0x88) /* POST status register */
102		return;
103	outw(port, val);
104}
105
106static void
107x86bios_emu_outl(struct x86emu *emu, uint16_t port, uint32_t val)
108{
109
110	if (port >= 0x80 && port < 0x88) /* POST status register */
111		return;
112	outl(port, val);
113}
114
115void
116x86bios_intr(struct x86regs *regs, int intno)
117{
118
119	if (intno < 0 || intno > 255)
120		return;
121
122	if (bootverbose)
123		printf("Calling int 0x%x (ax=0x%04x bx=0x%04x "
124		    "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n",
125		    intno, regs->R_AX, regs->R_BX, regs->R_CX,
126		    regs->R_DX, regs->R_ES, regs->R_DI);
127
128	mtx_lock_spin(&x86bios_lock);
129
130	memcpy(&x86bios_emu.x86, regs, sizeof(*regs));
131	x86emu_exec_intr(&x86bios_emu, intno);
132	memcpy(regs, &x86bios_emu.x86, sizeof(*regs));
133
134	mtx_unlock_spin(&x86bios_lock);
135
136	if (bootverbose)
137		printf("Exiting int 0x%x (ax=0x%04x bx=0x%04x "
138		    "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n",
139		    intno, regs->R_AX, regs->R_BX, regs->R_CX,
140		    regs->R_DX, regs->R_ES, regs->R_DI);
141}
142
143void *
144x86bios_offset(uint32_t offs)
145{
146
147	return (pbiosMem + offs);
148}
149
150static void
151x86bios_init(void *arg __unused)
152{
153	int offs;
154
155	mtx_init(&x86bios_lock, "x86bios lock", NULL, MTX_SPIN);
156
157	/* Can pbiosMem be NULL here? */
158	pbiosMem = pmap_mapbios(0x0, MAPPED_MEMORY_SIZE);
159
160	memset(&x86bios_emu, 0, sizeof(x86bios_emu));
161	x86emu_init_default(&x86bios_emu);
162
163	x86bios_emu.emu_inb = x86bios_emu_inb;
164	x86bios_emu.emu_inw = x86bios_emu_inw;
165	x86bios_emu.emu_inl = x86bios_emu_inl;
166	x86bios_emu.emu_outb = x86bios_emu_outb;
167	x86bios_emu.emu_outw = x86bios_emu_outw;
168	x86bios_emu.emu_outl = x86bios_emu_outl;
169
170	x86bios_emu.mem_base = (char *)pbiosMem;
171	x86bios_emu.mem_size = MAPPED_MEMORY_SIZE;
172
173	memset(busySegMap, 0, sizeof(busySegMap));
174
175	pbiosStack = x86bios_alloc(1, &offs);
176}
177
178static void
179x86bios_uninit(void *arg __unused)
180{
181
182	x86bios_free(pbiosStack, 1);
183
184	if (pbiosMem)
185		pmap_unmapdev((vm_offset_t)pbiosMem,
186		    MAPPED_MEMORY_SIZE);
187
188	mtx_destroy(&x86bios_lock);
189}
190
191static int
192x86bios_modevent(module_t mod __unused, int type, void *data __unused)
193{
194	int err = 0;
195
196	switch (type) {
197	case MOD_LOAD:
198		x86bios_init(NULL);
199		break;
200	case MOD_UNLOAD:
201		x86bios_uninit(NULL);
202		break;
203	default:
204		err = ENOTSUP;
205		break;
206	}
207
208	return (err);
209}
210
211static moduledata_t x86bios_mod = {
212	"x86bios",
213	x86bios_modevent,
214	NULL,
215};
216
217DECLARE_MODULE(x86bios, x86bios_mod, SI_SUB_CPU, SI_ORDER_ANY);
218MODULE_VERSION(x86bios, 1);
219