File:  [Apple Darwin 0.x] / driverkit / libDriver / Kernel / IOBuffer.m
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:37:51 2018 UTC (8 years, 3 months ago) by root
Branches: MAIN, Apple
CVS tags: HEAD, Darwin03, Darwin02
Darwin 0.2 Driver Kit

/*
 * 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.1 (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 1994 NeXT Computer, Inc.
 * All rights reserved.
 *
 */

#if NOTYET

/* Clean this up later. */
#define KERNEL_PRIVATE	1 
#define ARCH_PRIVATE	1 

#import <driverkit/IOBuffer.h>
#import <driverkit/generalFuncs.h>
#import <vm/vm_map.h>
#import <mach/vm_param.h>

#define MIN(a,b) ((a) < (b) ? (a) : (b))

/*
 * Helper functions
 */
static BOOL checkAlignmentFromVirtual(
    IOVirtualAddress	vaddr,
    IOAddressMap	map,
    int			size,
    IOAlignment	align
);
static BOOL checkAlignmentFromPhysical(
    IOPhysicalAddress	paddr,
    int			size,
    IOAlignment	align
);
static BOOL checkAlignmentFromSize(
    int			size,
    IOAlignment	align
);
static unsigned int
maskFromAlignment(
    IOAlignment		align
);
static unsigned int
alignmentFromAddress(
    IOVirtualAddress	addr
);
static void
copyData(
    IOVirtualAddress src,
    IOAddressMap srcMap,
    IOVirtualAddress dst,
    IOAddressMap dstMap,
    unsigned int totalLength
);



@implementation IOBuffer

-initWithSize:(unsigned int)newSize
{
    return [self initWithSize:newSize attributes:IOBuf_None
            alignment:IOBufferAlignMin];
}

-initWithSize:(unsigned int)newSize
 attributes:(IOBufferAttributes)newAttrs
 alignment:(IOAlignment)align
{
    if (checkAlignmentFromSize(newSize, align) == NO) {
	return nil;
    }
    
    size = newSize;
    alignment = align;
    if ([[self class] allocMemoryWithSize:newSize
		attributes:newAttrs
		alignment:align
		allocedAddress:&allocedData
		dataAddress:(IOVirtualAddress *)&data
		allocedSize:&allocedSize
		newAttributes:&attributes
		newMap:&map] == NO) {
	return nil;
    }

    attributes = newAttrs | IOBuf_Wired | IOBuf_Contiguous | IOBuf_WiredStatic;

    map = (IOAddressMap)IOVmTaskSelf();
    
    return self;
}


-initFromVirtualAddress:(IOVirtualAddress)addr
 addressMap:(IOAddressMap)newMap
 size:(unsigned int)newSize
{
    data = (void *)addr;
    map = newMap;

    alignment = MIN(alignmentFromAddress(addr),
    		    alignmentFromAddress(newSize));
    size = newSize;
	
    return self;
}


-initFromPhysicalAddress:(IOPhysicalAddress)addr
 size:(unsigned int)newSize
{
    data = (void *)addr;
    
    alignment = MIN(alignmentFromAddress(addr),
                    alignmentFromAddress(newSize));
    return nil;
}

-free
{
    (void)[self unwireMemory];
    if (allocedData) {
	[[self class] freeMemory:allocedData
	      size:allocedSize
	      map:map
	      attributes:attributes];
    }
    return [super free];
}

-(BOOL)copyFromBuffer:(IOBuffer *)sourceBuffer
{
    int length, sourceSize;
    BOOL rtn;
    IORange source, dest;
    
    sourceSize = [sourceBuffer size];
    source.size = dest.size = MIN(sourceSize, size);
    source.start = dest.start = 0;
    rtn = [self copyFromBuffer:sourceBuffer
		source:source
		destination:dest];
    if ((rtn == YES) && (sourceSize < source.size)) {
	bzero((char *)data + sourceSize, source.size - sourceSize);
    }
    return rtn;
}

-(BOOL)copyFromBuffer:(IOBuffer *)sourceBuffer
       source:(IORange)srcRange
       destination:(IORange)dstRange
{
    int sourceSize, destSize;
    IOVirtualRange sourceAddrRange, destAddrRange;
    
    if ([self isWired] == NO || [sourceBuffer isWired] == NO)
	return NO;

    sourceSize = [sourceBuffer size] - srcRange.start;
    destSize = [self size] - dstRange.start;
    if ((srcRange.size > sourceSize) || (srcRange.size > destSize))
	return NO;
	
    if ([sourceBuffer getVirtualAddress:&sourceAddrRange
		      at:srcRange.start] == NO) {
	return NO;
    }
    if ([self getVirtualAddress:&destAddrRange
		      at:dstRange.start] == NO) {
	return NO;
    }
    copyData(sourceAddrRange.start, [sourceBuffer addressMap],
	     destAddrRange.start, map, srcRange.size);

    return YES;
}

-(IOAddressMap)addressMap
{
    return map;
}


-(BOOL)wireMemory
{
    if ([self isWired])
	return YES;
    
    if (vm_map_pageable(map, trunc_page((char *)data),
		             round_page((char *)data + size), FALSE)
	    == KERN_SUCCESS) {
	attributes |= IOBuf_Wired;
	return YES;
    }

    return NO;
}

-(BOOL)unwireMemory
{
    if ([self isWired] == NO)
	return YES;
    if (!(attributes & IOBuf_WiredStatic) &&
        (vm_map_pageable(map, trunc_page((char *)data),
	                      round_page((char *)data + size), TRUE)
	    == KERN_SUCCESS)) {
	attributes &= ~IOBuf_Wired;
	return YES;
    }
    return NO;
}

-(BOOL)getVirtualAddress:(IOVirtualRange *)virtualRangePtr
 at:(unsigned int)offset
{
    if (offset >= size)
	return NO;
    if (virtualRangePtr != NULL) {
	virtualRangePtr->start = (IOVirtualAddress)((char *)data + offset);
	virtualRangePtr->size = size - offset;
    }
    return YES;
}

-(BOOL)getPhysicalAddress:(IOPhysicalRange *)physicalRangePtr
 at:(unsigned int)offset
{
    IOPhysicalAddress paddr;
    char *vaddr;
    int cbytes = 0;
    IOPhysicalAddress nextContPage, nextPhysPage;
    char *nextVirtPage, *curVirtPage;
    int bytesLeftInPage, curByteCount;
    
    if ((offset >= size) || ![self isWired])
	return NO;
	
    vaddr = (char *)data + offset;
    paddr = (IOPhysicalAddress) pmap_resident_extract(
	vm_map_pmap((vm_map_t)map), vaddr);

    if (physicalRangePtr != NULL) {
	curByteCount = size - offset;
	curVirtPage = (char *)trunc_page(vaddr);
	nextContPage = (IOPhysicalAddress)trunc_page(paddr) + PAGE_SIZE;
	bytesLeftInPage = nextContPage - paddr;
	
	while (curByteCount > 0) {
	    if (bytesLeftInPage >= curByteCount ){
		    cbytes += curByteCount;
		    break;
	    } else {
		cbytes += bytesLeftInPage;

		nextPhysPage = (IOPhysicalAddress) pmap_resident_extract(
		    vm_map_pmap((vm_map_t)map),
		    (curVirtPage + PAGE_SIZE));

		if (nextPhysPage == nextContPage){
		    curByteCount -= bytesLeftInPage;
		    bytesLeftInPage = PAGE_SIZE;
		    curVirtPage += PAGE_SIZE;
		    nextContPage += PAGE_SIZE;				
		} else {
		    break;
		}
	    } 
	}
    }
    if (physicalRangePtr != NULL) {
	physicalRangePtr->start = paddr;
	physicalRangePtr->size = cbytes;
    }
    return YES;
}

-(IOBufferAttributes)attributes
{
    return attributes;
}

-(BOOL)isContiguous
{
    return ((attributes & IOBuf_Contiguous) ? YES : NO);
}

-(BOOL)isWired
{
    return ((attributes & IOBuf_Wired) ? YES : NO);
}

-(unsigned int)size
{
    return size;
}

-(void *)data
{
    return data;
}

-(IOAlignment)alignment
{
    return alignment;
}

-(IORange)range
{
    return userRange;
}


-(void)setRange:(IORange)newRange
{
    userRange = newRange;
}


+(BOOL)allocMemoryWithSize:(int)memSize
       attributes:(IOBufferAttributes)attr
       alignment:(IOAlignment)align
       allocedAddress:(IOVirtualAddress *)allocPtr
       dataAddress:(IOVirtualAddress *)dataPtr
       allocedSize:(int *)sizePtr
       newAttributes:(IOBufferAttributes *)newAttrPtr
       newMap:(IOAddressMap *)mapPtr
{
    IOVirtualAddress vaddr;
    int alignSize, newSize;
    
    alignSize = IOAlignmentToSize(align);
    newSize = memSize + 2 * alignSize;
    
    /* an optimization that relies on IOMalloc returning aligned pages. */
    if (newSize > PAGE_SIZE && memSize <= PAGE_SIZE)
	newSize = PAGE_SIZE;
    
    vaddr = (IOVirtualAddress)IOMalloc(newSize);
    if (vaddr == 0)
	return FALSE;

    *allocPtr = vaddr;
    if (newSize != memSize)
	*dataPtr = (vaddr + alignSize - 1) & ~(alignSize - 1);
    else
	*dataPtr = vaddr;
    *sizePtr = newSize;
    *newAttrPtr = IOBuf_Wired | IOBuf_WiredStatic | IOBuf_Contiguous;
    *mapPtr = (IOAddressMap)IOVmTaskSelf();
    return TRUE;
}


+(BOOL)freeMemory:(IOVirtualAddress)addr
       size:(int)memsize
       map:(IOAddressMap)memmap
       attributes:(IOBufferAttributes)attr
{
    IOFree((void *)addr, memsize);
    return TRUE;
}

@end

/*
 * Helper functions
 */
 
/*
 * Returns TRUE if the address meets the specified aligment requirement.
 */
static BOOL checkAlignmentFromVirtual(
    IOVirtualAddress	vaddr,
    IOAddressMap	map,
    int			size,
    IOAlignment	align
)
{
    IOPhysicalAddress paddr;
    
    paddr = (IOPhysicalAddress) pmap_resident_extract(
	vm_map_pmap((vm_map_t)map), vaddr);

    return checkAlignmentFromPhysical(paddr, size, align);
}

static BOOL checkAlignmentFromPhysical(
    IOPhysicalAddress	paddr,
    int			size,
    IOAlignment		align
)
{
    unsigned int mask;
    
    if (align > IOBufferAlignMax)
	return NO;

    mask = maskFromAlignment(align);
    if ((paddr & mask) || (size & mask))
	return NO;

    return YES;
}

static BOOL checkAlignmentFromSize(
    int			size,
    IOAlignment	align
)
{
    unsigned int mask;
    if (align > IOBufferAlignMax)
	return NO;
    mask = maskFromAlignment(align);
    if (size & mask)
	return NO;
    return YES;
}

static unsigned int
maskFromAlignment(
    IOAlignment		align
)
{
    unsigned int mask;
    
    for (mask = 0; align; align--) {
	mask = (mask << 1) | 1;
    }
    return mask;
}

static unsigned int
alignmentFromAddress(
    unsigned int	addr
)
{
    unsigned int alignment;
    
    for (alignment=0; alignment < PAGE_SHIFT; alignment++) {
	if (addr & 0x01)
	    return alignment;
	addr >>= 1;
    }
    return alignment;
}

static void
copyData(
    IOVirtualAddress src,
    IOAddressMap srcMap,
    IOVirtualAddress dst,
    IOAddressMap dstMap,
    unsigned int totalLength
)
{
    IOPhysicalAddress physSrc, physDst;
    int currentLength;
    int leftInSrc, leftInDst;
    const unsigned int pageMask = PAGE_SIZE - 1;

    while (totalLength) {
	physSrc = (IOPhysicalAddress) pmap_resident_extract(
	    vm_map_pmap((vm_map_t)srcMap), src);
	physDst = (IOPhysicalAddress) pmap_resident_extract(
	    vm_map_pmap((vm_map_t)dstMap), dst);
	leftInSrc = PAGE_SIZE - (physSrc & pageMask);
	leftInDst = PAGE_SIZE - (physDst & pageMask);
	currentLength = MIN(leftInSrc, leftInDst);
	currentLength = MIN(totalLength, currentLength);
	bcopy(pmap_phys_to_kern(physSrc),
	      pmap_phys_to_kern(physDst),
	      currentLength);
	totalLength -= currentLength;
	src += currentLength;
	dst += currentLength;
    }
}

#endif NOTYET


unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.