Source to driverkit/KernBusMemory.m


Enter a symbol's name here to quickly find it.

/*
 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
 * Reserved.  This file contains Original Code and/or Modifications of
 * Original Code as defined in and that are subject to the Apple Public
 * Source License Version 1.0 (the 'License').  You may not use this file
 * except in compliance with the License.  Please obtain a copy of the
 * License at http://www.apple.com/publicsource and read it before using
 * this file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License."
 * 
 * @APPLE_LICENSE_HEADER_END@
 */

/*
 * Copyright (c) 1994 NeXT Computer, Inc.
 *
 * Kernel Bus Generic Memory Resource Object(s).
 *
 * HISTORY
 *
 * 15 Mar 1994 ? at NeXT
 *	Created.
 */

#import <mach/mach_types.h>
#import <vm/vm_kern.h>

#import <driverkit/KernBusMemory.h>

@implementation KernBusMemoryRange

- mapToAddress:		(vm_offset_t)destAddr
	inTarget:	(task_t)task
	cache:		(IOCache)cache
{
    Range		subRange = [self range];

    subRange.base = 0;

    return [[KernBusMemoryRangeMapping alloc]
				    initWithRange:self
				    subRange:subRange
				    atAddress:destAddr
				    inTarget:task
				    cache:cache];
}

- mapInTarget:		(task_t)task
	cache:		(IOCache)cache
{
    Range		subRange = [self range];

    subRange.base = 0;

    return [[KernBusMemoryRangeMapping alloc]
				    initWithRange:self
				    subRange:subRange
				    inTarget:task
				    cache:cache];
}

@end

#if ppc
#include <machdep/ppc/proc_reg.h>
#endif

@implementation KernBusMemoryRangeMapping

- initWithRange:	range
	subRange:	(Range)subRange
	atAddress:	(vm_offset_t)address
	inTarget:	(task_t)task
	cache:		(IOCache)cache
{
    Range		mappedRange;

    if (task == TASK_NULL)
    	return [self free];

    if ([super initWithRange:range subRange:subRange] == nil)
    	return nil;

    mappedRange = [self mappedRange];	// absolute physical range

#if ppc

    if( (task->map->pmap == kernel_pmap)
    &&  (IO_CacheOff	 == cache)
    &&  (address 	 == PEMapSegment( mappedRange.base, mappedRange.length)) ) {

	_address = address;
	_task = TASK_NULL;
	return self;

    } else {

	vm_offset_t	spa, epa;
    
	spa = mappedRange.base & 0xfffff000;
	epa = (mappedRange.base + mappedRange.length + 0xfff) & 0xfffff000;
	// non fatal - it may overlap another range
	pmap_add_physical_memory( spa, epa, FALSE, PTE_WIMG_IO);
    }

#endif

    if (_KernBusMemoryCreateMapping(
    				mappedRange.base,
				mappedRange.length, // will not work if == 0
				&address,
				task,
				NO,
				cache) != KERN_SUCCESS)
	return [self free];

    _task = task;
    _address = address;
    
    return self;
}

- initWithRange:	range
	subRange:	(Range)subRange
	inTarget:	(task_t)task
	cache:		(IOCache)cache
{
    Range		mappedRange;
    
    if (task == TASK_NULL)
    	return [self free];

    if ([super initWithRange:range subRange:subRange] == nil)
    	return nil;

    mappedRange = [self mappedRange];	// absolute physical range

#if ppc

    if( (task->map->pmap == kernel_pmap)
    &&  (IO_CacheOff	 == cache)
    &&  (_address 	 =  PEMapSegment( mappedRange.base, mappedRange.length)) ) {

	_task = TASK_NULL;
	return self;

    } else {

	vm_offset_t	spa, epa;
    
	spa = mappedRange.base & 0xfffff000;
	epa = (mappedRange.base + mappedRange.length + 0xfff) & 0xfffff000;
	// non fatal - it may overlap another range
	pmap_add_physical_memory( spa, epa, FALSE, PTE_WIMG_IO);
    }

#endif

    if (_KernBusMemoryCreateMapping(
    				mappedRange.base,
				mappedRange.length, // will not work if == 0
				&_address,
				task,
				YES,
				cache) != KERN_SUCCESS)
	return [self free];

    _task = task;

    return self;
}

- free
{
    Range		mappedRange = [self mappedRange];

    if (_task != TASK_NULL)
    	(void) vm_deallocate(_task->map, _address, mappedRange.length);

    return [super free];
}

- (task_t)task
{
    return _task;
}

- (vm_offset_t)address
{
    return _address;
}

@end

kern_return_t
_KernBusMemoryCreateMapping(
    vm_offset_t		physAddr,
    vm_size_t		length,
    vm_offset_t		*destAddr,
    task_t		task,
    BOOL		findSpace,
    IOCache		cache
)
{
    kern_return_t	result;
    vm_map_t		map = task->map;
    vm_offset_t		virtAddr;
    cache_spec_t	caching;
	
    vm_map_reference(map);
    
    if (findSpace)
    	*destAddr = vm_map_min(map);
    else
    	*destAddr = trunc_page(*destAddr);
    
    length = round_page(length);

    result = vm_map_find(
    			map,
			VM_OBJECT_NULL, (vm_offset_t) 0,
			destAddr, length,
			findSpace);
			
    if (result != KERN_SUCCESS) {
    	vm_map_deallocate(map);
	return result;
    }
    
    virtAddr = trunc_page(*destAddr);
    
    (void) vm_map_inherit(
			map,
			virtAddr, virtAddr + length,
			VM_INHERIT_NONE);
			
    physAddr = trunc_page(physAddr);
	
    switch (cache) {
    
    case IO_CacheOff:
    	caching = cache_disable;
	break;
	
    case IO_WriteThrough:
    	caching = cache_writethrough;
	break;
	
    default:
    	caching = cache_default;
	break;
    }
    
    while (length > 0) {
    	pmap_enter_cache_spec(
			    vm_map_pmap(map),
			    virtAddr,
			    physAddr,
			    VM_PROT_READ | VM_PROT_WRITE,
			    TRUE,
			    caching);
			    
	virtAddr += PAGE_SIZE; length -= PAGE_SIZE; physAddr += PAGE_SIZE;
    }
    
    vm_map_deallocate(map);
    
    return KERN_SUCCESS;
}