2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
26 * Mach Operating System
27 * Copyright (c) 1991,1990 Carnegie Mellon University
28 * All Rights Reserved.
30 * Permission to use, copy, modify and distribute this software and its
31 * documentation is hereby granted, provided that both the copyright
32 * notice and this permission notice appear in all copies of the
33 * software, derivative works or modified versions, and any portions
34 * thereof, and that both notices appear in supporting documentation.
36 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
40 * Carnegie Mellon requests users of this software to return to
42 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
43 * School of Computer Science
44 * Carnegie Mellon University
45 * Pittsburgh PA 15213-3890
47 * any improvements or extensions that they make and grant Carnegie Mellon
48 * the rights to redistribute these changes.
55 * Code to manipulate IO permission bitmaps.
60 #include <mach/boolean.h>
61 #include <mach/kern_return.h>
63 #include <ipc/ipc_port.h>
65 #include <kern/kalloc.h>
66 #include <kern/lock.h>
67 #include <kern/queue.h>
68 #include <kern/thread.h>
69 #include <kern/misc_protos.h>
72 #include <i386/io_port.h>
73 #include <i386/iopb.h>
75 #include <i386/iopb_entries.h>
84 iopb_destroy(iopb_tss_t io_tss
)
88 #if 0 /* Code removed until better solution comes on board */
90 * A set of ports for an IO device.
93 device_t device
; /* Mach device */
94 queue_chain_t dev_list
; /* link in device list */
95 queue_chain_t io_use_list
; /* List of threads that use it */
96 io_reg_t
*io_port_list
; /* list of IO ports that use it */
97 /* list ends with IO_REG_NULL */
99 typedef struct io_port
*io_port_t
;
102 * Lookup table for device -> io_port mapping
103 * (a linked list - I don't expect too many)
105 queue_head_t device_to_io_port_list
;
109 * all threads that have IO ports mapped
110 * all IO ports that have threads mapped
113 queue_chain_t psq
; /* Links from port set */
114 queue_chain_t tsq
; /* links from tss */
115 io_port_t ps
; /* Port set */
116 iopb_tss_t ts
; /* Task segment */
118 typedef struct io_use
*io_use_t
;
121 * Big lock for the whole mess.
123 decl_simple_lock_data(,iopb_lock
)
127 extern void io_bitmap_init(
129 extern void io_bitmap_set(
132 extern void io_bitmap_clear(
135 extern io_port_t
device_to_io_port_lookup(
137 extern void io_tss_init(
142 * Initialize the package.
147 queue_init(&device_to_io_port_list
);
148 simple_lock_init(&iopb_lock
, ETAP_IO_IOPB
);
152 * Initialize bitmap (set all bits to OFF == 1)
158 register unsigned char *b
;
161 s
= sizeof(isa_iopb
);
170 * Set selected bits in bitmap to ON == 0
179 while ((io_bit
= *bit_list
++) != IO_REG_NULL
) {
180 bp
[io_bit
>>3] &= ~(1 << (io_bit
& 0x7));
185 * Set selected bits in bitmap to OFF == 1
194 while ((io_bit
= *bit_list
++) != IO_REG_NULL
) {
195 bp
[io_bit
>>3] |= (1 << (io_bit
& 0x7));
200 * Lookup an io-port set by device
203 device_to_io_port_lookup(
206 register io_port_t io_port
;
208 queue_iterate(&device_to_io_port_list
, io_port
, io_port_t
, dev_list
) {
209 if (io_port
->device
== device
) {
218 * Create an io_port set
223 io_reg_t
*io_port_list
)
225 register io_port_t io_port
, old_io_port
;
227 io_port
= (io_port_t
) kalloc(sizeof(struct io_port
));
229 simple_lock(&iopb_lock
);
230 if (device_to_io_port_lookup(device
) != 0) {
231 simple_unlock(&iopb_lock
);
232 kfree((vm_offset_t
) io_port
, sizeof(struct io_port
));
236 io_port
->device
= device
;
237 queue_init(&io_port
->io_use_list
);
238 io_port
->io_port_list
= io_port_list
;
241 * Enter in lookup list.
243 queue_enter(&device_to_io_port_list
, io_port
, io_port_t
, dev_list
);
245 simple_unlock(&iopb_lock
);
250 * Destroy an io port set, removing any IO mappings.
259 simple_lock(&iopb_lock
);
260 io_port
= device_to_io_port_lookup(device
);
262 simple_unlock(&iopb_lock
);
266 queue_iterate(&io_port
->io_use_list
, iu
, io_use_t
, psq
) {
269 io_bitmap_clear(io_tss
->bitmap
, io_port
->io_port_list
);
270 queue_remove(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
);
272 queue_remove(&device_to_io_port_list
, io_port
, io_port_t
, dev_list
);
273 simple_unlock(&iopb_lock
);
275 while (!queue_empty(&io_port
->io_use_list
)) {
276 iu
= (io_use_t
) queue_first(&io_port
->io_use_list
);
277 queue_remove(&io_port
->io_use_list
, iu
, io_use_t
, psq
);
278 kfree((vm_offset_t
)iu
, sizeof(struct io_use
));
281 kfree((vm_offset_t
)io_port
, sizeof(struct io_port
));
285 * Initialize an IO TSS.
291 vm_offset_t addr
= (vm_offset_t
) io_tss
;
292 vm_size_t size
= (char *)&io_tss
->barrier
- (char *)io_tss
;
294 bzero((char *)&io_tss
->tss
, sizeof(struct i386_tss
));
295 io_tss
->tss
.io_bit_map_offset
296 = (char *)&io_tss
->bitmap
- (char *)io_tss
;
297 io_tss
->tss
.ss0
= KERNEL_DS
;
298 io_bitmap_init(io_tss
->bitmap
);
299 io_tss
->barrier
= ~0;
300 queue_init(&io_tss
->io_port_list
);
301 addr
+= LINEAR_KERNEL_ADDRESS
;
302 io_tss
->iopb_desc
[0] = ((size
-1) & 0xffff)
303 | ((addr
& 0xffff) << 16);
304 io_tss
->iopb_desc
[1] = ((addr
& 0x00ff0000) >> 16)
305 | ((ACC_TSS
|ACC_PL_K
|ACC_P
) << 8)
306 | ((size
-1) & 0x000f0000)
307 | (addr
& 0xff000000);
317 register iopb_tss_t ts
;
319 ts
= (iopb_tss_t
) kalloc(sizeof (struct iopb_tss
));
326 * Destroy an IOPB_TSS
335 simple_lock(&iopb_lock
);
337 queue_iterate(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
) {
339 /* skip bitmap clear - entire bitmap will vanish */
340 queue_remove(&io_port
->io_use_list
, iu
, io_use_t
, psq
);
343 simple_unlock(&iopb_lock
);
345 while (!queue_empty(&io_tss
->io_port_list
)) {
346 iu
= (io_use_t
) queue_first(&io_tss
->io_port_list
);
347 queue_remove(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
);
348 kfree((vm_offset_t
)iu
, sizeof(struct io_use
));
351 kfree((vm_offset_t
)io_tss
, sizeof(struct iopb_tss
));
355 * Add an IO mapping to a thread.
363 iopb_tss_t io_tss
, new_io_tss
;
367 if (thread
== THREAD_NULL
368 || device
== DEVICE_NULL
)
369 return KERN_INVALID_ARGUMENT
;
371 pcb
= thread
->top_act
->mact
.pcb
;
374 iu
= (io_use_t
) kalloc(sizeof(struct io_use
));
377 simple_lock(&iopb_lock
);
379 /* find the io_port_t for the device */
380 io_port
= device_to_io_port_lookup(device
);
383 * Device does not have IO ports available.
385 simple_unlock(&iopb_lock
);
387 kfree((vm_offset_t
)new_io_tss
, sizeof(struct iopb_tss
));
388 kfree((vm_offset_t
) iu
, sizeof(struct io_use
));
389 return KERN_INVALID_ARGUMENT
;
392 /* Have the IO port. */
394 /* Make sure the thread has a TSS. */
396 simple_lock(&pcb
->lock
);
397 io_tss
= pcb
->ims
.io_tss
;
399 if (new_io_tss
== 0) {
401 * Allocate an IO-tss.
403 simple_unlock(&pcb
->lock
);
404 simple_unlock(&iopb_lock
);
406 new_io_tss
= (iopb_tss_t
) kalloc(sizeof(struct iopb_tss
));
407 io_tss_init(new_io_tss
);
412 pcb
->ims
.io_tss
= io_tss
;
417 * Have io_port and io_tss.
418 * See whether device is already mapped.
420 queue_iterate(&io_tss
->io_port_list
, old_iu
, io_use_t
, tsq
) {
421 if (old_iu
->ps
== io_port
) {
425 simple_unlock(&pcb
->lock
);
426 simple_unlock(&iopb_lock
);
428 kfree((vm_offset_t
)iu
, sizeof(struct io_use
));
430 kfree((vm_offset_t
)new_io_tss
, sizeof(struct iopb_tss
));
440 queue_enter(&io_port
->io_use_list
, iu
, io_use_t
, psq
);
441 queue_enter(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
);
442 io_bitmap_set(io_tss
->bitmap
, io_port
->io_port_list
);
444 simple_unlock(&pcb
->lock
);
445 simple_unlock(&iopb_lock
);
448 kfree((vm_offset_t
)new_io_tss
, sizeof(struct iopb_tss
));
454 * Remove an IO mapping from a thread.
466 if (thread
== THREAD_NULL
467 || device
== DEVICE_NULL
)
468 return KERN_INVALID_ARGUMENT
;
470 pcb
= thread
->top_act
->mact
.pcb
;
472 simple_lock(&iopb_lock
);
474 /* find the io_port_t for the device */
476 io_port
= device_to_io_port_lookup(device
);
479 * Device does not have IO ports available.
481 simple_unlock(&iopb_lock
);
482 return KERN_INVALID_ARGUMENT
;
485 simple_lock(&pcb
->lock
);
486 io_tss
= pcb
->ims
.io_tss
;
488 simple_unlock(&pcb
->lock
);
489 simple_unlock(&iopb_lock
);
490 return KERN_INVALID_ARGUMENT
; /* not mapped */
496 queue_iterate(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
) {
497 if (iu
->ps
== io_port
) {
499 * Found mapping. Remove it.
501 io_bitmap_clear(io_tss
->bitmap
, io_port
->io_port_list
);
503 queue_remove(&io_port
->io_use_list
, iu
, io_use_t
, psq
);
504 queue_remove(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
);
506 simple_unlock(&pcb
->lock
);
507 simple_unlock(&iopb_lock
);
509 kfree((vm_offset_t
)iu
, sizeof(struct io_use
));
518 return KERN_INVALID_ARGUMENT
;
522 * Return the IO ports mapped into a thread.
526 i386_io_port_list(thread
, list
, list_count
)
529 unsigned int *list_count
;
532 register iopb_tss_t io_tss
;
533 unsigned int count
, alloc_count
;
535 vm_size_t size_needed
, size
;
539 if (thread
== THREAD_NULL
)
540 return KERN_INVALID_ARGUMENT
;
542 pcb
= thread
->top_act
->mact
.pcb
;
544 alloc_count
= 16; /* a guess */
547 size_needed
= alloc_count
* sizeof(ipc_port_t
);
548 if (size_needed
<= size
)
554 assert(size_needed
> 0);
559 return KERN_RESOURCE_SHORTAGE
;
561 devices
= (device_t
*)addr
;
564 simple_lock(&iopb_lock
);
565 simple_lock(&pcb
->lock
);
566 io_tss
= pcb
->ims
.io_tss
;
568 register io_use_t iu
;
570 queue_iterate(&io_tss
->io_port_list
, iu
, io_use_t
, tsq
) {
571 if (++count
< alloc_count
) {
572 *devices
= iu
->ps
->device
;
573 device_reference(*devices
);
578 simple_unlock(&pcb
->lock
);
579 simple_unlock(&iopb_lock
);
580 } while (count
> alloc_count
);
594 * If we allocated too much, must copy.
596 size_needed
= count
* sizeof(ipc_port_t
);
597 if (size_needed
< size
) {
598 vm_offset_t new_addr
;
600 new_addr
= kalloc(size_needed
);
602 for (i
= 0; i
< count
; i
++)
603 device_deallocate(devices
[i
]);
605 return KERN_RESOURCE_SHORTAGE
;
608 bcopy((char *)addr
, (char *)new_addr
, size_needed
);
610 devices
= (device_t
*)new_addr
;
613 for (i
= 0; i
< count
; i
++)
614 ((ipc_port_t
*)devices
)[i
] =
615 convert_device_to_port(devices
[i
]);
624 * Check whether an IO device is mapped to a particular thread.
625 * Used to support the 'iopl' device automatic mapping.
636 pcb
= thread
->top_act
->mact
.pcb
;
638 simple_lock(&iopb_lock
);
640 /* Find the io port for the device */
642 io_port
= device_to_io_port_lookup(device
);
644 simple_unlock(&iopb_lock
);
648 /* Look up the mapping in the device`s mapping list. */
650 queue_iterate(&io_port
->io_use_list
, iu
, io_use_t
, psq
) {
651 if (iu
->ts
== pcb
->ims
.io_tss
) {
655 simple_unlock(&iopb_lock
);
659 simple_unlock(&iopb_lock
);