Plan 9 from Bell Labs’s /sys/src/pub/doc/beagle/igepv2/powervr/virtmem.c

Copyright © 2021 Plan 9 Foundation
Distributed under the MIT License.
Download the Plan 9 distribution.


/* -*- Mode: C; tab-width: 4; indent-tabs-mode: 't; c-basic-offset: 4 -*-
 *
 * Name         : $RCSfile: virtmem.c $
 *
 * Copyright    : 2001,2002 by Imagination Technologies Limited. 
 *                  All rights reserved.
 *                  No part of this software, either material or conceptual 
 *                  may be copied or distributed, transmitted, transcribed,
 *                  stored in a retrieval system or translated into any 
 *                  human or computer language in any form by any means,
 *                  electronic, mechanical, manual or other-wise, or 
 *                  disclosed to third parties without the express written
 *                  permission of:
 *                             Imagination Technologies Limited, 
 *                             HomePark Industrial Estate, 
 *                             Kings Langley, 
 *                             Hertfordshire,
 *                             WD4 8LZ, 
 *                             UK
 *
 * Description  : Defines functions providing virtually contiguous memory
 *                allocations under Linux.
 *
 * Version	 	: $Revision: 1.12 $
 *
 **************************************************************************/

#include <linux/version.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/wrapper.h>
#include <linux/slab.h>
#include "virtmem.h"
#include "mmap.h"
#include "debug.h"

static VIRT_ALLOC_REC VMallocHead;
static PVIRT_ALLOC_REC psVMallocHead = &VMallocHead;

/*
// virtual_allocate_reserve
//
// Purpose: Allocates virtually contiguous pages and reserves them
//
// Args: nPages - number of pages to reserve
//       bCached - cacheable pages?
//
// Returns: Page-aligned address of virtual allocation or zero on error.
*/
void* virtual_allocate_reserve(unsigned long nPages, unsigned long bCached)
{
	void* pkvMem;
	void* pkvPageAlignedMem = 0;
	unsigned long pkvCurrentPage;
	PVIRT_ALLOC_REC psLastRecord = psVMallocHead;
	PVIRT_ALLOC_REC psCurrentRecord = psVMallocHead->pNext;
	PVIRT_ALLOC_REC psNewRecord;

	/* Allocate virtually contiguous pages */
	if (bCached)
		pkvMem = __vmalloc(nPages*PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL);
	else
#if defined(GCC_IA32)
		pkvMem = __vmalloc(nPages*PAGE_SIZE, GFP_KERNEL,
						   PAGE_KERNEL_NOCACHE);
#elif defined(ARM)
	    pkvMem = __vmalloc(nPages*PAGE_SIZE, GFP_KERNEL,
							__pgprot(_L_PTE_DEFAULT | L_PTE_DIRTY | L_PTE_WRITE));
#else
#error "virtual_allocate_reserve - don't know how to vmalloc uncached"
#endif

	if (pkvMem)
	{
		/* Determine a page aligned pointer */
		pkvPageAlignedMem = (void *)(((unsigned long)pkvMem + PAGE_SIZE - 1) & PAGE_MASK);

		/* Reserve those pages to allow them to be re-mapped to user space */
		for	(
				pkvCurrentPage = (unsigned long)pkvPageAlignedMem;
				pkvCurrentPage < ((unsigned long)pkvPageAlignedMem + nPages*PAGE_SIZE);
				pkvCurrentPage += PAGE_SIZE
			)
		{
			mem_map_reserve(ConvertKVToPage(pkvCurrentPage));
		}

/* DEBUGGING START */	
		DPF("New vmalloc - pkvMem: 0x%08X, pkvPageAlignedMem: 0x%08X, nPages: 0x%08X\n", pkvMem, pkvPageAlignedMem, nPages);
/* DEBUGGING END */

		/* Register the area in mmap address space */
		pvr_mmap_register_area(pkvPageAlignedMem, nPages*PAGE_SIZE, PVR_MMAP_VIRTUAL, bCached);

		/* Create a new memory allocation record */
		psNewRecord = kmalloc(sizeof(VIRT_ALLOC_REC), GFP_KERNEL);

		if (psNewRecord)
		{
			/* Locate the last entry in the tracking list */
			while (psCurrentRecord)
			{
				psLastRecord = psCurrentRecord;
				psCurrentRecord = psCurrentRecord->pNext;
			}

			/* Record the allocation */
			psNewRecord->pkvMem = (unsigned long)pkvMem;
			psNewRecord->pkvPageAlignedMem = (unsigned long)pkvPageAlignedMem;
			psNewRecord->nBytes = nPages * PAGE_SIZE;

			/* Append the new record */
			psLastRecord->pNext = psNewRecord;
			psNewRecord->pNext = NULL;
		}
		else
		{
			DPF("virtmem.c - virtual_allocate_reserve: Error - Failed to allocate memory record.\n");
		}
	}

	return pkvPageAlignedMem;
}


/*
// virtual_deallocate_unreserve
//
// Purpose: Unreserves and deallocates pages allocated by virtual_allocate_reserve
//
// Args: pkvPageAlignedMem - Page-aligned address returned by virtual_allocate_reserve
//
// Returns: None.
*/
void virtual_deallocate_unreserve(void* pkvPageAlignedMem)
{
	PVIRT_ALLOC_REC psCurrentRecord = psVMallocHead->pNext;
	PVIRT_ALLOC_REC psLastRecord = psVMallocHead;
	void* pkvMem;
	unsigned long nBytes;
	unsigned long pkvCurrentPage;

	/* Locate the corresponding allocation entry */
	while (psCurrentRecord)
	{
		if (psCurrentRecord->pkvPageAlignedMem == (unsigned long)pkvPageAlignedMem)
			break;
		psLastRecord = psCurrentRecord;
		psCurrentRecord = psCurrentRecord->pNext;
	}

	if (psCurrentRecord)
	{
		/* Retrieve the size of the allocation */
		nBytes = psCurrentRecord->nBytes;

		/* Retrieve the original allocation pointer */
		pkvMem = (void*)(psCurrentRecord->pkvMem);

		/* Unlink the allocation record */
		psLastRecord->pNext = psCurrentRecord->pNext;

		/* Delete the allocation record */
		kfree(psCurrentRecord);

		/* Unreserve pages */
		for	(
				pkvCurrentPage = (unsigned long)pkvPageAlignedMem;
				pkvCurrentPage < ((unsigned long)pkvPageAlignedMem + nBytes);
				pkvCurrentPage += PAGE_SIZE
			)
		{
			mem_map_unreserve(ConvertKVToPage(pkvCurrentPage));
		}

		pvr_mmap_remove_registered_area(pkvPageAlignedMem);

/* DEBUGGING START */	
		DPF("Deallocating vmalloc - pkvMem: 0x%08X\n", pkvMem);
/* DEBUGGING END */

		/* De-allocate memory */
		if (pkvMem)
		{
			vfree(pkvMem);
		}
	}
	else
	{
		DPF("virtmem.c - kernel_deallocate_unreserve: Error - failed to find allocation record.\n");
	}
}


/*
// virtual_memory_cleanup - Frees any remaining memory allocations
*/
void virtual_memory_cleanup(void)
{
	PVIRT_ALLOC_REC psCurrentRecord;

	while (psVMallocHead && (psCurrentRecord = psVMallocHead->pNext))
	{
		virtual_deallocate_unreserve((void *)psCurrentRecord->pkvPageAlignedMem);
	}
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@plan9.bell-labs.com.