FreeBSD/Linux Kernel Cross Reference
sys/i386at/iopl.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: iopl.c,v $
29 * Revision 2.11 93/09/01 11:32:49 mrt
30 * For X11R5, allow any old address to be mmapped.
31 * [93/08/19 rvb]
32 *
33 * Revision 2.10 93/03/09 11:18:43 danner
34 * And printer at 0x278
35 * [93/03/04 11:16:17 rvb]
36 *
37 * Added two ports for ATI graphics card from Savage.
38 * [93/03/03 rvb]
39 *
40 * Revision 2.9 92/04/03 12:09:07 rpd
41 * Change mapping of mmap function to map 0x0, 0xa0000..0xfffff
42 * directly.
43 * [92/03/16 rvb]
44 *
45 * Revision 2.8 92/01/03 20:11:01 dbg
46 * Add 'forbidden' list. For DOS compatibility, allow any port not
47 * on this list.
48 * [92/01/02 dbg]
49 *
50 * Add ports 70 and 71 for DOS programs (XXX).
51 * [91/12/18 dbg]
52 *
53 * Use io_port sets.
54 * [91/11/09 dbg]
55 *
56 * Revision 2.7 91/05/14 16:26:21 mrt
57 * Correcting copyright
58 *
59 * Revision 2.6 91/02/05 17:18:43 mrt
60 * Changed to new Mach copyright
61 * [91/02/01 17:44:59 mrt]
62 *
63 * Revision 2.5 90/11/26 14:50:15 rvb
64 * jsb bet me to XMK34, sigh ...
65 * [90/11/26 rvb]
66 * Synched 2.5 & 3.0 at I386q (r2.1.1.3) & XMK35 (r2.5)
67 * [90/11/15 rvb]
68 *
69 * Revision 2.1.1.2 90/03/28 08:30:58 rvb
70 * Add ioplmmap to map 0x0a0000 - 0x100000
71 * [90/03/25 rvb]
72 *
73 * Revision 2.1.1.1 90/02/01 13:36:55 rvb
74 * Allow io privileges to the process.
75 * [90/02/01 rvb]
76 *
77 */
78
79 #include <mach/vm_prot.h>
80 #include <mach/i386/vm_types.h>
81 #include <mach/i386/vm_param.h>
82
83 #include <ipc/ipc_port.h>
84
85 #include <device/io_req.h>
86
87 #include <i386/io_port.h>
88 #include <i386/eflags.h>
89 #include <i386/pit.h>
90
91 /*
92 * IOPL device.
93 */
94 ipc_port_t iopl_device_port = IP_NULL;
95 device_t iopl_device = 0;
96
97 /*
98 * Ports that we allow access to.
99 */
100 io_reg_t iopl_port_list[] = {
101 /* timer 2 */
102 0x42,
103 /* speaker output */
104 0x61,
105 /* configuration RAM */
106 0x70, 0x71, /* XXX should not need! */
107 /* ATI - savage */
108 0x1ce, 0x1cf,
109 /* game port */
110 0x201,
111 /* sound board */
112 0x220, 0x221, 0x222, 0x223, 0x224, 0x225, 0x226, 0x227,
113 0x228, 0x229, 0x22a, 0x22b, 0x22c, 0x22d, 0x22e, 0x22f,
114 /* printer */
115 0x278, 0x279, 0x27a,
116 0x378, 0x379, 0x37a,
117 /* ega/vga */
118 0x3b0, 0x3b1, 0x3b2, 0x3b3, 0x3b4, 0x3b5, 0x3b6, 0x3b7,
119 0x3b8, 0x3b9, 0x3ba, 0x3bb, 0x3bc, 0x3bd, 0x3be, 0x3bf,
120 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4, 0x3c5, 0x3c6, 0x3c7,
121 0x3c8, 0x3c9, 0x3ca, 0x3cb, 0x3cc, 0x3cd, 0x3ce, 0x3cf,
122 0x3d0, 0x3d1, 0x3d2, 0x3d3, 0x3d4, 0x3d5, 0x3d6, 0x3d7,
123 0x3d8, 0x3d9, 0x3da, 0x3db, 0x3dc, 0x3dd, 0x3de, 0x3df,
124 /* end of list */
125 IO_REG_NULL
126 };
127
128 int
129 ioplopen(dev, flag, ior)
130 int dev;
131 int flag;
132 io_req_t ior;
133 {
134 iopl_device_port = ior->io_device->port;
135 iopl_device = ior->io_device;
136
137 io_port_create(iopl_device, iopl_port_list);
138 return (0);
139 }
140
141
142 /*ARGSUSED*/
143 ioplclose(dev, flags)
144 int dev;
145 int flags;
146 {
147 io_port_destroy(iopl_device);
148 iopl_device_port = IP_NULL;
149 iopl_device = 0;
150 return 0;
151 }
152
153 /*ARGSUSED*/
154 int iopl_all = 1;
155 ioplmmap(dev, off, prot)
156 int dev;
157 vm_offset_t off;
158 vm_prot_t prot;
159 {
160 extern vm_offset_t last_addr;
161
162 if (iopl_all) {
163 if (off == 0)
164 return 0;
165 else if (off < 0xa0000)
166 return -1;
167 else if (off >= 0x100000 && off <= last_addr)
168 return -1;
169 else
170 return i386_btop(off);
171
172 }
173 if (off > 0x60000)
174 return(-1);
175
176 /* Get page frame number for the page to be mapped. */
177
178 return(i386_btop(0xa0000 + off));
179 }
180
181 /*
182 * For DOS compatibility, it's easier to list the ports we don't
183 * allow access to.
184 */
185 #define IOPL_PORTS_USED_MAX 256
186 io_reg_t iopl_ports_used[IOPL_PORTS_USED_MAX] = {
187 IO_REG_NULL
188 };
189
190 boolean_t
191 iopl_port_forbidden(io_port)
192 int io_port;
193 {
194 int i;
195
196 #if 0 /* we only read from these... it should be OK */
197
198 if (io_port <= 0xff)
199 return TRUE; /* system ports. 42,61,70,71 allowed above */
200
201 if (io_port >= 0x130 && io_port <= 0x137)
202 return TRUE; /* AHA disk */
203
204 if (io_port >= 0x170 && io_port <= 0x177)
205 return TRUE; /* HD disk */
206
207 if (io_port >= 0x1f0 && io_port <= 0x1f7)
208 return TRUE; /* HD disk */
209
210 if (io_port >= 0x230 && io_port <= 0x237)
211 return TRUE; /* AHA disk */
212
213 if (io_port >= 0x280 && io_port <= 0x2df)
214 return TRUE; /* 8390 network */
215
216 if (io_port >= 0x300 && io_port <= 0x31f)
217 return TRUE; /* 8390 network */
218
219 if (io_port >= 0x330 && io_port <= 0x337)
220 return TRUE; /* AHA disk */
221
222 if (io_port >= 0x370 && io_port <= 0x377)
223 return TRUE; /* FD disk */
224
225 if (io_port >= 0x3f0 && io_port <= 0x3f7)
226 return TRUE; /* FD disk */
227
228 #endif
229
230 /*
231 * Must be OK, as far as we know...
232 * Record the port in the list, for
233 * curiosity seekers.
234 */
235 for (i = 0; i < IOPL_PORTS_USED_MAX; i++) {
236 if (iopl_ports_used[i] == io_port)
237 break; /* in list */
238 if (iopl_ports_used[i] == IO_REG_NULL) {
239 iopl_ports_used[i] = io_port;
240 iopl_ports_used[i+1] = IO_REG_NULL;
241 break;
242 }
243 }
244
245 return FALSE;
246 }
247
248 /*
249 * Emulate certain IO instructions for the AT bus.
250 *
251 * We emulate writes to the timer control port, 43.
252 * Only writes to timer 2 are allowed.
253 *
254 * Temporarily, we allow reads of any IO port,
255 * but ONLY if the thread has the IOPL device mapped
256 * and is not in V86 mode.
257 *
258 * This is a HACK and MUST go away when the DOS emulator
259 * emulates these IO ports, or when we decide that
260 * the DOS world can get access to all uncommitted IO
261 * ports. In that case, config() should remove the IO
262 * ports for devices it exists from the allowable list.
263 */
264 boolean_t
265 iopl_emulate(regs, opcode, io_port)
266 struct i386_saved_state *regs;
267 int opcode;
268 int io_port;
269 {
270 iopb_tss_t iopb;
271
272 iopb = current_thread()->pcb->ims.io_tss;
273 if (iopb == 0)
274 return FALSE; /* no IO mapped */
275
276 /*
277 * Handle outb to the timer control port,
278 * for timer 2 only.
279 */
280 if (io_port == PITCTL_PORT) {
281
282 int io_byte = regs->eax & 0xff;
283
284 if (((iopb->bitmap[PITCTR2_PORT >> 3] & (1 << (PITCTR2_PORT & 0x7)))
285 == 0) /* allowed */
286 && (opcode == 0xe6 || opcode == 0xee) /* outb */
287 && (io_byte & 0xc0) == 0x80) /* timer 2 */
288 {
289 outb(io_port, io_byte);
290 return TRUE;
291 }
292 return FALSE; /* invalid IO to port 42 */
293 }
294
295 /*
296 * If the thread has the IOPL device mapped, and
297 * the io port is not on the 'forbidden' list, allow
298 * reads from it. Reject writes.
299 *
300 * Don`t do this for V86 mode threads
301 * (hack for DOS emulator XXX!)
302 */
303 if (!(regs->efl & EFL_VM) &&
304 iopb_check_mapping(current_thread(), iopl_device) &&
305 !iopl_port_forbidden(io_port))
306 {
307 /*
308 * handle inb, inw, inl
309 */
310 switch (opcode) {
311 case 0xE4: /* inb imm */
312 case 0xEC: /* inb dx */
313 regs->eax = (regs->eax & 0xffffff00)
314 | inb(io_port);
315 return TRUE;
316
317 case 0x66E5: /* inw imm */
318 case 0x66ED: /* inw dx */
319 regs->eax = (regs->eax & 0xffff0000)
320 | inw(io_port);
321 return TRUE;
322
323 case 0xE5: /* inl imm */
324 case 0xED: /* inl dx */
325 regs->eax = inl(io_port);
326 return TRUE;
327
328 default:
329 return FALSE; /* OUT not allowed */
330 }
331 }
332
333 /*
334 * Not OK.
335 */
336 return FALSE;
337 }
338
Cache object: 124efdd99506d1ac2bb11e50549c9fa3
|