2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
29 * Mach Operating System
30 * Copyright (c) 1991,1990 Carnegie Mellon University
31 * All Rights Reserved.
33 * Permission to use, copy, modify and distribute this software and its
34 * documentation is hereby granted, provided that both the copyright
35 * notice and this permission notice appear in all copies of the
36 * software, derivative works or modified versions, and any portions
37 * thereof, and that both notices appear in supporting documentation.
39 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
40 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
41 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
43 * Carnegie Mellon requests users of this software to return to
45 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
46 * School of Computer Science
47 * Carnegie Mellon University
48 * Pittsburgh PA 15213-3890
50 * any improvements or extensions that they make and grant Carnegie Mellon
51 * the rights to redistribute these changes.
58 * Code to manipulate IO permission bitmaps.
63 #include <mach/boolean.h>
64 #include <mach/kern_return.h>
66 #include <ipc/ipc_port.h>
68 #include <kern/kalloc.h>
69 #include <kern/lock.h>
70 #include <kern/queue.h>
71 #include <kern/thread.h>
72 #include <kern/misc_protos.h>
75 #include <i386/io_port.h>
76 #include <i386/iopb.h>
78 #include <i386/iopb_entries.h>
87 iopb_destroy(iopb_tss_t io_tss
)
91 #if 0 /* Code removed until better solution comes on board */
93 * A set of ports for an IO device.
96 device_t device
; /* Mach device */
97 queue_chain_t dev_list
; /* link in device list */
98 queue_chain_t io_use_list
; /* List of threads that use it */
99 io_reg_t
*io_port_list
; /* list of IO ports that use it */
100 /* list ends with IO_REG_NULL */
102 typedef struct io_port
*io_port_t
;
105 * Lookup table for device -> io_port mapping
106 * (a linked list - I don't expect too many)
108 queue_head_t device_to_io_port_list
;
112 * all threads that have IO ports mapped
113 * all IO ports that have threads mapped
116 queue_chain_t psq
; /* Links from port set */
117 queue_chain_t tsq
; /* links from tss */
118 io_port_t ps
; /* Port set */
119 iopb_tss_t ts
; /* Task segment */
121 typedef struct io_use
*io_use_t
;
124 * Big lock for the whole mess.
126 decl_simple_lock_data(,iopb_lock
)
130 extern void io_bitmap_init(
132 extern void io_bitmap_set(
135 extern void io_bitmap_clear(
138 extern io_port_t
device_to_io_port_lookup(
140 extern void io_tss_init(
145 * Initialize the package.
150 queue_init(&device_to_io_port_list
);
151 simple_lock_init(&iopb_lock
, ETAP_IO_IOPB
);
155 * Initialize bitmap (set all bits to OFF == 1)
161 register unsigned char *b
;
164 s
= sizeof(isa_iopb
);
173 * Set selected bits in bitmap to ON == 0
182 while ((io_bit
= *bit_list
++) != IO_REG_NULL
) {
183 bp
[io_bit
>>3] &= ~(1 << (io_bit
& 0x7));
188 * Set selected bits in bitmap to OFF == 1
197 while ((io_bit
= *bit_list
++) != IO_REG_NULL
) {
198 bp
[io_bit
>>3] |= (1 << (io_bit
& 0x7));
203 * Lookup an io-port set by device
206 device_to_io_port_lookup(
209 register io_port_t io_port
;
211 queue_iterate(&device_to_io_port_list
, io_port
, io_port_t
, dev_list
) {
212 if (io_port
->device
== device
) {
221 * Create an io_port set
226 io_reg_t
*io_port_list
)
228 register io_port_t io_port
, old_io_port
;
230 io_port
= (io_port_t
) kalloc(sizeof(struct io_port
));
232 simple_lock(&iopb_lock
);
233 if (device_to_io_port_lookup(device
) != 0) {
234 simple_unlock(&iopb_lock
);
235 kfree((vm_offset_t
) io_port
, sizeof(struct io_port
));
239 io_port
->device
= device
;
240 queue_init(&io_port
->io_use_list
);
241 io_port
->io_port_list
= io_port_list
;
244 * Enter in lookup list.
246 queue_enter(&device_to_io_port_list
, io_port
, io_port_t
, dev_list
);
248 simple_unlock(&iopb_lock
);
253 * Destroy an io port set, removing any IO mappings.
262 simple_lock(&iopb_lock
);
263 io_port
= device_to_io_port_lookup(device
);
265 simple_unlock(&iopb_lock
);
269 queue_iterate(&io_port
->io_use_list
, iu
, io_use_t
, psq
) {
272 io_bitmap_clear(io_tss
->bitmap
, io_port
->io_port_list
);
273 queue_remove(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
);
275 queue_remove(&device_to_io_port_list
, io_port
, io_port_t
, dev_list
);
276 simple_unlock(&iopb_lock
);
278 while (!queue_empty(&io_port
->io_use_list
)) {
279 iu
= (io_use_t
) queue_first(&io_port
->io_use_list
);
280 queue_remove(&io_port
->io_use_list
, iu
, io_use_t
, psq
);
281 kfree((vm_offset_t
)iu
, sizeof(struct io_use
));
284 kfree((vm_offset_t
)io_port
, sizeof(struct io_port
));
288 * Initialize an IO TSS.
294 vm_offset_t addr
= (vm_offset_t
) io_tss
;
295 vm_size_t size
= (char *)&io_tss
->barrier
- (char *)io_tss
;
297 bzero((char *)&io_tss
->tss
, sizeof(struct i386_tss
));
298 io_tss
->tss
.io_bit_map_offset
299 = (char *)&io_tss
->bitmap
- (char *)io_tss
;
300 io_tss
->tss
.ss0
= KERNEL_DS
;
301 io_bitmap_init(io_tss
->bitmap
);
302 io_tss
->barrier
= ~0;
303 queue_init(&io_tss
->io_port_list
);
304 addr
+= LINEAR_KERNEL_ADDRESS
;
305 io_tss
->iopb_desc
[0] = ((size
-1) & 0xffff)
306 | ((addr
& 0xffff) << 16);
307 io_tss
->iopb_desc
[1] = ((addr
& 0x00ff0000) >> 16)
308 | ((ACC_TSS
|ACC_PL_K
|ACC_P
) << 8)
309 | ((size
-1) & 0x000f0000)
310 | (addr
& 0xff000000);
320 register iopb_tss_t ts
;
322 ts
= (iopb_tss_t
) kalloc(sizeof (struct iopb_tss
));
329 * Destroy an IOPB_TSS
338 simple_lock(&iopb_lock
);
340 queue_iterate(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
) {
342 /* skip bitmap clear - entire bitmap will vanish */
343 queue_remove(&io_port
->io_use_list
, iu
, io_use_t
, psq
);
346 simple_unlock(&iopb_lock
);
348 while (!queue_empty(&io_tss
->io_port_list
)) {
349 iu
= (io_use_t
) queue_first(&io_tss
->io_port_list
);
350 queue_remove(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
);
351 kfree((vm_offset_t
)iu
, sizeof(struct io_use
));
354 kfree((vm_offset_t
)io_tss
, sizeof(struct iopb_tss
));
358 * Add an IO mapping to a thread.
366 iopb_tss_t io_tss
, new_io_tss
;
370 if (thread
== THREAD_NULL
371 || device
== DEVICE_NULL
)
372 return KERN_INVALID_ARGUMENT
;
374 pcb
= thread
->top_act
->mact
.pcb
;
377 iu
= (io_use_t
) kalloc(sizeof(struct io_use
));
380 simple_lock(&iopb_lock
);
382 /* find the io_port_t for the device */
383 io_port
= device_to_io_port_lookup(device
);
386 * Device does not have IO ports available.
388 simple_unlock(&iopb_lock
);
390 kfree((vm_offset_t
)new_io_tss
, sizeof(struct iopb_tss
));
391 kfree((vm_offset_t
) iu
, sizeof(struct io_use
));
392 return KERN_INVALID_ARGUMENT
;
395 /* Have the IO port. */
397 /* Make sure the thread has a TSS. */
399 simple_lock(&pcb
->lock
);
400 io_tss
= pcb
->ims
.io_tss
;
402 if (new_io_tss
== 0) {
404 * Allocate an IO-tss.
406 simple_unlock(&pcb
->lock
);
407 simple_unlock(&iopb_lock
);
409 new_io_tss
= (iopb_tss_t
) kalloc(sizeof(struct iopb_tss
));
410 io_tss_init(new_io_tss
);
415 pcb
->ims
.io_tss
= io_tss
;
420 * Have io_port and io_tss.
421 * See whether device is already mapped.
423 queue_iterate(&io_tss
->io_port_list
, old_iu
, io_use_t
, tsq
) {
424 if (old_iu
->ps
== io_port
) {
428 simple_unlock(&pcb
->lock
);
429 simple_unlock(&iopb_lock
);
431 kfree((vm_offset_t
)iu
, sizeof(struct io_use
));
433 kfree((vm_offset_t
)new_io_tss
, sizeof(struct iopb_tss
));
443 queue_enter(&io_port
->io_use_list
, iu
, io_use_t
, psq
);
444 queue_enter(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
);
445 io_bitmap_set(io_tss
->bitmap
, io_port
->io_port_list
);
447 simple_unlock(&pcb
->lock
);
448 simple_unlock(&iopb_lock
);
451 kfree((vm_offset_t
)new_io_tss
, sizeof(struct iopb_tss
));
457 * Remove an IO mapping from a thread.
469 if (thread
== THREAD_NULL
470 || device
== DEVICE_NULL
)
471 return KERN_INVALID_ARGUMENT
;
473 pcb
= thread
->top_act
->mact
.pcb
;
475 simple_lock(&iopb_lock
);
477 /* find the io_port_t for the device */
479 io_port
= device_to_io_port_lookup(device
);
482 * Device does not have IO ports available.
484 simple_unlock(&iopb_lock
);
485 return KERN_INVALID_ARGUMENT
;
488 simple_lock(&pcb
->lock
);
489 io_tss
= pcb
->ims
.io_tss
;
491 simple_unlock(&pcb
->lock
);
492 simple_unlock(&iopb_lock
);
493 return KERN_INVALID_ARGUMENT
; /* not mapped */
499 queue_iterate(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
) {
500 if (iu
->ps
== io_port
) {
502 * Found mapping. Remove it.
504 io_bitmap_clear(io_tss
->bitmap
, io_port
->io_port_list
);
506 queue_remove(&io_port
->io_use_list
, iu
, io_use_t
, psq
);
507 queue_remove(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
);
509 simple_unlock(&pcb
->lock
);
510 simple_unlock(&iopb_lock
);
512 kfree((vm_offset_t
)iu
, sizeof(struct io_use
));
521 return KERN_INVALID_ARGUMENT
;
525 * Return the IO ports mapped into a thread.
529 i386_io_port_list(thread
, list
, list_count
)
532 unsigned int *list_count
;
535 register iopb_tss_t io_tss
;
536 unsigned int count
, alloc_count
;
538 vm_size_t size_needed
, size
;
542 if (thread
== THREAD_NULL
)
543 return KERN_INVALID_ARGUMENT
;
545 pcb
= thread
->top_act
->mact
.pcb
;
547 alloc_count
= 16; /* a guess */
550 size_needed
= alloc_count
* sizeof(ipc_port_t
);
551 if (size_needed
<= size
)
557 assert(size_needed
> 0);
562 return KERN_RESOURCE_SHORTAGE
;
564 devices
= (device_t
*)addr
;
567 simple_lock(&iopb_lock
);
568 simple_lock(&pcb
->lock
);
569 io_tss
= pcb
->ims
.io_tss
;
571 register io_use_t iu
;
573 queue_iterate(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
) {
574 if (++count
< alloc_count
) {
575 *devices
= iu
->ps
->device
;
576 device_reference(*devices
);
581 simple_unlock(&pcb
->lock
);
582 simple_unlock(&iopb_lock
);
583 } while (count
> alloc_count
);
597 * If we allocated too much, must copy.
599 size_needed
= count
* sizeof(ipc_port_t
);
600 if (size_needed
< size
) {
601 vm_offset_t new_addr
;
603 new_addr
= kalloc(size_needed
);
605 for (i
= 0; i
< count
; i
++)
606 device_deallocate(devices
[i
]);
608 return KERN_RESOURCE_SHORTAGE
;
611 bcopy((char *)addr
, (char *)new_addr
, size_needed
);
613 devices
= (device_t
*)new_addr
;
616 for (i
= 0; i
< count
; i
++)
617 ((ipc_port_t
*)devices
)[i
] =
618 convert_device_to_port(devices
[i
]);
627 * Check whether an IO device is mapped to a particular thread.
628 * Used to support the 'iopl' device automatic mapping.
639 pcb
= thread
->top_act
->mact
.pcb
;
641 simple_lock(&iopb_lock
);
643 /* Find the io port for the device */
645 io_port
= device_to_io_port_lookup(device
);
647 simple_unlock(&iopb_lock
);
651 /* Look up the mapping in the device`s mapping list. */
653 queue_iterate(&io_port
->io_use_list
, iu
, io_use_t
, psq
) {
654 if (iu
->ts
== pcb
->ims
.io_tss
) {
658 simple_unlock(&iopb_lock
);
662 simple_unlock(&iopb_lock
);