2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
34 * Mach Operating System
35 * Copyright (c) 1991,1990 Carnegie Mellon University
36 * All Rights Reserved.
38 * Permission to use, copy, modify and distribute this software and its
39 * documentation is hereby granted, provided that both the copyright
40 * notice and this permission notice appear in all copies of the
41 * software, derivative works or modified versions, and any portions
42 * thereof, and that both notices appear in supporting documentation.
44 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
45 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
46 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
48 * Carnegie Mellon requests users of this software to return to
50 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
51 * School of Computer Science
52 * Carnegie Mellon University
53 * Pittsburgh PA 15213-3890
55 * any improvements or extensions that they make and grant Carnegie Mellon
56 * the rights to redistribute these changes.
63 * Code to manipulate IO permission bitmaps.
68 #include <mach/boolean.h>
69 #include <mach/kern_return.h>
71 #include <ipc/ipc_port.h>
73 #include <kern/kalloc.h>
74 #include <kern/lock.h>
75 #include <kern/queue.h>
76 #include <kern/thread.h>
77 #include <kern/misc_protos.h>
80 #include <i386/io_port.h>
81 #include <i386/iopb.h>
83 #include <i386/iopb_entries.h>
92 iopb_destroy(__unused iopb_tss_t io_tss
)
96 #if 0 /* Code removed until better solution comes on board */
98 * A set of ports for an IO device.
101 device_t device
; /* Mach device */
102 queue_chain_t dev_list
; /* link in device list */
103 queue_chain_t io_use_list
; /* List of threads that use it */
104 io_reg_t
*io_port_list
; /* list of IO ports that use it */
105 /* list ends with IO_REG_NULL */
107 typedef struct io_port
*io_port_t
;
110 * Lookup table for device -> io_port mapping
111 * (a linked list - I don't expect too many)
113 queue_head_t device_to_io_port_list
;
117 * all threads that have IO ports mapped
118 * all IO ports that have threads mapped
121 queue_chain_t psq
; /* Links from port set */
122 queue_chain_t tsq
; /* links from tss */
123 io_port_t ps
; /* Port set */
124 iopb_tss_t ts
; /* Task segment */
126 typedef struct io_use
*io_use_t
;
129 * Big lock for the whole mess.
131 decl_simple_lock_data(,iopb_lock
)
135 extern void io_bitmap_init(
137 extern void io_bitmap_set(
140 extern void io_bitmap_clear(
143 extern io_port_t
device_to_io_port_lookup(
145 extern void io_tss_init(
150 * Initialize the package.
155 queue_init(&device_to_io_port_list
);
156 simple_lock_init(&iopb_lock
, 0);
160 * Initialize bitmap (set all bits to OFF == 1)
166 register unsigned char *b
;
169 s
= sizeof(isa_iopb
);
178 * Set selected bits in bitmap to ON == 0
187 while ((io_bit
= *bit_list
++) != IO_REG_NULL
) {
188 bp
[io_bit
>>3] &= ~(1 << (io_bit
& 0x7));
193 * Set selected bits in bitmap to OFF == 1
202 while ((io_bit
= *bit_list
++) != IO_REG_NULL
) {
203 bp
[io_bit
>>3] |= (1 << (io_bit
& 0x7));
208 * Lookup an io-port set by device
211 device_to_io_port_lookup(
214 register io_port_t io_port
;
216 queue_iterate(&device_to_io_port_list
, io_port
, io_port_t
, dev_list
) {
217 if (io_port
->device
== device
) {
226 * Create an io_port set
231 io_reg_t
*io_port_list
)
233 register io_port_t io_port
, old_io_port
;
235 io_port
= (io_port_t
) kalloc(sizeof(struct io_port
));
237 simple_lock(&iopb_lock
);
238 if (device_to_io_port_lookup(device
) != 0) {
239 simple_unlock(&iopb_lock
);
240 kfree((vm_offset_t
) io_port
, sizeof(struct io_port
));
244 io_port
->device
= device
;
245 queue_init(&io_port
->io_use_list
);
246 io_port
->io_port_list
= io_port_list
;
249 * Enter in lookup list.
251 queue_enter(&device_to_io_port_list
, io_port
, io_port_t
, dev_list
);
253 simple_unlock(&iopb_lock
);
258 * Destroy an io port set, removing any IO mappings.
267 simple_lock(&iopb_lock
);
268 io_port
= device_to_io_port_lookup(device
);
270 simple_unlock(&iopb_lock
);
274 queue_iterate(&io_port
->io_use_list
, iu
, io_use_t
, psq
) {
277 io_bitmap_clear(io_tss
->bitmap
, io_port
->io_port_list
);
278 queue_remove(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
);
280 queue_remove(&device_to_io_port_list
, io_port
, io_port_t
, dev_list
);
281 simple_unlock(&iopb_lock
);
283 while (!queue_empty(&io_port
->io_use_list
)) {
284 iu
= (io_use_t
) queue_first(&io_port
->io_use_list
);
285 queue_remove(&io_port
->io_use_list
, iu
, io_use_t
, psq
);
286 kfree((vm_offset_t
)iu
, sizeof(struct io_use
));
289 kfree((vm_offset_t
)io_port
, sizeof(struct io_port
));
293 * Initialize an IO TSS.
299 vm_offset_t addr
= (vm_offset_t
) io_tss
;
300 vm_size_t size
= (char *)&io_tss
->barrier
- (char *)io_tss
;
302 bzero((char *)&io_tss
->tss
, sizeof(struct i386_tss
));
303 io_tss
->tss
.io_bit_map_offset
304 = (char *)&io_tss
->bitmap
- (char *)io_tss
;
305 io_tss
->tss
.ss0
= KERNEL_DS
;
306 io_bitmap_init(io_tss
->bitmap
);
307 io_tss
->barrier
= ~0;
308 queue_init(&io_tss
->io_port_list
);
309 addr
|= LINEAR_KERNEL_ADDRESS
;
310 io_tss
->iopb_desc
[0] = ((size
-1) & 0xffff)
311 | ((addr
& 0xffff) << 16);
312 io_tss
->iopb_desc
[1] = ((addr
& 0x00ff0000) >> 16)
313 | ((ACC_TSS
|ACC_PL_K
|ACC_P
) << 8)
314 | ((size
-1) & 0x000f0000)
315 | (addr
& 0xff000000);
325 register iopb_tss_t ts
;
327 ts
= (iopb_tss_t
) kalloc(sizeof (struct iopb_tss
));
334 * Destroy an IOPB_TSS
343 simple_lock(&iopb_lock
);
345 queue_iterate(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
) {
347 /* skip bitmap clear - entire bitmap will vanish */
348 queue_remove(&io_port
->io_use_list
, iu
, io_use_t
, psq
);
351 simple_unlock(&iopb_lock
);
353 while (!queue_empty(&io_tss
->io_port_list
)) {
354 iu
= (io_use_t
) queue_first(&io_tss
->io_port_list
);
355 queue_remove(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
);
356 kfree((vm_offset_t
)iu
, sizeof(struct io_use
));
359 kfree((vm_offset_t
)io_tss
, sizeof(struct iopb_tss
));
363 * Add an IO mapping to a thread.
371 iopb_tss_t io_tss
, new_io_tss
;
375 if (thread
== THREAD_NULL
376 || device
== DEVICE_NULL
)
377 return KERN_INVALID_ARGUMENT
;
379 pcb
= thread
->machine
.pcb
;
382 iu
= (io_use_t
) kalloc(sizeof(struct io_use
));
385 simple_lock(&iopb_lock
);
387 /* find the io_port_t for the device */
388 io_port
= device_to_io_port_lookup(device
);
391 * Device does not have IO ports available.
393 simple_unlock(&iopb_lock
);
395 kfree((vm_offset_t
)new_io_tss
, sizeof(struct iopb_tss
));
396 kfree((vm_offset_t
) iu
, sizeof(struct io_use
));
397 return KERN_INVALID_ARGUMENT
;
400 /* Have the IO port. */
402 /* Make sure the thread has a TSS. */
404 simple_lock(&pcb
->lock
);
405 io_tss
= pcb
->io_tss
;
407 if (new_io_tss
== 0) {
409 * Allocate an IO-tss.
411 simple_unlock(&pcb
->lock
);
412 simple_unlock(&iopb_lock
);
414 new_io_tss
= (iopb_tss_t
) kalloc(sizeof(struct iopb_tss
));
415 io_tss_init(new_io_tss
);
420 pcb
->io_tss
= io_tss
;
425 * Have io_port and io_tss.
426 * See whether device is already mapped.
428 queue_iterate(&io_tss
->io_port_list
, old_iu
, io_use_t
, tsq
) {
429 if (old_iu
->ps
== io_port
) {
433 simple_unlock(&pcb
->lock
);
434 simple_unlock(&iopb_lock
);
436 kfree((vm_offset_t
)iu
, sizeof(struct io_use
));
438 kfree((vm_offset_t
)new_io_tss
, sizeof(struct iopb_tss
));
448 queue_enter(&io_port
->io_use_list
, iu
, io_use_t
, psq
);
449 queue_enter(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
);
450 io_bitmap_set(io_tss
->bitmap
, io_port
->io_port_list
);
452 simple_unlock(&pcb
->lock
);
453 simple_unlock(&iopb_lock
);
456 kfree((vm_offset_t
)new_io_tss
, sizeof(struct iopb_tss
));
462 * Remove an IO mapping from a thread.
474 if (thread
== THREAD_NULL
475 || device
== DEVICE_NULL
)
476 return KERN_INVALID_ARGUMENT
;
478 pcb
= thread
->machine
.pcb
;
480 simple_lock(&iopb_lock
);
482 /* find the io_port_t for the device */
484 io_port
= device_to_io_port_lookup(device
);
487 * Device does not have IO ports available.
489 simple_unlock(&iopb_lock
);
490 return KERN_INVALID_ARGUMENT
;
493 simple_lock(&pcb
->lock
);
494 io_tss
= pcb
->io_tss
;
496 simple_unlock(&pcb
->lock
);
497 simple_unlock(&iopb_lock
);
498 return KERN_INVALID_ARGUMENT
; /* not mapped */
504 queue_iterate(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
) {
505 if (iu
->ps
== io_port
) {
507 * Found mapping. Remove it.
509 io_bitmap_clear(io_tss
->bitmap
, io_port
->io_port_list
);
511 queue_remove(&io_port
->io_use_list
, iu
, io_use_t
, psq
);
512 queue_remove(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
);
514 simple_unlock(&pcb
->lock
);
515 simple_unlock(&iopb_lock
);
517 kfree((vm_offset_t
)iu
, sizeof(struct io_use
));
526 return KERN_INVALID_ARGUMENT
;
530 * Return the IO ports mapped into a thread.
534 i386_io_port_list(thread
, list
, list_count
)
537 unsigned int *list_count
;
540 register iopb_tss_t io_tss
;
541 unsigned int count
, alloc_count
;
543 vm_size_t size_needed
, size
;
547 if (thread
== THREAD_NULL
)
548 return KERN_INVALID_ARGUMENT
;
550 pcb
= thread
->machine
.pcb
;
552 alloc_count
= 16; /* a guess */
555 size_needed
= alloc_count
* sizeof(ipc_port_t
);
556 if (size_needed
<= size
)
562 assert(size_needed
> 0);
567 return KERN_RESOURCE_SHORTAGE
;
569 devices
= (device_t
*)addr
;
572 simple_lock(&iopb_lock
);
573 simple_lock(&pcb
->lock
);
574 io_tss
= pcb
->io_tss
;
576 register io_use_t iu
;
578 queue_iterate(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
) {
579 if (++count
< alloc_count
) {
580 *devices
= iu
->ps
->device
;
581 device_reference(*devices
);
586 simple_unlock(&pcb
->lock
);
587 simple_unlock(&iopb_lock
);
588 } while (count
> alloc_count
);
602 * If we allocated too much, must copy.
604 size_needed
= count
* sizeof(ipc_port_t
);
605 if (size_needed
< size
) {
606 vm_offset_t new_addr
;
608 new_addr
= kalloc(size_needed
);
610 for (i
= 0; i
< count
; i
++)
611 device_deallocate(devices
[i
]);
613 return KERN_RESOURCE_SHORTAGE
;
616 bcopy((char *)addr
, (char *)new_addr
, size_needed
);
618 devices
= (device_t
*)new_addr
;
621 for (i
= 0; i
< count
; i
++)
622 ((ipc_port_t
*)devices
)[i
] =
623 convert_device_to_port(devices
[i
]);
632 * Check whether an IO device is mapped to a particular thread.
633 * Used to support the 'iopl' device automatic mapping.
644 pcb
= thread
->machine
.pcb
;
646 simple_lock(&iopb_lock
);
648 /* Find the io port for the device */
650 io_port
= device_to_io_port_lookup(device
);
652 simple_unlock(&iopb_lock
);
656 /* Look up the mapping in the device`s mapping list. */
658 queue_iterate(&io_port
->io_use_list
, iu
, io_use_t
, psq
) {
659 if (iu
->ts
== pcb
->io_tss
) {
663 simple_unlock(&iopb_lock
);
667 simple_unlock(&iopb_lock
);