#if defined(JAZZ)

/*++

Copyright (c) 1991  Microsoft Corporation

Module Name:

    jxmemory.c

Abstract:

    This module implements the ARC firmware memory configuration operations
    for a MIPS R3000 or R4000 Jazz system.

Author:

    David N. Cutler (davec) 18-May-1991


Revision History:

--*/

#include "fwp.h"
#include "selfmap.h"
extern  end[];

//
// Define memory listhead, allocation entries, and free index.
//

ULONG FwMemoryFree;
LIST_ENTRY FwMemoryListHead;
FW_MEMORY_DESCRIPTOR FwMemoryTable[FW_MEMORY_TABLE_SIZE];

VOID
FwInitializeMemory (
    VOID
    )

/*++

Routine Description:

    This routine initializes the memory allocation list for the memory
    configuration routine.

Arguments:

    None.

Return Value:

    None.

--*/

{

    ULONG MemoryPages;
    //
    // Initialize the memory allocation listhead.
    //

    InitializeListHead(&FwMemoryListHead);

    //
    // Initialize the entry for the exception vectors and the system
    // parameter block.
    //

    FwMemoryTable[0].MemoryEntry.MemoryType = MemoryFirmwarePermanent;

    FwMemoryTable[0].MemoryEntry.BasePage = 0;
    FwMemoryTable[0].MemoryEntry.PageCount = 2;
    InsertTailList(&FwMemoryListHead, &FwMemoryTable[0].ListEntry);

    //
    // Initialize the entry for the firmware stack and code.
    //

    FwMemoryTable[1].MemoryEntry.MemoryType = MemoryFirmwareTemporary;

    FwMemoryTable[1].MemoryEntry.PageCount = FW_PAGES_OLD - 2;
    FwMemoryTable[1].MemoryEntry.BasePage = 2;
    InsertTailList(&FwMemoryListHead, &FwMemoryTable[1].ListEntry);

    //
    // Initialize the entry for free memory and zero the free memory area.
    //

    FwMemoryTable[2].MemoryEntry.MemoryType = MemoryFree;
    FwMemoryTable[2].MemoryEntry.BasePage = FW_PAGES_OLD;
    FwMemoryTable[2].MemoryEntry.PageCount = 0x7ed - FW_PAGES_OLD;
    InsertTailList(&FwMemoryListHead, &FwMemoryTable[2].ListEntry);

    //
    // Initialize the entry for the firmware pool.
    //

    FwMemoryTable[3].MemoryEntry.MemoryType = MemoryFirmwareTemporary;
    FwMemoryTable[3].MemoryEntry.BasePage = 0x7ed;
    FwMemoryTable[3].MemoryEntry.PageCount = 0x7fd - 0x7ed;
    InsertTailList(&FwMemoryListHead, &FwMemoryTable[3].ListEntry);

    //
    // Initialize the entry for the PCR page used by the kernel debugger.
    //

    FwMemoryTable[4].MemoryEntry.MemoryType = MemoryFirmwareTemporary;
    FwMemoryTable[4].MemoryEntry.BasePage = 0x7fd;
    FwMemoryTable[4].MemoryEntry.PageCount = 0x800 - 0x7fd;
    InsertTailList(&FwMemoryListHead, &FwMemoryTable[4].ListEntry);

    //
    // If the size of memory is greater than 8mb, then generate another
    // descriptor to describe the free memory above the PCR page.
    //

    if ((MemorySize > 8) && (((ULONG) end & ~KSEG1_BASE) < 0x0800000)) {
        MemoryPages = (MemorySize << (20 - PAGE_SHIFT));
        FwMemoryTable[5].MemoryEntry.MemoryType = MemoryFree;
        FwMemoryTable[5].MemoryEntry.BasePage = 0x800;
        FwMemoryTable[5].MemoryEntry.PageCount = MemoryPages - 0x800;
        InsertTailList(&FwMemoryListHead, &FwMemoryTable[5].ListEntry);
        //RtlZeroMemory((PVOID)(KSEG0_BASE + 0x800000),
        //               (MemoryPages - 0x800) << PAGE_SHIFT);
        FwMemoryFree = 6;

    } else if (((ULONG) end & ~KSEG1_BASE) > 0x0800000) {

        //
        // If this copy of the firmware is loaded above 8 MB, then
        // only part of memory should be zeroed and appropriate memory
        // descriptors should be created.
        //
        // Note: currently all the memory between 800000 and the end
        // of this code is made firmware permanent.
        //

        FwMemoryTable[5].MemoryEntry.MemoryType = MemoryFirmwarePermanent;
        FwMemoryTable[5].MemoryEntry.BasePage = 0x800;
        FwMemoryTable[5].MemoryEntry.PageCount =
            ROUND_TO_PAGES((ULONG) end & ~KSEG1_BASE) - 0x800;
        InsertTailList(&FwMemoryListHead, &FwMemoryTable[5].ListEntry);

        MemoryPages = (MemorySize << (20 - PAGE_SHIFT));
        FwMemoryTable[6].MemoryEntry.MemoryType = MemoryFree;
        FwMemoryTable[6].MemoryEntry.BasePage = ROUND_TO_PAGES((ULONG) end & ~KSEG1_BASE);
        FwMemoryTable[6].MemoryEntry.PageCount = MemoryPages -
            FwMemoryTable[6].MemoryEntry.BasePage;
        InsertTailList(&FwMemoryListHead, &FwMemoryTable[6].ListEntry);
        //RtlZeroMemory((PVOID)(KSEG0_BASE + (FwMemoryTable[6].MemoryEntry.BasePage << PAGE_SHIFT)),
        //              FwMemoryTable[6].MemoryEntry.PageCount << PAGE_SHIFT);
        FwMemoryFree = 7;

    } else {
        FwMemoryFree = 5;
    }

    //
    // Initialize the memory configuration routine address in the system
    // parameter block.
    //

    SYSTEM_BLOCK->FirmwareVector[MemoryRoutine] = FwGetMemoryDescriptor;

    return;
}

PMEMORY_DESCRIPTOR
FwGetMemoryDescriptor (
    IN PMEMORY_DESCRIPTOR MemoryDescriptor OPTIONAL
    )

/*++

Routine Description:

    This routine returns a pointer to the next memory descriptor. If
    the specified memory descriptor is NULL, then a pointer to the
    first memory descriptor is returned. If there are no more memory
    descriptors, then NULL is returned.

Arguments:

    MemoryDescriptor - Supplies a optional pointer to a memory descriptor.

Return Value:

    If there are any more entries in the memory descriptor list, the
    address of the next descriptor is returned. Otherwise, NULL is
    returned.

--*/

{

    PFW_MEMORY_DESCRIPTOR TableEntry;
    PLIST_ENTRY NextEntry;

    //
    // If a memory descriptor address is specified, then return the
    // address of the next descriptor or NULL as appropriate. Otherwise,
    // return the address of the first memory descriptor.
    //

    if (ARGUMENT_PRESENT(MemoryDescriptor)) {
        TableEntry = CONTAINING_RECORD(MemoryDescriptor,
                                       FW_MEMORY_DESCRIPTOR,
                                       MemoryEntry);

        NextEntry = TableEntry->ListEntry.Flink;
        if (NextEntry != &FwMemoryListHead) {
            return &(CONTAINING_RECORD(NextEntry,
                                       FW_MEMORY_DESCRIPTOR,
                                       ListEntry)->MemoryEntry);

        } else {
            return NULL;
        }

    } else {
        return &FwMemoryTable[0].MemoryEntry;
    }
}

VOID
FwGenerateDescriptor (
    IN PFW_MEMORY_DESCRIPTOR MemoryDescriptor,
    IN MEMORY_TYPE MemoryType,
    IN ULONG BasePage,
    IN ULONG PageCount
    )

/*++

Routine Description:

    This routine allocates a new memory descriptor to describe the
    specified region of memory which is assumed to lie totally within
    the specified region which is free.

Arguments:

    MemoryDescriptor - Supplies a pointer to a free memory descriptor
        from which the specified memory is to be allocated.

    MemoryType - Supplies the type that is assigned to the allocated
        memory.

    BasePage - Supplies the base page number.

    PageCount - Supplies the number of pages.

Return Value:

    None.

--*/

{

    PLIST_ENTRY NextEntry;
    ULONG Offset;

    //
    // If the specified region totally consumes the free region, then no
    // additional descriptors need to be allocated. If the specified region
    // is at the start or end of the free region, then only one descriptor
    // needs to be allocated. Otherwise, two additional descriptors need to
    // be allocated.
    //

    Offset = BasePage - MemoryDescriptor->MemoryEntry.BasePage;
    if ((Offset == 0) && (PageCount == MemoryDescriptor->MemoryEntry.PageCount)) {

        //
        // The specified region totally consumes the free region.
        //

        MemoryDescriptor->MemoryEntry.MemoryType = MemoryType;

    } else {

        //
        // A memory descriptor must be generated to describe the allocated
        // memory.
        //

        FwMemoryTable[FwMemoryFree].MemoryEntry.MemoryType = MemoryType;
        FwMemoryTable[FwMemoryFree].MemoryEntry.BasePage = BasePage;
        FwMemoryTable[FwMemoryFree].MemoryEntry.PageCount = PageCount;
        InsertTailList(&FwMemoryListHead,
                       &FwMemoryTable[FwMemoryFree].ListEntry);

        FwMemoryFree += 1;

        //
        // Determine whether an additional memory descriptor must be generated.
        //

        if (BasePage == MemoryDescriptor->MemoryEntry.BasePage) {

            //
            // The specified region lies at the start of the free region.
            //

            MemoryDescriptor->MemoryEntry.BasePage += PageCount;
            MemoryDescriptor->MemoryEntry.PageCount -= PageCount;

        } else if ((Offset + PageCount) == MemoryDescriptor->MemoryEntry.PageCount) {

            //
            // The specified region lies at the end of the free region.
            //

            MemoryDescriptor->MemoryEntry.PageCount -= PageCount;

        } else {

            //
            // The specified region lies in the middle of the free region.
            // Another memory descriptor must be generated.
            //

            FwMemoryTable[FwMemoryFree].MemoryEntry.MemoryType = MemoryFree;
            FwMemoryTable[FwMemoryFree].MemoryEntry.BasePage = BasePage + PageCount;
            FwMemoryTable[FwMemoryFree].MemoryEntry.PageCount =
                                    MemoryDescriptor->MemoryEntry.PageCount -
                                    (PageCount + Offset);
            InsertTailList(&FwMemoryListHead,
                           &FwMemoryTable[FwMemoryFree].ListEntry);

            FwMemoryFree += 1;
            MemoryDescriptor->MemoryEntry.PageCount = Offset;
        }
    }

    return;
}

VOID
FwResetMemory(
    VOID
)

/*++

Routine Description:

    This routine calls FwInitializeMemory to reset the memory descriptors
    and then loops through and clears all of the appropriate memory.

Arguments:

    None.

Return Value:

    None.

--*/

{
    PMEMORY_DESCRIPTOR MemoryDescriptor;

    FwInitializeMemory();

    //
    // Reset all memory not used by the firmware.
    // TEMPTEMP Just reset under 8M Bytes for now.
    //

    MemoryDescriptor = FwGetMemoryDescriptor(NULL);
    while (MemoryDescriptor != NULL) {

        if ((MemoryDescriptor->MemoryType != MemoryFirmwarePermanent) &&
            (MemoryDescriptor->MemoryType != MemoryFirmwareTemporary) &&
            (MemoryDescriptor->BasePage < 0x800)) {
            RtlZeroMemory((PVOID)(KSEG0_BASE + (MemoryDescriptor->BasePage << PAGE_SHIFT)),
                          MemoryDescriptor->PageCount << PAGE_SHIFT);
        }

        MemoryDescriptor = FwGetMemoryDescriptor(MemoryDescriptor);
    }

    //
    // Sweep the data cache
    //

    HalSweepDcache();

}
#endif
