예제 #1
0
/*******************************************************************************
**
**  gckVGMMU_Destroy
**
**  Destroy a nAQMMU object.
**
**  INPUT:
**
**      gckVGMMU Mmu
**          Pointer to an gckVGMMU object.
**
**  OUTPUT:
**
**      Nothing.
*/
gceSTATUS gckVGMMU_Destroy(
    IN gckVGMMU Mmu
    )
{
    gcmkHEADER_ARG("Mmu=0x%x", Mmu);

    /* Verify the arguments. */
    gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);

    /* Free the page table. */
    gcmkVERIFY_OK(gckOS_FreeContiguous(Mmu->os,
                                  Mmu->pageTablePhysical,
                                  Mmu->pageTableLogical,
                                  Mmu->pageTableSize));

    /* Roll back. */
    gcmkVERIFY_OK(gckOS_DeleteMutex(Mmu->os, Mmu->mutex));

    /* Mark the gckVGMMU object as unknown. */
    Mmu->object.type = gcvOBJ_UNKNOWN;

    /* Free the gckVGMMU object. */
    gcmkVERIFY_OK(gckOS_Free(Mmu->os, Mmu));

    gcmkFOOTER_NO();
    /* Success. */
    return gcvSTATUS_OK;
}
/*******************************************************************************
**
**  gckKERNEL_QueryVideoMemory
**
**  Query the amount of video memory.
**
**  INPUT:
**
**      gckKERNEL Kernel
**          Pointer to an gckKERNEL object.
**
**  OUTPUT:
**
**      gcsHAL_INTERFACE * Interface
**          Pointer to an gcsHAL_INTERFACE structure that will be filled in with
**          the memory information.
*/
gceSTATUS
gckKERNEL_QueryVideoMemory(
    IN gckKERNEL Kernel,
    OUT gcsHAL_INTERFACE * Interface
    )
{
    gckGALDEVICE device;

    gcmkHEADER_ARG("Kernel=%p", Kernel);

    /* Verify the arguments. */
    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
    gcmkVERIFY_ARGUMENT(Interface != NULL);

    /* Extract the pointer to the gckGALDEVICE class. */
    device = (gckGALDEVICE) Kernel->context;

    /* Get internal memory size and physical address. */
    Interface->u.QueryVideoMemory.internalSize = device->internalSize;
    Interface->u.QueryVideoMemory.internalPhysical = device->internalPhysicalName;

    /* Get external memory size and physical address. */
    Interface->u.QueryVideoMemory.externalSize = device->externalSize;
    Interface->u.QueryVideoMemory.externalPhysical = device->externalPhysicalName;

    /* Get contiguous memory size and physical address. */
    Interface->u.QueryVideoMemory.contiguousSize = device->contiguousSize;
    Interface->u.QueryVideoMemory.contiguousPhysical = device->contiguousPhysicalName;

    /* Success. */
    gcmkFOOTER_NO();
    return gcvSTATUS_OK;
}
/*******************************************************************************
**  gckKERNEL_GetProcessDBCache
**
**  Get teh secure cache from a process database.
**
**  INPUT:
**
**      gckKERNEL Kernel
**          Pointer to a gckKERNEL object.
**
**      gctUINT32 ProcessID
**          Process ID used to identify the database.
**
**  OUTPUT:
**
**      gcskSECURE_CACHE_PTR * Cache
**          Pointer to a variable that receives the secure cache pointer.
*/
gceSTATUS
gckKERNEL_GetProcessDBCache(
    IN gckKERNEL Kernel,
    IN gctUINT32 ProcessID,
    OUT gcskSECURE_CACHE_PTR * Cache
    )
{
    gceSTATUS status;
    gcsDATABASE_PTR database;

    gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID);

    /* Verify the arguments. */
    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
    gcmkVERIFY_ARGUMENT(Cache != gcvNULL);

    /* Find the database. */
    gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));

    /* Return the pointer to the cache. */
    *Cache = &database->cache;

    /* Success. */
    gcmkFOOTER_ARG("*Cache=0x%x", *Cache);
    return gcvSTATUS_OK;

OnError:
    /* Return the status. */
    gcmkFOOTER();
    return status;
}
gceSTATUS
gckHEAP_ProfileEnd(
    IN gckHEAP Heap,
    IN gctCONST_STRING Title
    )
{
    gcmkHEADER_ARG("Heap=0x%x Title=0x%x", Heap, Title);

    /* Verify the arguments. */
    gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP);
    gcmkVERIFY_ARGUMENT(Title != gcvNULL);

    gcmkPRINT("");
    gcmkPRINT("=====[ HEAP - %s ]=====", Title);
    gcmkPRINT("Number of allocations           : %12u",   Heap->allocCount);
    gcmkPRINT("Number of bytes allocated       : %12llu", Heap->allocBytes);
    gcmkPRINT("Maximum allocation size         : %12llu", Heap->allocBytesMax);
    gcmkPRINT("Total number of bytes allocated : %12llu", Heap->allocBytesTotal);
    gcmkPRINT("Number of heaps                 : %12u",   Heap->heapCount);
    gcmkPRINT("Heap memory in bytes            : %12llu", Heap->heapMemory);
    gcmkPRINT("Maximum number of heaps         : %12u",   Heap->heapCountMax);
    gcmkPRINT("Maximum heap memory in bytes    : %12llu", Heap->heapMemoryMax);
    gcmkPRINT("==============================================");

    /* Success. */
    gcmkFOOTER_NO();
    return gcvSTATUS_OK;
}
예제 #5
0
/*******************************************************************************
**
**	gckCOMMAND_Stop
**
**	Stop the command queue.
**
**	INPUT:
**
**		gckCOMMAND Command
**			Pointer to an gckCOMMAND object to stop.
**
**	OUTPUT:
**
**		Nothing.
*/
gceSTATUS
gckCOMMAND_Stop(
	IN gckCOMMAND Command
	)
{
    gckHARDWARE hardware;
	gceSTATUS status;
	gctUINT32 idle;

	gcmkHEADER_ARG("Command=0x%x", Command);

	/* Verify the arguments. */
	gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);

	if (!Command->running)
	{
		/* Command queue is not running. */
		gcmkFOOTER_NO();
		return gcvSTATUS_OK;
	}

    /* Extract the gckHARDWARE object. */
    hardware = Command->kernel->hardware;
    gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);

    /* Replace last WAIT with END. */
    gcmkONERROR(
		gckHARDWARE_End(hardware,
						Command->wait,
						&Command->waitSize));

	/* Wait for idle. */
	gcmkONERROR(
		gckHARDWARE_GetIdle(hardware, gcvTRUE, &idle));

	/* Command queue is no longer running. */
	Command->running = gcvFALSE;

	/* Success. */
	gcmkFOOTER_NO();
	return gcvSTATUS_OK;

OnError:
	/* Return the status. */
	gcmkFOOTER();
	return status;
}
/*******************************************************************************
**
**  gckVIDMEM_DestroyVirtual
**
**  Destroy an gcuVIDMEM_NODE union for virtual memory.
**
**  INPUT:
**
**      gcuVIDMEM_NODE_PTR Node
**          Pointer to a gcuVIDMEM_NODE union.
**
**  OUTPUT:
**
**      Nothing.
*/
gceSTATUS
gckVIDMEM_DestroyVirtual(
    IN gcuVIDMEM_NODE_PTR Node
    )
{
    gckOS os;

    gcmkHEADER_ARG("Node=0x%x", Node);

    /* Verify the arguments. */
    gcmkVERIFY_OBJECT(Node->Virtual.kernel, gcvOBJ_KERNEL);

    /* Extact the gckOS object pointer. */
    os = Node->Virtual.kernel->os;
    gcmkVERIFY_OBJECT(os, gcvOBJ_OS);

#ifdef __QNXNTO__
    /* Unregister. */
    gcmkVERIFY_OK(
            gckMMU_RemoveNode(Node->Virtual.kernel->mmu, Node));

    /* Free virtual memory. */
    gcmkVERIFY_OK(
            gckOS_FreePagedMemory(os,
                                  Node->Virtual.physical,
                                  Node->Virtual.bytes));
#endif

    /* Delete the mutex. */
    gcmkVERIFY_OK(gckOS_DeleteMutex(os, Node->Virtual.mutex));

    if (Node->Virtual.pageTable != gcvNULL)
    {
        /* Free the pages. */
        gcmkVERIFY_OK(gckMMU_FreePages(Node->Virtual.kernel->mmu,
                                       Node->Virtual.pageTable,
                                       Node->Virtual.pageCount));
    }

    /* Delete the gcuVIDMEM_NODE union. */
    gcmkVERIFY_OK(gckOS_Free(os, Node));

    /* Success. */
    gcmkFOOTER_NO();
    return gcvSTATUS_OK;
}
gceSTATUS
gckDVFS_Construct(
    IN gckHARDWARE Hardware,
    OUT gckDVFS * Dvfs
    )
{
    gceSTATUS status = gcvSTATUS_OK;
    gctPOINTER pointer;
    gckDVFS dvfs = gcvNULL;
    gckOS os = Hardware->os;

    gcmkHEADER_ARG("Hardware=0x%X", Hardware);

    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
    gcmkVERIFY_ARGUMENT(Dvfs != gcvNULL);

    /* Allocate a gckDVFS manager. */
    gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(struct _gckDVFS), &pointer));

    gckOS_ZeroMemory(pointer, gcmSIZEOF(struct _gckDVFS));

    dvfs = pointer;

    /* Initialization. */
    dvfs->hardware = Hardware;
    dvfs->pollingTime = gcdDVFS_POLLING_TIME;
    dvfs->os = Hardware->os;
    dvfs->currentScale = 64;

    /* Create a polling timer. */
    gcmkONERROR(gckOS_CreateTimer(os, _TimerFunction, pointer, &dvfs->timer));

    /* Initialize frequency and voltage adjustment helper. */
    gcmkONERROR(gckOS_PrepareGPUFrequency(os, Hardware->core));

    /* Return result. */
    *Dvfs = dvfs;

    gcmkFOOTER_NO();
    return gcvSTATUS_OK;

OnError:
    /* Roll back. */
    if (dvfs)
    {
        if (dvfs->timer)
        {
            gcmkVERIFY_OK(gckOS_DestroyTimer(os, dvfs->timer));
        }

        gcmkOS_SAFE_FREE(os, dvfs);
    }

    gcmkFOOTER();
    return status;
}
/*******************************************************************************
**
**  gckVIDMEM_Allocate
**
**  Allocate rectangular memory from the gckVIDMEM object.
**
**  INPUT:
**
**      gckVIDMEM Memory
**          Pointer to an gckVIDMEM object.
**
**      gctUINT Width
**          Width of rectangle to allocate.  Make sure the width is properly
**          aligned.
**
**      gctUINT Height
**          Height of rectangle to allocate.  Make sure the height is properly
**          aligned.
**
**      gctUINT Depth
**          Depth of rectangle to allocate.  This equals to the number of
**          rectangles to allocate contiguously (i.e., for cubic maps and volume
**          textures).
**
**      gctUINT BytesPerPixel
**          Number of bytes per pixel.
**
**      gctUINT32 Alignment
**          Byte alignment for allocation.
**
**      gceSURF_TYPE Type
**          Type of surface to allocate (use by bank optimization).
**
**  OUTPUT:
**
**      gcuVIDMEM_NODE_PTR * Node
**          Pointer to a variable that will hold the allocated memory node.
*/
gceSTATUS
gckVIDMEM_Allocate(
    IN gckVIDMEM Memory,
    IN gctUINT Width,
    IN gctUINT Height,
    IN gctUINT Depth,
    IN gctUINT BytesPerPixel,
    IN gctUINT32 Alignment,
    IN gceSURF_TYPE Type,
#ifdef __QNXNTO__
    IN gctHANDLE Handle,
#endif
    OUT gcuVIDMEM_NODE_PTR * Node
    )
{
    gctSIZE_T bytes;
    gceSTATUS status;

    gcmkHEADER_ARG("Memory=0x%x Width=%u Height=%u Depth=%u BytesPerPixel=%u "
                   "Alignment=%u Type=%d",
                   Memory, Width, Height, Depth, BytesPerPixel, Alignment,
                   Type);

    /* Verify the arguments. */
    gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM);
    gcmkVERIFY_ARGUMENT(Width > 0);
    gcmkVERIFY_ARGUMENT(Height > 0);
    gcmkVERIFY_ARGUMENT(Depth > 0);
    gcmkVERIFY_ARGUMENT(BytesPerPixel > 0);
    gcmkVERIFY_ARGUMENT(Node != gcvNULL);
#ifdef __QNXNTO__
    gcmkVERIFY_ARGUMENT(Handle != gcvNULL);
#endif

    /* Compute linear size. */
    bytes = Width * Height * Depth * BytesPerPixel;

    /* Allocate through linear function. */
#ifdef __QNXNTO__
    gcmkONERROR(
        gckVIDMEM_AllocateLinear(Memory, bytes, Alignment, Type, Handle, Node));
#else
    gcmkONERROR(
        gckVIDMEM_AllocateLinear(Memory, bytes, Alignment, Type, Node));
#endif

    /* Success. */
    gcmkFOOTER_ARG("*Node=0x%x", *Node);
    return gcvSTATUS_OK;

OnError:
    /* Return the status. */
    gcmkFOOTER();
    return status;
}
/*******************************************************************************
**
**  gckKERNEL_Destroy
**
**  Destroy an gckKERNEL object.
**
**  INPUT:
**
**      gckKERNEL Kernel
**          Pointer to an gckKERNEL object to destroy.
**
**  OUTPUT:
**
**      Nothing.
*/
gceSTATUS gckVGKERNEL_Destroy(
    IN gckVGKERNEL Kernel
    )
{
    gceSTATUS status;

    gcmkHEADER_ARG("Kernel=0x%x", Kernel);

    /* Verify the arguments. */
    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);

    do
    {
        /* Destroy the gckVGMMU object. */
        if (Kernel->mmu != gcvNULL)
        {
            gcmkERR_BREAK(gckVGMMU_Destroy(Kernel->mmu));
            Kernel->mmu = gcvNULL;
        }

        /* Destroy the gckVGCOMMAND object. */
        if (Kernel->command != gcvNULL)
        {
            gcmkERR_BREAK(gckVGCOMMAND_Destroy(Kernel->command));
            Kernel->command = gcvNULL;
        }

        /* Destroy the gckVGINTERRUPT object. */
        if (Kernel->interrupt != gcvNULL)
        {
            gcmkERR_BREAK(gckVGINTERRUPT_Destroy(Kernel->interrupt));
            Kernel->interrupt = gcvNULL;
        }

        /* Destroy the gckVGHARDWARE object. */
        if (Kernel->hardware != gcvNULL)
        {
            gcmkERR_BREAK(gckVGHARDWARE_Destroy(Kernel->hardware));
            Kernel->hardware = gcvNULL;
        }

        /* Mark the gckKERNEL object as unknown. */
        Kernel->object.type = gcvOBJ_UNKNOWN;

        /* Free the gckKERNEL object. */
        gcmkERR_BREAK(gckOS_Free(Kernel->os, Kernel));
    }
    while (gcvFALSE);

    gcmkFOOTER();

    /* Return status. */
    return status;
}
gceSTATUS
gckKERNEL_AttachProcess(
	IN gckKERNEL Kernel,
	IN gctBOOL Attach
	)
{
	gceSTATUS status;
    gctINT32 old;

	gcmkHEADER_ARG("Kernel=0x%x Attach=%d", Kernel, Attach);

	/* Verify the arguments. */
	gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);

	if (Attach)
	{
        /* Increment the number of clients attached. */
        gcmkONERROR(
            gckOS_AtomIncrement(Kernel->os, Kernel->atomClients, &old));

        if (old == 0)
        {
            /* gcmkONERROR(gckHARDWARE_SetPowerManagementState(Kernel->hardware, gcvPOWER_ON)); */
        }
    }

	else
	{
		/* Decrement the number of clients attached. */
        gcmkONERROR(
            gckOS_AtomDecrement(Kernel->os, Kernel->atomClients, &old));

        if (old == 1)
		{
            gcmkONERROR(gckHARDWARE_SetPowerManagementState(Kernel->hardware, gcvPOWER_OFF));

            /* Flush the debug cache. */
            gcmkPRINT("$$FLUSH$$");
		}
	}

	/* Success. */
	gcmkFOOTER_NO();
	return gcvSTATUS_OK;

OnError:
	/* Return the status. */
	gcmkFOOTER();
	return status;
}
/*******************************************************************************
**
**  gckKERNEL_GetVideoMemoryPool
**
**  Get the gckVIDMEM object belonging to the specified pool.
**
**  INPUT:
**
**      gckKERNEL Kernel
**          Pointer to an gckKERNEL object.
**
**      gcePOOL Pool
**          Pool to query gckVIDMEM object for.
**
**  OUTPUT:
**
**      gckVIDMEM * VideoMemory
**          Pointer to a variable that will hold the pointer to the gckVIDMEM
**          object belonging to the requested pool.
*/
gceSTATUS
gckKERNEL_GetVideoMemoryPool(
    IN gckKERNEL Kernel,
    IN gcePOOL Pool,
    OUT gckVIDMEM * VideoMemory
    )
{
    gckGALDEVICE device;
    gckVIDMEM videoMemory;

    gcmkHEADER_ARG("Kernel=%p Pool=%d", Kernel, Pool);

    /* Verify the arguments. */
    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
    gcmkVERIFY_ARGUMENT(VideoMemory != NULL);

    /* Extract the pointer to the gckGALDEVICE class. */
    device = (gckGALDEVICE) Kernel->context;

    /* Dispatch on pool. */
    switch (Pool)
    {
    case gcvPOOL_LOCAL_INTERNAL:
        /* Internal memory. */
        videoMemory = device->internalVidMem;
        break;

    case gcvPOOL_LOCAL_EXTERNAL:
        /* External memory. */
        videoMemory = device->externalVidMem;
        break;

    case gcvPOOL_SYSTEM:
        /* System memory. */
        videoMemory = device->contiguousVidMem;
        break;

    default:
        /* Unknown pool. */
        videoMemory = NULL;
    }

    /* Return pointer to the gckVIDMEM object. */
    *VideoMemory = videoMemory;

    /* Return status. */
    gcmkFOOTER_ARG("*VideoMemory=%p", *VideoMemory);
    return (videoMemory == NULL) ? gcvSTATUS_OUT_OF_MEMORY : gcvSTATUS_OK;
}
예제 #12
0
/*******************************************************************************
**
**  gckVIDMEM_Destroy
**
**  Destroy an gckVIDMEM object.
**
**  INPUT:
**
**      gckVIDMEM Memory
**          Pointer to an gckVIDMEM object to destroy.
**
**  OUTPUT:
**
**      Nothing.
*/
gceSTATUS
gckVIDMEM_Destroy(
    IN gckVIDMEM Memory
    )
{
    gcuVIDMEM_NODE_PTR node, next;
    gctINT i;

    gcmkHEADER_ARG("Memory=0x%x", Memory);

    /* Verify the arguments. */
    gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM);

    /* Walk all sentinels. */
    for (i = 0; i < gcmCOUNTOF(Memory->sentinel); ++i)
    {
        /* Bail out of the heap is not used. */
        if (Memory->sentinel[i].VidMem.next == gcvNULL)
        {
            break;
        }

        /* Walk all the nodes until we reach the sentinel. */
        for (node = Memory->sentinel[i].VidMem.next;
             node->VidMem.bytes != 0;
             node = next)
        {
            /* Save pointer to the next node. */
            next = node->VidMem.next;

            /* Free the node. */
            gcmkVERIFY_OK(gckOS_Free(Memory->os, node));
        }
    }

    /* Free the mutex. */
    gcmkVERIFY_OK(gckOS_DeleteMutex(Memory->os, Memory->mutex));

    /* Mark the object as unknown. */
    Memory->object.type = gcvOBJ_UNKNOWN;

    /* Free the gckVIDMEM object. */
    gcmkVERIFY_OK(gckOS_Free(Memory->os, Memory));

    /* Success. */
    gcmkFOOTER_NO();
    return gcvSTATUS_OK;
}
gceSTATUS
gckKERNEL_QuerySettings(
	IN gckKERNEL Kernel,
	OUT gcsKERNEL_SETTINGS * Settings
	)
{
    gcmkHEADER_ARG("Kernel=%p", Kernel);

	/* Verify the arguments. */
	gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
	gcmkVERIFY_ARGUMENT(Settings != gcvNULL);

	/* Success. */
    gcmkFOOTER_NO();
	return gcvSTATUS_OK;
}
예제 #14
0
/*******************************************************************************
**
**	gckCOMMAND_Destroy
**
**	Destroy an gckCOMMAND object.
**
**	INPUT:
**
**		gckCOMMAND Command
**			Pointer to an gckCOMMAND object to destroy.
**
**	OUTPUT:
**
**		Nothing.
*/
gceSTATUS
gckCOMMAND_Destroy(
	IN gckCOMMAND Command
	)
{
	gctINT i;

	gcmkHEADER_ARG("Command=0x%x", Command);

	/* Verify the arguments. */
	gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);

	/* Stop the command queue. */
	gcmkVERIFY_OK(gckCOMMAND_Stop(Command));

	for (i = 0; i < gcdCOMMAND_QUEUES; ++i)
	{
		gcmkASSERT(Command->queues[i].signal != gcvNULL);
		gcmkVERIFY_OK(
			gckOS_DestroySignal(Command->os, Command->queues[i].signal));

		gcmkASSERT(Command->queues[i].logical != gcvNULL);
		gcmkVERIFY_OK(
			gckOS_FreeNonPagedMemory(Command->os,
									 Command->pageSize,
									 Command->queues[i].physical,
									 Command->queues[i].logical));
	}

    /* Delete the context switching mutex. */
    gcmkVERIFY_OK(gckOS_DeleteMutex(Command->os, Command->mutexContext));

    /* Delete the command queue mutex. */
    gcmkVERIFY_OK(gckOS_DeleteMutex(Command->os, Command->mutexQueue));

	/* Mark object as unknown. */
	Command->object.type = gcvOBJ_UNKNOWN;

	/* Free the gckCOMMAND object. */
	gcmkVERIFY_OK(gckOS_Free(Command->os, Command));

	/* Success. */
	gcmkFOOTER_NO();
	return gcvSTATUS_OK;
}
/*******************************************************************************
**
**	gckKERNEL_QueryVideoMemory
**
**	Query the amount of video memory.
**
**	INPUT:
**
**		gckKERNEL Kernel
**			Pointer to an gckKERNEL object.
**
**	OUTPUT:
**
**		gcsHAL_INTERFACE * Interface
**			Pointer to an gcsHAL_INTERFACE structure that will be filled in with
**			the memory information.
*/
gceSTATUS gckKERNEL_QueryVideoMemory(
	IN gckKERNEL Kernel,
	OUT gcsHAL_INTERFACE * Interface
	)
{
	GCHAL * gchal;

    gcmkHEADER_ARG("Kernel=%p", Kernel);

	gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_KERNEL,
			   "[ENTER] gckKERNEL_QueryVideoMemory");

	/* Verify the arguments. */
	gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
	gcmkVERIFY_ARGUMENT(Interface != gcvNULL);

	/* Extract the pointer to the CExtension class. */
	gchal = (GCHAL *) Kernel->context;

	/* Get internal memory size and physical address. */
	Interface->u.QueryVideoMemory.internalSize     =
		gchal->GetInternalSize();
	Interface->u.QueryVideoMemory.internalPhysical =
		gchal->GetInternalPhysical();

	/* Get external memory size and physical address. */
	Interface->u.QueryVideoMemory.externalSize     =
		gchal->GetExternalSize();
	Interface->u.QueryVideoMemory.externalPhysical =
		gchal->GetExternalPhysical();

	/* Get contiguous memory size and physical address. */
	Interface->u.QueryVideoMemory.contiguousSize     =
		gchal->GetContiguousSize();
	Interface->u.QueryVideoMemory.contiguousPhysical =
		gchal->GetContiguousPhysical();

	gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_KERNEL,
			   "[LEAVE] gckKERNEL_QueryVideoMemory(%u)",
			   gcvSTATUS_OK);

	/* Success. */
    gcmkFOOTER_NO();
	return gcvSTATUS_OK;
}
/*******************************************************************************
**
**  gckHEAP_Free
**
**  Free allocated memory from the heap.
**
**  INPUT:
**
**      gckHEAP Heap
**          Pointer to a gckHEAP object.
**
**      IN gctPOINTER Memory
**          Pointer to memory to free.
**
**  OUTPUT:
**
**      NOTHING.
*/
gceSTATUS
gckHEAP_Free(
    IN gckHEAP Heap,
    IN gctPOINTER Memory
    )
{
    gcskNODE_PTR node;
    gceSTATUS status;

    gcmkHEADER_ARG("Heap=0x%x Memory=0x%x", Heap, Memory);

    /* Verify the arguments. */
    gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP);
    gcmkVERIFY_ARGUMENT(Memory != gcvNULL);

    /* Acquire the mutex. */
    gcmkONERROR(
        gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE));

    /* Pointer to structure. */
    node = (gcskNODE_PTR) Memory - 1;

    /* Mark the node as freed. */
    node->next = gcvNULL;

#if VIVANTE_PROFILER || gcmIS_DEBUG(gcdDEBUG_CODE)
    /* Update profile counters. */
    Heap->allocBytes -= node->bytes;
#endif

    /* Release the mutex. */
    gcmkVERIFY_OK(
        gckOS_ReleaseMutex(Heap->os, Heap->mutex));

    /* Success. */
    gcmkFOOTER_NO();
    return gcvSTATUS_OK;

OnError:
    /* Return the status. */
    gcmkFOOTER();
    return status;
}
예제 #17
0
/*******************************************************************************
**
**	gckCOMMAND_Release
**
**	Release a previously reserved command queue.  The command FIFO mutex will be
**  released.
**
**	INPUT:
**
**		gckCOMMAND Command
**			Pointer to an gckCOMMAND object.
**
**	OUTPUT:
**
**		Nothing.
*/
gceSTATUS
gckCOMMAND_Release(
    IN gckCOMMAND Command
    )
{
	gceSTATUS status;

	gcmkHEADER_ARG("Command=0x%x", Command);

    /* Verify the arguments. */
    gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);

    /* Release the command queue mutex. */
    status = gckOS_ReleaseMutex(Command->os, Command->mutexQueue);

    /* Return the status. */
    gcmkFOOTER();
    return status;
}
/*******************************************************************************
**
**  gckKERNEL_QueryCommandBuffer
**
**  Query command buffer attributes.
**
**  INPUT:
**
**      gckKERNEL Kernel
**          Pointer to an gckVGHARDWARE object.
**
**  OUTPUT:
**
**      gcsCOMMAND_BUFFER_INFO_PTR Information
**          Pointer to the information structure to receive buffer attributes.
*/
gceSTATUS
gckKERNEL_QueryCommandBuffer(
    IN gckKERNEL Kernel,
    OUT gcsCOMMAND_BUFFER_INFO_PTR Information
    )
{
    gceSTATUS status;

    gcmkHEADER_ARG("Kernel=0x%x *Pool=0x%x",
                   Kernel, Information);
    /* Verify the arguments. */
    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);

    /* Get the information. */
    status = gckVGCOMMAND_QueryCommandBuffer(Kernel->vg->command, Information);

    gcmkFOOTER();
    /* Return status. */
    return status;
}
예제 #19
0
gceSTATUS
gckVGMMU_SetPage(
    IN gckVGMMU Mmu,
    IN gctUINT32 PageAddress,
    IN gctUINT32 *PageEntry
    )
{
    gcmkHEADER_ARG("Mmu=0x%x", Mmu);

    /* Verify the arguments. */
    gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
    gcmkVERIFY_ARGUMENT(PageEntry != gcvNULL);
    gcmkVERIFY_ARGUMENT(!(PageAddress & 0xFFF));

    *PageEntry = PageAddress;

    /* Success. */
    gcmkFOOTER_NO();
    return gcvSTATUS_OK;
}
/*******************************************************************************
**
**	gckKERNEL_Destroy
**
**	Destroy an gckKERNEL object.
**
**	INPUT:
**
**		gckKERNEL Kernel
**			Pointer to an gckKERNEL object to destroy.
**
**	OUTPUT:
**
**		Nothing.
*/
gceSTATUS
gckKERNEL_Destroy(
	IN gckKERNEL Kernel
	)
{
	gcmkHEADER_ARG("Kernel=0x%x", Kernel);

	/* Verify the arguments. */
	gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);



	/* Destroy the gckMMU object. */
	gcmkVERIFY_OK(gckMMU_Destroy(Kernel->mmu));

	/* Destroy the gckEVENT object. */
	gcmkVERIFY_OK(gckEVENT_Destroy(Kernel->event));

	/* Destroy the gckCOMMNAND object. */
	gcmkVERIFY_OK(gckCOMMAND_Destroy(Kernel->command));

	/* Destroy the gckHARDWARE object. */
	gcmkVERIFY_OK(gckHARDWARE_Destroy(Kernel->hardware));

    /* Detsroy the client atom. */
    gcmkVERIFY_OK(gckOS_AtomDestroy(Kernel->os, Kernel->atomClients));

	/* Mark the gckKERNEL object as unknown. */
	Kernel->object.type = gcvOBJ_UNKNOWN;

#if MRVL_LOW_POWER_MODE_DEBUG
    gcmkVERIFY_OK(
		gckOS_Free(Kernel->os, Kernel->kernelMSG));
#endif
	/* Free the gckKERNEL object. */
	gcmkVERIFY_OK(gckOS_Free(Kernel->os, Kernel));

	/* Success. */
	gcmkFOOTER_NO();
	return gcvSTATUS_OK;
}
/*******************************************************************************
**
**	gckKERNEL_Notify
**
**	This function iscalled by clients to notify the gckKERNEL object of an event.
**
**	INPUT:
**
**		gckKERNEL Kernel
**			Pointer to an gckKERNEL object.
**
**		gceNOTIFY Notification
**			Notification event.
**
**		gctBOOL Data
**			Optional data for notification.
**
**	OUTPUT:
**
**		Nothing.
*/
gceSTATUS gckKERNEL_Notify(
    IN gckKERNEL Kernel,
    IN gceNOTIFY Notification,
	IN gctBOOL Data
    )
{
    gceSTATUS status;

    gcmkHEADER_ARG("Kernel=%p Notification=%d Data=%d",
                   Kernel, Notification, Data);

    /* Verify the arguments. */
    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);

    /* Dispatch on notifcation. */
    switch (Notification)
    {
    case gcvNOTIFY_INTERRUPT:
        /* Process interrupt. */
        status = gckHARDWARE_Interrupt(Kernel->hardware, Data);
		break;

#ifdef EMULATOR
	case gcvNOTIFY_COMMAND_QUEUE:
		// Unfreeze C-Model.
		((GCHAL*) Kernel->context)->UnFreeze();
		status = gcvSTATUS_OK;
		break;
#endif

    default:
        /* Success. */
        status = gcvSTATUS_OK;
        break;
    }

    /* Return the status. */
    gcmkFOOTER();
    return status;
}
예제 #22
0
/*******************************************************************************
**
**  gckVGMMU_FreePages
**
**  Free pages inside the page table.
**
**  INPUT:
**
**      gckVGMMU Mmu
**          Pointer to an gckVGMMU object.
**
**      gctPOINTER PageTable
**          Base address of the page table to free.
**
**      gctSIZE_T PageCount
**          Number of pages to free.
**
**  OUTPUT:
**
**      Nothing.
*/
gceSTATUS gckVGMMU_FreePages(
    IN gckVGMMU Mmu,
    IN gctPOINTER PageTable,
    IN gctSIZE_T PageCount
    )
{
    gctUINT32 * table;

    gcmkHEADER_ARG("Mmu=0x%x PageTable=0x%x PageCount=0x%x",
        Mmu, PageTable, PageCount);

    /* Verify the arguments. */
    gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
    gcmkVERIFY_ARGUMENT(PageTable != gcvNULL);
    gcmkVERIFY_ARGUMENT(PageCount > 0);

    gcmkTRACE_ZONE(
        gcvLEVEL_INFO, gcvZONE_MMU,
        "%s(%d): freeing %u pages at index %u @ %p.\n",
        __FUNCTION__, __LINE__,
        PageCount,
        ((gctUINT32 *) PageTable - (gctUINT32 *) Mmu->pageTableLogical),
        PageTable
        );

    /* Convert pointer. */
    table = (gctUINT32 *) PageTable;

    /* Mark the page table entries as available. */
    while (PageCount-- > 0)
    {
        *table++ = (gctUINT32)~0;
    }

    gcmkFOOTER_NO();
    /* Success. */
    return gcvSTATUS_OK;
}
gceSTATUS
gckKERNEL_QuerySettings(
    IN gckKERNEL Kernel,
    OUT gcsKERNEL_SETTINGS * Settings
    )
{
    gckGALDEVICE device;

    gcmkHEADER_ARG("Kernel=%p", Kernel);

    /* Verify the arguments. */
    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
    gcmkVERIFY_ARGUMENT(Settings != gcvNULL);

    /* Extract the pointer to the gckGALDEVICE class. */
    device = (gckGALDEVICE) Kernel->context;

    /* Fill in signal. */
    Settings->signal = device->signal;

    /* Success. */
    gcmkFOOTER_ARG("Settings->signal=%d", Settings->signal);
    return gcvSTATUS_OK;
}
/*******************************************************************************
**
**  gckKERNEL_Notify
**
**  This function iscalled by clients to notify the gckKERNRL object of an event.
**
**  INPUT:
**
**      gckKERNEL Kernel
**          Pointer to an gckKERNEL object.
**
**      gceNOTIFY Notification
**          Notification event.
**
**  OUTPUT:
**
**      Nothing.
*/
gceSTATUS
gckKERNEL_Notify(
    IN gckKERNEL Kernel,
    IN gceNOTIFY Notification,
    IN gctBOOL Data
    )
{
    gceSTATUS status;

    gcmkHEADER_ARG("Kernel=%p Notification=%d Data=%d",
                   Kernel, Notification, Data);

    /* Verify the arguments. */
    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);

    /* Dispatch on notifcation. */
    switch (Notification)
    {
    case gcvNOTIFY_INTERRUPT:
        /* Process the interrupt. */
#if COMMAND_PROCESSOR_VERSION > 1
        status = gckINTERRUPT_Notify(Kernel->interrupt, Data);
#else
        status = gckHARDWARE_Interrupt(Kernel->hardware, Data);
#endif
        break;

    default:
        status = gcvSTATUS_OK;
        break;
    }

    /* Success. */
    gcmkFOOTER();
    return status;
}
/*******************************************************************************
**  gckKERNEL_FindProcessDB
**
**  Find a record from a process database.
**
**  INPUT:
**
**      gckKERNEL Kernel
**          Pointer to a gckKERNEL object.
**
**      gctUINT32 ProcessID
**          Process ID used to identify the database.
**
**      gceDATABASE_TYPE TYPE
**          Type of the record to remove.
**
**      gctPOINTER Pointer
**          Data of the record to remove.
**
**  OUTPUT:
**
**      gcsDATABASE_RECORD_PTR Record
**          Copy of record.
*/
gceSTATUS
gckKERNEL_FindProcessDB(
    IN gckKERNEL Kernel,
    IN gctUINT32 ProcessID,
    IN gctUINT32 ThreadID,
    IN gceDATABASE_TYPE Type,
    IN gctPOINTER Pointer,
    OUT gcsDATABASE_RECORD_PTR Record
    )
{
    gceSTATUS status;
    gcsDATABASE_PTR database;

    gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Pointer=0x%x",
                   Kernel, ProcessID, ThreadID, Type, Pointer);

    /* Verify the arguments. */
    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
    gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);

    /* Find the database. */
    gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));

    /* Find the record. */
    gcmkONERROR(
        gckKERNEL_FindRecord(Kernel, database, Type, Pointer, Record));

    /* Success. */
    gcmkFOOTER_NO();
    return gcvSTATUS_OK;

OnError:
    /* Return the status. */
    gcmkFOOTER();
    return status;
}
gceSTATUS
gckHEAP_ProfileStart(
    IN gckHEAP Heap
    )
{
    gcmkHEADER_ARG("Heap=0x%x", Heap);

    /* Verify the arguments. */
    gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP);

    /* Zero the counters. */
    Heap->allocCount      = 0;
    Heap->allocBytes      = 0;
    Heap->allocBytesMax   = 0;
    Heap->allocBytesTotal = 0;
    Heap->heapCount       = 0;
    Heap->heapCountMax    = 0;
    Heap->heapMemory      = 0;
    Heap->heapMemoryMax   = 0;

    /* Success. */
    gcmkFOOTER_NO();
    return gcvSTATUS_OK;
}
예제 #27
0
/*******************************************************************************
**
**  gckVGMMU_AllocatePages
**
**  Allocate pages inside the page table.
**
**  INPUT:
**
**      gckVGMMU Mmu
**          Pointer to an gckVGMMU object.
**
**      gctSIZE_T PageCount
**          Number of pages to allocate.
**
**  OUTPUT:
**
**      gctPOINTER * PageTable
**          Pointer to a variable that receives the base address of the page
**          table.
**
**      gctUINT32 * Address
**          Pointer to a variable that receives the hardware specific address.
*/
gceSTATUS gckVGMMU_AllocatePages(
    IN gckVGMMU Mmu,
    IN gctSIZE_T PageCount,
    OUT gctPOINTER * PageTable,
    OUT gctUINT32 * Address
    )
{
    gceSTATUS status;
    gctUINT32 tail, index, i;
    gctUINT32 * table;
    gctBOOL allocated = gcvFALSE;

    gcmkHEADER_ARG("Mmu=0x%x PageCount=0x%x PageTable=0x%x Address=0x%x",
        Mmu, PageCount, PageTable, Address);

    /* Verify the arguments. */
    gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
    gcmkVERIFY_ARGUMENT(PageCount > 0);
    gcmkVERIFY_ARGUMENT(PageTable != gcvNULL);
    gcmkVERIFY_ARGUMENT(Address != gcvNULL);

    gcmkTRACE_ZONE(
        gcvLEVEL_INFO, gcvZONE_MMU,
        "%s(%d): %u pages.\n",
        __FUNCTION__, __LINE__,
        PageCount
        );

    if (PageCount > Mmu->entryCount)
    {
        gcmkTRACE_ZONE(
            gcvLEVEL_ERROR, gcvZONE_MMU,
            "%s(%d): page table too small for %u pages.\n",
            __FUNCTION__, __LINE__,
            PageCount
            );

        gcmkFOOTER_NO();
        /* Not enough pages avaiable. */
        return gcvSTATUS_OUT_OF_RESOURCES;
    }

    /* Grab the mutex. */
    status = gckOS_AcquireMutex(Mmu->os, Mmu->mutex, gcvINFINITE);

    if (status < 0)
    {
        gcmkTRACE_ZONE(
            gcvLEVEL_ERROR, gcvZONE_MMU,
            "%s(%d): could not acquire mutex.\n"
            ,__FUNCTION__, __LINE__
            );

        gcmkFOOTER();
        /* Error. */
        return status;
    }

    /* Compute the tail for this allocation. */
    tail = Mmu->entryCount - PageCount;

    /* Walk all entries until we find enough slots. */
    for (index = Mmu->entry; index <= tail;)
    {
        /* Access page table. */
        table = (gctUINT32 *) Mmu->pageTableLogical + index;

        /* See if all slots are available. */
        for (i = 0; i < PageCount; i++, table++)
        {
            if (*table != ~0)
            {
                /* Start from next slot. */
                index += i + 1;
                break;
            }
        }

        if (i == PageCount)
        {
            /* Bail out if we have enough page entries. */
            allocated = gcvTRUE;
            break;
        }
    }

    if (!allocated)
    {
        if (status >= 0)
        {
            /* Walk all entries until we find enough slots. */
            for (index = 0; index <= tail;)
            {
                /* Access page table. */
                table = (gctUINT32 *) Mmu->pageTableLogical + index;

                /* See if all slots are available. */
                for (i = 0; i < PageCount; i++, table++)
                {
                    if (*table != ~0)
                    {
                        /* Start from next slot. */
                        index += i + 1;
                        break;
                    }
                }

                if (i == PageCount)
                {
                    /* Bail out if we have enough page entries. */
                    allocated = gcvTRUE;
                    break;
                }
            }
        }
    }

    if (!allocated && (status >= 0))
    {
        gcmkTRACE_ZONE(
            gcvLEVEL_ERROR, gcvZONE_MMU,
            "%s(%d): not enough free pages for %u pages.\n",
            __FUNCTION__, __LINE__,
            PageCount
            );

        /* Not enough empty slots available. */
        status = gcvSTATUS_OUT_OF_RESOURCES;
    }

    if (status >= 0)
    {
        /* Build virtual address. */
        status = gckVGHARDWARE_BuildVirtualAddress(Mmu->hardware,
                                                 index,
                                                 0,
                                                 Address);

        if (status >= 0)
        {
            /* Update current entry into page table. */
            Mmu->entry = index + PageCount;

            /* Return pointer to page table. */
            *PageTable = (gctUINT32 *)  Mmu->pageTableLogical + index;

            gcmkTRACE_ZONE(
                gcvLEVEL_INFO, gcvZONE_MMU,
                "%s(%d): allocated %u pages at index %u (0x%08X) @ %p.\n",
                __FUNCTION__, __LINE__,
                PageCount,
                index,
                *Address,
                *PageTable
                );
            }
    }

    /* Release the mutex. */
    gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->mutex));
    gcmkFOOTER();

    /* Return status. */
    return status;
}
/*******************************************************************************
**
**  gckHEAP_Allocate
**
**  Allocate data from the heap.
**
**  INPUT:
**
**      gckHEAP Heap
**          Pointer to a gckHEAP object.
**
**      IN gctSIZE_T Bytes
**          Number of byte to allocate.
**
**  OUTPUT:
**
**      gctPOINTER * Memory
**          Pointer to a variable that will hold the address of the allocated
**          memory.
*/
gceSTATUS
gckHEAP_Allocate(
    IN gckHEAP Heap,
    IN gctSIZE_T Bytes,
    OUT gctPOINTER * Memory
    )
{
    gctBOOL acquired = gcvFALSE;
    gcskHEAP_PTR heap;
    gceSTATUS status;
    gctSIZE_T bytes;
    gcskNODE_PTR node, used, prevFree = gcvNULL;
    gctPOINTER memory = gcvNULL;

    gcmkHEADER_ARG("Heap=0x%x Bytes=%lu", Heap, Bytes);

    /* Verify the arguments. */
    gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP);
    gcmkVERIFY_ARGUMENT(Bytes > 0);
    gcmkVERIFY_ARGUMENT(Memory != gcvNULL);

    /* Determine number of bytes required for a node. */
    bytes = gcmALIGN(Bytes + gcmSIZEOF(gcskNODE), 8);

    /* Acquire the mutex. */
    gcmkONERROR(
        gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE));

    acquired = gcvTRUE;

    /* Check if this allocation is bigger than the default allocation size. */
    if (bytes > Heap->allocationSize - gcmSIZEOF(gcskHEAP) - gcmSIZEOF(gcskNODE))
    {
        /* Adjust allocation size. */
        Heap->allocationSize = bytes * 2;
    }

    else if (Heap->heap != gcvNULL)
    {
        gctINT i;

        /* 2 retries, since we might need to compact. */
        for (i = 0; i < 2; ++i)
        {
            /* Walk all the heaps. */
            for (heap = Heap->heap; heap != gcvNULL; heap = heap->next)
            {
                /* Check if this heap has enough bytes to hold the request. */
                if (bytes <= heap->size - gcmSIZEOF(gcskNODE))
                {
                    prevFree = gcvNULL;

                    /* Walk the chain of free nodes. */
                    for (node = heap->freeList;
                         node != gcvNULL;
                         node = node->next
                    )
                    {
                        gcmkASSERT(node->next != gcdIN_USE);

                        /* Check if this free node has enough bytes. */
                        if (node->bytes >= bytes)
                        {
                            /* Use the node. */
                            goto UseNode;
                        }

                        /* Save current free node for linked list management. */
                        prevFree = node;
                    }
                }
            }

            if (i == 0)
            {
                /* Compact the heap. */
                gcmkVERIFY_OK(_CompactKernelHeap(Heap));

#if gcmIS_DEBUG(gcdDEBUG_CODE)
                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
                               "===== KERNEL HEAP =====");
                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
                               "Number of allocations           : %12u",
                               Heap->allocCount);
                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
                               "Number of bytes allocated       : %12llu",
                               Heap->allocBytes);
                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
                               "Maximum allocation size         : %12llu",
                               Heap->allocBytesMax);
                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
                               "Total number of bytes allocated : %12llu",
                               Heap->allocBytesTotal);
                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
                               "Number of heaps                 : %12u",
                               Heap->heapCount);
                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
                               "Heap memory in bytes            : %12llu",
                               Heap->heapMemory);
                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
                               "Maximum number of heaps         : %12u",
                               Heap->heapCountMax);
                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
                               "Maximum heap memory in bytes    : %12llu",
                               Heap->heapMemoryMax);
#endif
            }
        }
    }

    /* Release the mutex. */
    gcmkONERROR(
        gckOS_ReleaseMutex(Heap->os, Heap->mutex));

    acquired = gcvFALSE;

    /* Allocate a new heap. */
    gcmkONERROR(
        gckOS_AllocateMemory(Heap->os,
                             Heap->allocationSize,
                             &memory));

    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HEAP,
                   "Allocated heap 0x%x (%lu bytes)",
                   memory, Heap->allocationSize);

    /* Acquire the mutex. */
    gcmkONERROR(
        gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE));

    acquired = gcvTRUE;

    /* Use the allocated memory as the heap. */
    heap = (gcskHEAP_PTR) memory;

    /* Insert this heap to the head of the chain. */
    heap->next = Heap->heap;
    heap->prev = gcvNULL;
    heap->size = Heap->allocationSize - gcmSIZEOF(gcskHEAP);

    if (heap->next != gcvNULL)
    {
        heap->next->prev = heap;
    }
    Heap->heap = heap;

    /* Mark the end of the heap. */
    node = (gcskNODE_PTR) ( (gctUINT8_PTR) heap
                          + Heap->allocationSize
                          - gcmSIZEOF(gcskNODE)
                          );
    node->bytes = 0;
    node->next  = gcvNULL;

    /* Create a free list. */
    node           = (gcskNODE_PTR) (heap + 1);
    heap->freeList = node;

    /* Initialize the free list. */
    node->bytes = heap->size - gcmSIZEOF(gcskNODE);
    node->next  = gcvNULL;

    /* No previous free. */
    prevFree = gcvNULL;

#if VIVANTE_PROFILER || gcmIS_DEBUG(gcdDEBUG_CODE)
    /* Update profiling. */
    Heap->heapCount  += 1;
    Heap->heapMemory += Heap->allocationSize;

    if (Heap->heapCount > Heap->heapCountMax)
    {
        Heap->heapCountMax = Heap->heapCount;
    }
    if (Heap->heapMemory > Heap->heapMemoryMax)
    {
        Heap->heapMemoryMax = Heap->heapMemory;
    }
#endif

UseNode:
    /* Verify some stuff. */
    gcmkASSERT(heap != gcvNULL);
    gcmkASSERT(node != gcvNULL);
    gcmkASSERT(node->bytes >= bytes);

    if (heap->prev != gcvNULL)
    {
        /* Unlink the heap from the linked list. */
        heap->prev->next = heap->next;
        if (heap->next != gcvNULL)
        {
            heap->next->prev = heap->prev;
        }

        /* Move the heap to the front of the list. */
        heap->next       = Heap->heap;
        heap->prev       = gcvNULL;
        Heap->heap       = heap;
        heap->next->prev = heap;
    }

    /* Check if there is enough free space left after usage for another free
    ** node. */
    if (node->bytes - bytes >= gcmSIZEOF(gcskNODE))
    {
        /* Allocated used space from the back of the free list. */
        used = (gcskNODE_PTR) ((gctUINT8_PTR) node + node->bytes - bytes);

        /* Adjust the number of free bytes. */
        node->bytes -= bytes;
        gcmkASSERT(node->bytes >= gcmSIZEOF(gcskNODE));
    }
    else
    {
        /* Remove this free list from the chain. */
        if (prevFree == gcvNULL)
        {
            heap->freeList = node->next;
        }
        else
        {
            prevFree->next = node->next;
        }

        /* Consume the entire free node. */
        used  = (gcskNODE_PTR) node;
        bytes = node->bytes;
    }

    /* Mark node as used. */
    used->bytes     = bytes;
    used->next      = gcdIN_USE;
#if gcmIS_DEBUG(gcdDEBUG_CODE)
    used->timeStamp = ++Heap->timeStamp;
#endif

#if VIVANTE_PROFILER || gcmIS_DEBUG(gcdDEBUG_CODE)
    /* Update profile counters. */
    Heap->allocCount      += 1;
    Heap->allocBytes      += bytes;
    Heap->allocBytesMax    = gcmMAX(Heap->allocBytes, Heap->allocBytesMax);
    Heap->allocBytesTotal += bytes;
#endif

    /* Release the mutex. */
    gcmkVERIFY_OK(
        gckOS_ReleaseMutex(Heap->os, Heap->mutex));

    /* Return pointer to memory. */
    *Memory = used + 1;

    /* Success. */
    gcmkFOOTER_ARG("*Memory=0x%x", *Memory);
    return gcvSTATUS_OK;

OnError:
    if (acquired)
    {
        /* Release the mutex. */
        gcmkVERIFY_OK(
            gckOS_ReleaseMutex(Heap->os, Heap->mutex));
    }

    if (memory != gcvNULL)
    {
        /* Free the heap memory. */
        gckOS_FreeMemory(Heap->os, memory);
    }

    /* Return the status. */
    gcmkFOOTER();
    return status;
}
/*******************************************************************************
**
**  gckHEAP_Construct
**
**  Construct a new gckHEAP object.
**
**  INPUT:
**
**      gckOS Os
**          Pointer to a gckOS object.
**
**      gctSIZE_T AllocationSize
**          Minimum size per arena.
**
**  OUTPUT:
**
**      gckHEAP * Heap
**          Pointer to a variable that will hold the pointer to the gckHEAP
**          object.
*/
gceSTATUS
gckHEAP_Construct(
    IN gckOS Os,
    IN gctSIZE_T AllocationSize,
    OUT gckHEAP * Heap
    )
{
    gceSTATUS status;
    gckHEAP heap = gcvNULL;
    gctPOINTER pointer = gcvNULL;

    gcmkHEADER_ARG("Os=0x%x AllocationSize=%lu", Os, AllocationSize);

    /* Verify the arguments. */
    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
    gcmkVERIFY_ARGUMENT(Heap != gcvNULL);

    /* Allocate the gckHEAP object. */
    gcmkONERROR(gckOS_AllocateMemory(Os,
                                     gcmSIZEOF(struct _gckHEAP),
                                     &pointer));

    heap = pointer;

    /* Initialize the gckHEAP object. */
    heap->object.type    = gcvOBJ_HEAP;
    heap->os             = Os;
    heap->allocationSize = AllocationSize;
    heap->heap           = gcvNULL;
#if gcmIS_DEBUG(gcdDEBUG_CODE)
    heap->timeStamp      = 0;
#endif

#if VIVANTE_PROFILER || gcmIS_DEBUG(gcdDEBUG_CODE)
    /* Zero the counters. */
    heap->allocCount      = 0;
    heap->allocBytes      = 0;
    heap->allocBytesMax   = 0;
    heap->allocBytesTotal = 0;
    heap->heapCount       = 0;
    heap->heapCountMax    = 0;
    heap->heapMemory      = 0;
    heap->heapMemoryMax   = 0;
#endif

    /* Create the mutex. */
    gcmkONERROR(gckOS_CreateMutex(Os, &heap->mutex));

    /* Return the pointer to the gckHEAP object. */
    *Heap = heap;

    /* Success. */
    gcmkFOOTER_ARG("*Heap=0x%x", *Heap);
    return gcvSTATUS_OK;

OnError:
    /* Roll back. */
    if (heap != gcvNULL)
    {
        /* Free the heap structure. */
        gcmkVERIFY_OK(gckOS_FreeMemory(Os, heap));
    }

    /* Return the status. */
    gcmkFOOTER();
    return status;
}
예제 #30
0
/*******************************************************************************
**
**  gckVGMMU_Construct
**
**  Construct a new gckVGMMU object.
**
**  INPUT:
**
**      gckVGKERNEL Kernel
**          Pointer to an gckVGKERNEL object.
**
**      gctSIZE_T MmuSize
**          Number of bytes for the page table.
**
**  OUTPUT:
**
**      gckVGMMU * Mmu
**          Pointer to a variable that receives the gckVGMMU object pointer.
*/
gceSTATUS gckVGMMU_Construct(
    IN gckVGKERNEL Kernel,
    IN gctSIZE_T MmuSize,
    OUT gckVGMMU * Mmu
    )
{
    gckOS os;
    gckVGHARDWARE hardware;
    gceSTATUS status;
    gckVGMMU mmu;
    gctUINT32 * pageTable;
    gctUINT32 i;

    gcmkHEADER_ARG("Kernel=0x%x MmuSize=0x%x Mmu=0x%x", Kernel, MmuSize, Mmu);

    /* Verify the arguments. */
    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
    gcmkVERIFY_ARGUMENT(MmuSize > 0);
    gcmkVERIFY_ARGUMENT(Mmu != gcvNULL);

    /* Extract the gckOS object pointer. */
    os = Kernel->os;
    gcmkVERIFY_OBJECT(os, gcvOBJ_OS);

    /* Extract the gckVGHARDWARE object pointer. */
    hardware = Kernel->hardware;
    gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);

    /* Allocate memory for the gckVGMMU object. */
    status = gckOS_Allocate(os, sizeof(struct _gckVGMMU), (gctPOINTER *) &mmu);

    if (status < 0)
    {
        /* Error. */
        gcmkFATAL(
            "%s(%d): could not allocate gckVGMMU object.",
            __FUNCTION__, __LINE__
            );

        gcmkFOOTER();
        return status;
    }

    /* Initialize the gckVGMMU object. */
    mmu->object.type = gcvOBJ_MMU;
    mmu->os = os;
    mmu->hardware = hardware;

    /* Create the mutex. */
    status = gckOS_CreateMutex(os, &mmu->mutex);

    if (status < 0)
    {
        /* Roll back. */
        mmu->object.type = gcvOBJ_UNKNOWN;
        gcmkVERIFY_OK(gckOS_Free(os, mmu));

        gcmkFOOTER();
        /* Error. */
        return status;
    }

    /* Allocate the page table. */
    mmu->pageTableSize = MmuSize;
    status = gckOS_AllocateContiguous(os,
                                      gcvFALSE,
                                      &mmu->pageTableSize,
                                      &mmu->pageTablePhysical,
                                      &mmu->pageTableLogical);

    if (status < 0)
    {
        /* Roll back. */
        gcmkVERIFY_OK(gckOS_DeleteMutex(os, mmu->mutex));

        mmu->object.type = gcvOBJ_UNKNOWN;
        gcmkVERIFY_OK(gckOS_Free(os, mmu));

        /* Error. */
        gcmkFATAL(
            "%s(%d): could not allocate page table.",
            __FUNCTION__, __LINE__
            );

        gcmkFOOTER();
        return status;
    }

    /* Compute number of entries in page table. */
    mmu->entryCount = mmu->pageTableSize / sizeof(gctUINT32);
    mmu->entry = 0;

    /* Mark the entire page table as available. */
    pageTable = (gctUINT32 *) mmu->pageTableLogical;
    for (i = 0; i < mmu->entryCount; i++)
    {
        pageTable[i] = (gctUINT32)~0;
    }

    /* Set page table address. */
    status = gckVGHARDWARE_SetMMU(hardware, mmu->pageTableLogical);

    if (status < 0)
    {
        /* Free the page table. */
        gcmkVERIFY_OK(gckOS_FreeContiguous(mmu->os,
                                      mmu->pageTablePhysical,
                                      mmu->pageTableLogical,
                                      mmu->pageTableSize));

        /* Roll back. */
        gcmkVERIFY_OK(gckOS_DeleteMutex(os, mmu->mutex));

        mmu->object.type = gcvOBJ_UNKNOWN;
        gcmkVERIFY_OK(gckOS_Free(os, mmu));

        /* Error. */
        gcmkFATAL(
            "%s(%d): could not program page table.",
            __FUNCTION__, __LINE__
            );

        gcmkFOOTER();
        return status;
    }

    /* Return the gckVGMMU object pointer. */
    *Mmu = mmu;

    gcmkTRACE_ZONE(
        gcvLEVEL_INFO, gcvZONE_MMU,
        "%s(%d): %u entries at %p.(0x%08X)\n",
        __FUNCTION__, __LINE__,
        mmu->entryCount,
        mmu->pageTableLogical,
        mmu->pageTablePhysical
        );

    gcmkFOOTER_NO();
    /* Success. */
    return gcvSTATUS_OK;
}