2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_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 License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 * Mach Operating System
33 * Copyright (c) 1991,1990 Carnegie Mellon University
34 * All Rights Reserved.
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
46 * Carnegie Mellon requests users of this software to return to
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
61 * Code to manipulate IO permission bitmaps.
66 #include <mach/boolean.h>
67 #include <mach/kern_return.h>
69 #include <ipc/ipc_port.h>
71 #include <kern/kalloc.h>
72 #include <kern/lock.h>
73 #include <kern/queue.h>
74 #include <kern/thread.h>
75 #include <kern/misc_protos.h>
78 #include <i386/io_port.h>
79 #include <i386/iopb.h>
81 #include <i386/iopb_entries.h>
90 iopb_destroy(__unused iopb_tss_t io_tss
)
94 #if 0 /* Code removed until better solution comes on board */
96 * A set of ports for an IO device.
99 device_t device
; /* Mach device */
100 queue_chain_t dev_list
; /* link in device list */
101 queue_chain_t io_use_list
; /* List of threads that use it */
102 io_reg_t
*io_port_list
; /* list of IO ports that use it */
103 /* list ends with IO_REG_NULL */
105 typedef struct io_port
*io_port_t
;
108 * Lookup table for device -> io_port mapping
109 * (a linked list - I don't expect too many)
111 queue_head_t device_to_io_port_list
;
115 * all threads that have IO ports mapped
116 * all IO ports that have threads mapped
119 queue_chain_t psq
; /* Links from port set */
120 queue_chain_t tsq
; /* links from tss */
121 io_port_t ps
; /* Port set */
122 iopb_tss_t ts
; /* Task segment */
124 typedef struct io_use
*io_use_t
;
127 * Big lock for the whole mess.
129 decl_simple_lock_data(,iopb_lock
)
133 extern void io_bitmap_init(
135 extern void io_bitmap_set(
138 extern void io_bitmap_clear(
141 extern io_port_t
device_to_io_port_lookup(
143 extern void io_tss_init(
148 * Initialize the package.
153 queue_init(&device_to_io_port_list
);
154 simple_lock_init(&iopb_lock
, 0);
158 * Initialize bitmap (set all bits to OFF == 1)
164 register unsigned char *b
;
167 s
= sizeof(isa_iopb
);
176 * Set selected bits in bitmap to ON == 0
185 while ((io_bit
= *bit_list
++) != IO_REG_NULL
) {
186 bp
[io_bit
>>3] &= ~(1 << (io_bit
& 0x7));
191 * Set selected bits in bitmap to OFF == 1
200 while ((io_bit
= *bit_list
++) != IO_REG_NULL
) {
201 bp
[io_bit
>>3] |= (1 << (io_bit
& 0x7));
206 * Lookup an io-port set by device
209 device_to_io_port_lookup(
212 register io_port_t io_port
;
214 queue_iterate(&device_to_io_port_list
, io_port
, io_port_t
, dev_list
) {
215 if (io_port
->device
== device
) {
224 * Create an io_port set
229 io_reg_t
*io_port_list
)
231 register io_port_t io_port
, old_io_port
;
233 io_port
= (io_port_t
) kalloc(sizeof(struct io_port
));
235 simple_lock(&iopb_lock
);
236 if (device_to_io_port_lookup(device
) != 0) {
237 simple_unlock(&iopb_lock
);
238 kfree((vm_offset_t
) io_port
, sizeof(struct io_port
));
242 io_port
->device
= device
;
243 queue_init(&io_port
->io_use_list
);
244 io_port
->io_port_list
= io_port_list
;
247 * Enter in lookup list.
249 queue_enter(&device_to_io_port_list
, io_port
, io_port_t
, dev_list
);
251 simple_unlock(&iopb_lock
);
256 * Destroy an io port set, removing any IO mappings.
265 simple_lock(&iopb_lock
);
266 io_port
= device_to_io_port_lookup(device
);
268 simple_unlock(&iopb_lock
);
272 queue_iterate(&io_port
->io_use_list
, iu
, io_use_t
, psq
) {
275 io_bitmap_clear(io_tss
->bitmap
, io_port
->io_port_list
);
276 queue_remove(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
);
278 queue_remove(&device_to_io_port_list
, io_port
, io_port_t
, dev_list
);
279 simple_unlock(&iopb_lock
);
281 while (!queue_empty(&io_port
->io_use_list
)) {
282 iu
= (io_use_t
) queue_first(&io_port
->io_use_list
);
283 queue_remove(&io_port
->io_use_list
, iu
, io_use_t
, psq
);
284 kfree((vm_offset_t
)iu
, sizeof(struct io_use
));
287 kfree((vm_offset_t
)io_port
, sizeof(struct io_port
));
291 * Initialize an IO TSS.
297 vm_offset_t addr
= (vm_offset_t
) io_tss
;
298 vm_size_t size
= (char *)&io_tss
->barrier
- (char *)io_tss
;
300 bzero((char *)&io_tss
->tss
, sizeof(struct i386_tss
));
301 io_tss
->tss
.io_bit_map_offset
302 = (char *)&io_tss
->bitmap
- (char *)io_tss
;
303 io_tss
->tss
.ss0
= KERNEL_DS
;
304 io_bitmap_init(io_tss
->bitmap
);
305 io_tss
->barrier
= ~0;
306 queue_init(&io_tss
->io_port_list
);
307 addr
|= LINEAR_KERNEL_ADDRESS
;
308 io_tss
->iopb_desc
[0] = ((size
-1) & 0xffff)
309 | ((addr
& 0xffff) << 16);
310 io_tss
->iopb_desc
[1] = ((addr
& 0x00ff0000) >> 16)
311 | ((ACC_TSS
|ACC_PL_K
|ACC_P
) << 8)
312 | ((size
-1) & 0x000f0000)
313 | (addr
& 0xff000000);
323 register iopb_tss_t ts
;
325 ts
= (iopb_tss_t
) kalloc(sizeof (struct iopb_tss
));
332 * Destroy an IOPB_TSS
341 simple_lock(&iopb_lock
);
343 queue_iterate(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
) {
345 /* skip bitmap clear - entire bitmap will vanish */
346 queue_remove(&io_port
->io_use_list
, iu
, io_use_t
, psq
);
349 simple_unlock(&iopb_lock
);
351 while (!queue_empty(&io_tss
->io_port_list
)) {
352 iu
= (io_use_t
) queue_first(&io_tss
->io_port_list
);
353 queue_remove(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
);
354 kfree((vm_offset_t
)iu
, sizeof(struct io_use
));
357 kfree((vm_offset_t
)io_tss
, sizeof(struct iopb_tss
));
361 * Add an IO mapping to a thread.
369 iopb_tss_t io_tss
, new_io_tss
;
373 if (thread
== THREAD_NULL
374 || device
== DEVICE_NULL
)
375 return KERN_INVALID_ARGUMENT
;
377 pcb
= thread
->machine
.pcb
;
380 iu
= (io_use_t
) kalloc(sizeof(struct io_use
));
383 simple_lock(&iopb_lock
);
385 /* find the io_port_t for the device */
386 io_port
= device_to_io_port_lookup(device
);
389 * Device does not have IO ports available.
391 simple_unlock(&iopb_lock
);
393 kfree((vm_offset_t
)new_io_tss
, sizeof(struct iopb_tss
));
394 kfree((vm_offset_t
) iu
, sizeof(struct io_use
));
395 return KERN_INVALID_ARGUMENT
;
398 /* Have the IO port. */
400 /* Make sure the thread has a TSS. */
402 simple_lock(&pcb
->lock
);
403 io_tss
= pcb
->ims
.io_tss
;
405 if (new_io_tss
== 0) {
407 * Allocate an IO-tss.
409 simple_unlock(&pcb
->lock
);
410 simple_unlock(&iopb_lock
);
412 new_io_tss
= (iopb_tss_t
) kalloc(sizeof(struct iopb_tss
));
413 io_tss_init(new_io_tss
);
418 pcb
->ims
.io_tss
= io_tss
;
423 * Have io_port and io_tss.
424 * See whether device is already mapped.
426 queue_iterate(&io_tss
->io_port_list
, old_iu
, io_use_t
, tsq
) {
427 if (old_iu
->ps
== io_port
) {
431 simple_unlock(&pcb
->lock
);
432 simple_unlock(&iopb_lock
);
434 kfree((vm_offset_t
)iu
, sizeof(struct io_use
));
436 kfree((vm_offset_t
)new_io_tss
, sizeof(struct iopb_tss
));
446 queue_enter(&io_port
->io_use_list
, iu
, io_use_t
, psq
);
447 queue_enter(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
);
448 io_bitmap_set(io_tss
->bitmap
, io_port
->io_port_list
);
450 simple_unlock(&pcb
->lock
);
451 simple_unlock(&iopb_lock
);
454 kfree((vm_offset_t
)new_io_tss
, sizeof(struct iopb_tss
));
460 * Remove an IO mapping from a thread.
472 if (thread
== THREAD_NULL
473 || device
== DEVICE_NULL
)
474 return KERN_INVALID_ARGUMENT
;
476 pcb
= thread
->machine
.pcb
;
478 simple_lock(&iopb_lock
);
480 /* find the io_port_t for the device */
482 io_port
= device_to_io_port_lookup(device
);
485 * Device does not have IO ports available.
487 simple_unlock(&iopb_lock
);
488 return KERN_INVALID_ARGUMENT
;
491 simple_lock(&pcb
->lock
);
492 io_tss
= pcb
->ims
.io_tss
;
494 simple_unlock(&pcb
->lock
);
495 simple_unlock(&iopb_lock
);
496 return KERN_INVALID_ARGUMENT
; /* not mapped */
502 queue_iterate(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
) {
503 if (iu
->ps
== io_port
) {
505 * Found mapping. Remove it.
507 io_bitmap_clear(io_tss
->bitmap
, io_port
->io_port_list
);
509 queue_remove(&io_port
->io_use_list
, iu
, io_use_t
, psq
);
510 queue_remove(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
);
512 simple_unlock(&pcb
->lock
);
513 simple_unlock(&iopb_lock
);
515 kfree((vm_offset_t
)iu
, sizeof(struct io_use
));
524 return KERN_INVALID_ARGUMENT
;
528 * Return the IO ports mapped into a thread.
532 i386_io_port_list(thread
, list
, list_count
)
535 unsigned int *list_count
;
538 register iopb_tss_t io_tss
;
539 unsigned int count
, alloc_count
;
541 vm_size_t size_needed
, size
;
545 if (thread
== THREAD_NULL
)
546 return KERN_INVALID_ARGUMENT
;
548 pcb
= thread
->machine
.pcb
;
550 alloc_count
= 16; /* a guess */
553 size_needed
= alloc_count
* sizeof(ipc_port_t
);
554 if (size_needed
<= size
)
560 assert(size_needed
> 0);
565 return KERN_RESOURCE_SHORTAGE
;
567 devices
= (device_t
*)addr
;
570 simple_lock(&iopb_lock
);
571 simple_lock(&pcb
->lock
);
572 io_tss
= pcb
->ims
.io_tss
;
574 register io_use_t iu
;
576 queue_iterate(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
) {
577 if (++count
< alloc_count
) {
578 *devices
= iu
->ps
->device
;
579 device_reference(*devices
);
584 simple_unlock(&pcb
->lock
);
585 simple_unlock(&iopb_lock
);
586 } while (count
> alloc_count
);
600 * If we allocated too much, must copy.
602 size_needed
= count
* sizeof(ipc_port_t
);
603 if (size_needed
< size
) {
604 vm_offset_t new_addr
;
606 new_addr
= kalloc(size_needed
);
608 for (i
= 0; i
< count
; i
++)
609 device_deallocate(devices
[i
]);
611 return KERN_RESOURCE_SHORTAGE
;
614 bcopy((char *)addr
, (char *)new_addr
, size_needed
);
616 devices
= (device_t
*)new_addr
;
619 for (i
= 0; i
< count
; i
++)
620 ((ipc_port_t
*)devices
)[i
] =
621 convert_device_to_port(devices
[i
]);
630 * Check whether an IO device is mapped to a particular thread.
631 * Used to support the 'iopl' device automatic mapping.
642 pcb
= thread
->machine
.pcb
;
644 simple_lock(&iopb_lock
);
646 /* Find the io port for the device */
648 io_port
= device_to_io_port_lookup(device
);
650 simple_unlock(&iopb_lock
);
654 /* Look up the mapping in the device`s mapping list. */
656 queue_iterate(&io_port
->io_use_list
, iu
, io_use_t
, psq
) {
657 if (iu
->ts
== pcb
->ims
.io_tss
) {
661 simple_unlock(&iopb_lock
);
665 simple_unlock(&iopb_lock
);