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