Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1615 lines
54 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
ntsetup.c
Abstract:
This module is the tail-end of the OS loader program. It performs all
PPC specific allocations and initialize. The OS loader invokes this
this routine immediately before calling the loaded kernel image.
Author:
John Vert (jvert) 20-Jun-1991
Environment:
Kernel mode
Revision History:
--*/
#include "bldr.h"
#include <stdio.h>
#define KB 1024
#define MB (KB * KB)
#define MBpages (MB / PAGE_SIZE)
#define MIN(_a,_b) (((_a) <= (_b)) ? (_a) : (_b))
#define MAX(_a,_b) (((_a) >= (_b)) ? (_a) : (_b))
#define PAGES(_bytes) ((_bytes) >> PAGE_SHIFT)
#define BYTES(_pages) ((_pages) << PAGE_SHIFT)
#define PageFromAddress(_addr) PAGES((_addr) & ~KSEG0_BASE)
#define AddressFromPage(_page) (KSEG0_BASE | BYTES(_page))
#define RealAddressFromPage(_page) BYTES(_page)
//
// If a system has less than PAGED_KERNEL_MEMORY_LIMIT pages of memory,
// we will page the kernel, thus making more memory available for apps.
// If a system has more than PAGED_KERNEL_MEMORY_LIMIT pages of memory,
// we will map the kernel using the KSEG0 BAT, thus avoiding translation
// overhead.
//
#define PAGED_KERNEL_MEMORY_LIMIT (48*MBpages)
//
// Boolean indicating whether the kernel is to be paged or mapped by a BAT register.
//
BOOLEAN PageKernel;
//
// Define macro to round structure size to next 16-byte boundary
//
#define ROUND_UP(x) ((sizeof(x) + 15) & (~15))
//
// Configuration Data Header
// The following structure is copied from fw\ppc\oli2msft.h
// NOTE shielint - Somehow, this structure got incorporated into
// firmware EISA configuration data. We need to know the size of the
// header and remove it before writing eisa configuration data to
// registry.
//
typedef struct _CONFIGURATION_DATA_HEADER {
USHORT Version;
USHORT Revision;
PCHAR Type;
PCHAR Vendor;
PCHAR ProductName;
PCHAR SerialNumber;
} CONFIGURATION_DATA_HEADER;
#define CONFIGURATION_DATA_HEADER_SIZE sizeof(CONFIGURATION_DATA_HEADER)
//
// Internal function references
//
ARC_STATUS
ReorganizeEisaConfigurationTree(
IN PCONFIGURATION_COMPONENT_DATA RootEntry
);
ARC_STATUS
CreateEisaConfigurationData (
IN PCONFIGURATION_COMPONENT_DATA RootEntry
);
VOID
BlQueryImplementationAndRevision (
OUT PULONG ProcessorId,
OUT PULONG ProcessorRev
);
ARC_STATUS
NextFreePage (
IN OUT PULONG FreePage,
IN OUT PULONG NumberFree,
IN OUT PMEMORY_ALLOCATION_DESCRIPTOR *FreeDescriptor
)
{
PLIST_ENTRY NextEntry;
PMEMORY_ALLOCATION_DESCRIPTOR NextDescriptor;
(*FreePage)++;
(*NumberFree)--;
if (*NumberFree != 0) {
return ESUCCESS;
}
BlLog((LOG_ALL,"Generating FirmwarePermanent descriptor for %x pages at %x taken for PTE pages",(*FreeDescriptor)->PageCount,(*FreeDescriptor)->BasePage));
(*FreeDescriptor)->MemoryType = LoaderFirmwarePermanent;
NextEntry = (*FreeDescriptor)->ListEntry.Flink;
while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
NextDescriptor = CONTAINING_RECORD(NextEntry,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
if (NextDescriptor->MemoryType == LoaderFree) {
*FreeDescriptor = NextDescriptor;
*FreePage = NextDescriptor->BasePage;
*NumberFree = NextDescriptor->PageCount;
BlLog((LOG_ALL,"%x PTE pages available at %x",*NumberFree,*FreePage));
return ESUCCESS;
}
NextEntry = NextEntry->Flink;
}
return ENOMEM;
}
ARC_STATUS
AllocateKseg0Blocks (
OUT PULONG HighestKseg0PageParameter
)
{
ARC_STATUS Status;
ULONG HighestKseg0Page;
ULONG HptPages;
ULONG BasePage;
ULONG NumberOfPcrs;
//
// We need to allocate a number of items in what will become KSEG0,
// mapped by a BAT register. We want these items to be allocated as
// low in memory as possible.
//
// N.B. We do a number of individual allocations, rather than one
// large allocation, in order to ensure that the allocations
// succeed, even if low memory is fragmented.
//
BlSetAllocationPolicy(BlAllocateLowestFit, BlAllocateHighestFit);
HighestKseg0Page = 5; // exception vector pages
BlLogMemoryDescriptors(LOG_ALL_W);
//
// Allocate the hashed page table first, because the HPT must be
// aligned based on its size.
//
// N.B. Not all machines require an HPT (e.g., 603).
//
HptPages = BlLoaderBlock->u.Ppc.HashedPageTableSize;
BlLoaderBlock->u.Ppc.HashedPageTable = 0;
if (HptPages != 0) {
Status = BlAllocateAlignedDescriptor(LoaderFirmwarePermanent,
0,
HptPages,
HptPages,
&BasePage);
if (Status != ESUCCESS) {
return Status;
}
BlLoaderBlock->u.Ppc.HashedPageTable = RealAddressFromPage(BasePage);
RtlZeroMemory((PVOID)AddressFromPage(BasePage), BYTES(HptPages));
if ((BasePage + HptPages) > HighestKseg0Page) {
HighestKseg0Page = BasePage + HptPages;
}
BlLog((LOG_ALL,"Allocated %x pages for HPT at %x",HptPages,BasePage));
}
//
// Allocate PCRs for additional processors. (We don't know how many
// processors there might be, so we assume the most.)
//
// N.B. If we can't get the maximum number of PCR pages, we try for
// less. This just means the system won't be able to start 32
// processors. If not even one page can be allocated,
// however, we give up on the boot, because our next
// allocation is sure to fail.
//
BlLoaderBlock->u.Ppc.PcrPagesDescriptor = NULL;
NumberOfPcrs = MAXIMUM_PROCESSORS - 1;
do {
Status = BlAllocateAlignedDescriptor(LoaderStartupPcrPage,
0,
NumberOfPcrs,
0,
&BasePage);
if (Status == ESUCCESS) {
break;
}
NumberOfPcrs--;
} while (NumberOfPcrs != 0);
if (Status != ESUCCESS) {
return Status;
}
BlLoaderBlock->u.Ppc.PcrPagesDescriptor = BlFindMemoryDescriptor(BasePage);
RtlZeroMemory((PVOID)AddressFromPage(BasePage), NumberOfPcrs * PAGE_SIZE);
if ((BasePage + NumberOfPcrs) > HighestKseg0Page) {
HighestKseg0Page = BasePage + NumberOfPcrs;
}
BlLog((LOG_ALL,"Allocated %x pages for PCRs at %x",NumberOfPcrs,BasePage));
//
// Allocate a few extra pages in KSEG0 for the kernel to use.
//
Status = BlAllocateDescriptor(LoaderFirmwarePermanent,
0,
5,
&BasePage);
if (Status != ESUCCESS) {
return(Status);
}
BlLoaderBlock->u.Ppc.KernelKseg0PagesDescriptor = BlFindMemoryDescriptor(BasePage);
RtlZeroMemory((PVOID)AddressFromPage(BasePage), 5 * PAGE_SIZE);
if ((BasePage + 5) > HighestKseg0Page) {
HighestKseg0Page = BasePage + 5;
}
BlLog((LOG_ALL,"Allocated %x pages for kernel at %x",5,BasePage));
//
// Allocate and zero three pages, one for the page directory page,
// one for the hyperspace PTE page, and one for the HAL's PTE page.
//
Status = BlAllocateDescriptor(LoaderStartupPdrPage,
0,
3,
&BasePage);
if (Status != ESUCCESS) {
return(Status);
}
BlLoaderBlock->u.Ppc.PdrPage = BasePage;
RtlZeroMemory((PVOID)AddressFromPage(BasePage), 3 * PAGE_SIZE);
if ((BasePage + 3) > HighestKseg0Page) {
HighestKseg0Page = BasePage + 3;
}
BlLog((LOG_ALL,"Allocated %x pages for PDR at %x",3,BasePage));
//
// Allocate and zero two pages, one for the PCR for processor 0 and
// one for the common PCR2 page.
//
Status = BlAllocateDescriptor(LoaderStartupPcrPage,
0,
2,
&BasePage);
if (Status != ESUCCESS) {
return(Status);
}
BlLoaderBlock->u.Ppc.PcrPage = BasePage;
BlLoaderBlock->u.Ppc.PcrPage2 = BlLoaderBlock->u.Ppc.PcrPage + 1;
RtlZeroMemory((PVOID)AddressFromPage(BasePage), 2 * PAGE_SIZE);
if ((BasePage + 2) > HighestKseg0Page) {
HighestKseg0Page = BasePage + 2;
}
BlLog((LOG_ALL,"Allocated %x pages for PCR at %x",2,BasePage));
//
// Now that we've allocated everything that needs to be in KSEG0, we
// can tell the memory allocator to start allocating using a
// best-fit algorithm.
//
BlSetAllocationPolicy(BlAllocateBestFit, BlAllocateBestFit);
*HighestKseg0PageParameter = HighestKseg0Page;
BlLogWaitForKeystroke();
return ESUCCESS;
}
ARC_STATUS
BlSetupForNt(
IN PLOADER_PARAMETER_BLOCK BlLoaderBlock
)
/*++
Routine Description:
This function initializes the PPC specific kernel data structures
required by the NT system.
Arguments:
BlLoaderBlock - Supplies the address of the loader parameter block.
Return Value:
ESUCCESS is returned if the setup is successfully complete. Otherwise,
an unsuccessful status is returned.
--*/
{
PCONFIGURATION_COMPONENT_DATA ConfigEntry;
CHAR Identifier[256];
ULONG KernelPage;
ULONG LinesPerBlock;
ULONG LineSize;
PCHAR NewIdentifier;
ARC_STATUS Status;
PCHAR IcacheModeString;
PCHAR DcacheModeString;
ULONG HighestKseg0Page;
ULONG Kseg0Pages;
ULONG Page;
ULONG HighPage;
ULONG Entry;
PHARDWARE_PTE PdePage;
PHARDWARE_PTE PtePage;
PLIST_ENTRY NextEntry;
PMEMORY_ALLOCATION_DESCRIPTOR NextDescriptor;
PMEMORY_ALLOCATION_DESCRIPTOR FreeDescriptor;
ULONG FreePage;
ULONG NumberFree;
ULONG ProcessorId;
ULONG ProcessorRev;
UCHAR Processor[32];
UCHAR Revision[32];
//
// If the host configuration is not a multiprocessor machine, then add
// the processor identification to the processor identification string.
//
if (SYSTEM_BLOCK->RestartBlock == NULL) {
ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
ProcessorClass,
CentralProcessor,
NULL);
if (ConfigEntry != NULL) {
BlQueryImplementationAndRevision(&ProcessorId, &ProcessorRev);
//
// Unfortunately, PowerPC numbering doesn't directly give us
// the name of the part.
//
switch (ProcessorId) {
case 6:
sprintf(Processor, "603+");
break;
case 7:
sprintf(Processor, "603++");
break;
case 9:
sprintf(Processor, "604+");
break;
default:
sprintf(Processor, "%d", ProcessorId + 600);
}
//
// 601 revision is just a number, others are a xx.yy eg
// 3.1
//
if ( ProcessorId == 1 ) {
sprintf(Revision, "%d", ProcessorRev);
} else {
sprintf(Revision, "%d.%d", ProcessorRev >> 8,
ProcessorRev & 0xff);
}
sprintf(&Identifier[0],
"%s - Pr %s, Rev %s",
ConfigEntry->ComponentEntry.Identifier,
Processor,
Revision);
NewIdentifier = (PCHAR)BlAllocateHeap(strlen(&Identifier[0]) + 1);
if (NewIdentifier != NULL) {
strcpy(NewIdentifier, &Identifier[0]);
ConfigEntry->ComponentEntry.IdentifierLength = strlen(NewIdentifier);
ConfigEntry->ComponentEntry.Identifier = NewIdentifier;
}
}
}
//
// Find System entry and check each of its direct child to
// look for EisaAdapter.
//
ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
SystemClass,
ArcSystem,
NULL);
if (ConfigEntry) {
ConfigEntry = ConfigEntry->Child;
}
while (ConfigEntry) {
if ((ConfigEntry->ComponentEntry.Class == AdapterClass) &&
(ConfigEntry->ComponentEntry.Type == EisaAdapter)) {
//
// Convert EISA format configuration data to our CM_ format.
//
Status = ReorganizeEisaConfigurationTree(ConfigEntry);
if (Status != ESUCCESS) {
return(Status);
}
}
ConfigEntry = ConfigEntry->Sibling;
}
//
// Find the primary data and instruction cache configuration entries, and
// compute the fill size and cache size for each cache. These entries MUST
// be present on all ARC compliant systems.
//
// BUT of course they aren't. So we'll handle their not being there by
// ignoring their absence and not writing cache sizes to the loader block.
//
ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
CacheClass,
PrimaryDcache,
NULL);
if (ConfigEntry != NULL) {
LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
BlLoaderBlock->u.Ppc.FirstLevelDcacheFillSize = LinesPerBlock * LineSize;
BlLoaderBlock->u.Ppc.FirstLevelDcacheSize =
1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
}
ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
CacheClass,
PrimaryIcache,
NULL);
if (ConfigEntry != NULL) {
LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
BlLoaderBlock->u.Ppc.FirstLevelIcacheFillSize = LinesPerBlock * LineSize;
BlLoaderBlock->u.Ppc.FirstLevelIcacheSize =
1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
}
//
// Find the secondary data and instruction cache configuration entries,
// and if present, compute the fill size and cache size for each cache.
// These entries are optional, and may or may not, be present.
//
ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
CacheClass,
SecondaryCache,
NULL);
if (ConfigEntry != NULL) {
LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
BlLoaderBlock->u.Ppc.SecondLevelDcacheFillSize = LinesPerBlock * LineSize;
BlLoaderBlock->u.Ppc.SecondLevelDcacheSize =
1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
BlLoaderBlock->u.Ppc.SecondLevelIcacheSize = 0;
BlLoaderBlock->u.Ppc.SecondLevelIcacheFillSize = 0;
} else {
ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
CacheClass,
SecondaryDcache,
NULL);
if (ConfigEntry != NULL) {
LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
BlLoaderBlock->u.Ppc.SecondLevelDcacheFillSize = LinesPerBlock * LineSize;
BlLoaderBlock->u.Ppc.SecondLevelDcacheSize =
1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
CacheClass,
SecondaryIcache,
NULL);
if (ConfigEntry != NULL) {
LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
BlLoaderBlock->u.Ppc.SecondLevelIcacheFillSize = LinesPerBlock * LineSize;
BlLoaderBlock->u.Ppc.SecondLevelIcacheSize =
1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
} else {
BlLoaderBlock->u.Ppc.SecondLevelIcacheSize = 0;
BlLoaderBlock->u.Ppc.SecondLevelIcacheFillSize = 0;
}
} else {
BlLoaderBlock->u.Ppc.SecondLevelDcacheSize = 0;
BlLoaderBlock->u.Ppc.SecondLevelDcacheFillSize = 0;
BlLoaderBlock->u.Ppc.SecondLevelIcacheSize = 0;
BlLoaderBlock->u.Ppc.SecondLevelIcacheFillSize = 0;
}
}
//
// Allocate DPC stack pages for the boot processor.
//
Status = BlAllocateDescriptor(LoaderStartupDpcStack,
0,
PAGES(KERNEL_STACK_SIZE),
&KernelPage);
if (Status != ESUCCESS) {
return(Status);
}
BlLoaderBlock->u.Ppc.InterruptStack = AddressFromPage(KernelPage) + KERNEL_STACK_SIZE;
//
// Allocate kernel stack pages for the boot processor idle thread.
//
Status = BlAllocateDescriptor(LoaderStartupKernelStack,
0,
PAGES(KERNEL_STACK_SIZE),
&KernelPage);
if (Status != ESUCCESS) {
return(Status);
}
BlLoaderBlock->KernelStack = AddressFromPage(KernelPage) + KERNEL_STACK_SIZE;
//
// Allocate panic stack pages for the boot processor.
//
Status = BlAllocateDescriptor(LoaderStartupPanicStack,
0,
PAGES(KERNEL_STACK_SIZE),
&KernelPage);
if (Status != ESUCCESS) {
return(Status);
}
BlLoaderBlock->u.Ppc.PanicStack = AddressFromPage(KernelPage) + KERNEL_STACK_SIZE;
//
// Disable the caches, if requested.
//
BlLoaderBlock->u.Ppc.IcacheMode = 0;
if (IcacheModeString = ArcGetEnvironmentVariable("ICACHEMODE")) {
if (_stricmp(IcacheModeString, "OFF") == 0) {
BlLoaderBlock->u.Ppc.IcacheMode = 1;
}
}
BlLoaderBlock->u.Ppc.DcacheMode = 0;
if (DcacheModeString = ArcGetEnvironmentVariable("DCACHEMODE")) {
if (_stricmp(DcacheModeString, "OFF") == 0) {
BlLoaderBlock->u.Ppc.DcacheMode = 1;
}
}
//
// Allocate the PRCB, process, and thread.
//
#define OS_DATA_SIZE PAGES(ROUND_UP(KPRCB)+ROUND_UP(EPROCESS)+ROUND_UP(ETHREAD)+(PAGE_SIZE-1))
Status = BlAllocateDescriptor(LoaderStartupPdrPage,
0,
OS_DATA_SIZE,
&KernelPage);
if (Status != ESUCCESS) {
return(Status);
}
BlLoaderBlock->Prcb = AddressFromPage(KernelPage);
RtlZeroMemory((PVOID)BlLoaderBlock->Prcb, BYTES(OS_DATA_SIZE));
BlLoaderBlock->Process = BlLoaderBlock->Prcb + ROUND_UP(KPRCB);
BlLoaderBlock->Thread = BlLoaderBlock->Process + ROUND_UP(EPROCESS);
//
// Initialize the page directory page. Set up the mappings for the
// PDR page and the hyperspace page.
//
PdePage = (PHARDWARE_PTE)AddressFromPage(BlLoaderBlock->u.Ppc.PdrPage);
BlLog((LOG_ALL,"PDE page at %x",PdePage));
PdePage[PDE_BASE>>PDI_SHIFT].PageFrameNumber = BlLoaderBlock->u.Ppc.PdrPage;
PdePage[PDE_BASE>>PDI_SHIFT].Valid = 1;
PdePage[PDE_BASE>>PDI_SHIFT].Write = 1;
BlLog((LOG_ALL,"PDE mapped at PdePage[%x] = %x",PDE_BASE>>PDI_SHIFT,*(PULONG)&PdePage[PDE_BASE>>PDI_SHIFT]));
PdePage[(PDE_BASE>>PDI_SHIFT)+1].PageFrameNumber = BlLoaderBlock->u.Ppc.PdrPage + 1;
PdePage[(PDE_BASE>>PDI_SHIFT)+1].Valid = 1;
PdePage[(PDE_BASE>>PDI_SHIFT)+1].Write = 1;
BlLog((LOG_ALL,"Hyperspace mapped at PdePage[%x] = %x",(PDE_BASE>>PDI_SHIFT)+1,*(PULONG)&PdePage[(PDE_BASE>>PDI_SHIFT)+1]));
//
// Allocate one page for the HAL to use to map memory. This goes in
// the very last PDE slot (VA 0xFFC00000 - 0xFFFFFFFF). Our HAL
// is currently not using this but it is required since this is
// where the magic PTE for the kernel debugger to map physical pages
// is located.
//
PdePage[1023].PageFrameNumber = BlLoaderBlock->u.Ppc.PdrPage + 2;
PdePage[1023].Valid = 1;
PdePage[1023].Write = 1;
BlLog((LOG_ALL,"HAL PTE page mapped at PdePage[%x] = %x",1023,*(PULONG)&PdePage[1023]));
//
// Within the above Page Table Page, allocate a PTE for
// USER_SHARED_DATA (PcrPage2) at virtual address 0xffffe000. This
// is the second to last page in the address space.
//
PtePage = (PHARDWARE_PTE)AddressFromPage(BlLoaderBlock->u.Ppc.PdrPage + 2);
BlLog((LOG_ALL,"PCR2 PTE page at %x",PtePage));
PtePage[1022].PageFrameNumber = BlLoaderBlock->u.Ppc.PcrPage2;
PtePage[1022].Valid = 1;
PtePage[1022].Dirty = 1; // allow user read, kernel read/write
PtePage[1022].Change = 1;
PtePage[1022].Reference = 1;
BlLog((LOG_ALL,"PCR2 PTE mapped at PtePage[%x] = %x",1022,*(PULONG)&PtePage[1022]));
//
// If we're paging the kernel, find free memory to use for page
// table pages.
//
if (PageKernel) {
FreePage = 0;
NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
NextDescriptor = CONTAINING_RECORD(NextEntry,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
if (NextDescriptor->MemoryType == LoaderFree) {
FreeDescriptor = NextDescriptor;
FreePage = FreeDescriptor->BasePage;
NumberFree = FreeDescriptor->PageCount;
break;
}
NextEntry = NextEntry->Flink;
}
if (FreePage == 0) {
BlLog((LOG_ALL,"Unable to find free memory for PTE pages"));
return ENOMEM;
}
BlLog((LOG_ALL,"%x PTE pages available at %x",NumberFree,FreePage));
}
//
// If we're paging the kernel, then for each page used to load boot
// code/data, set up a PTE. Do not do this for pages that reside in
// KSEG0. If we're not paging the kernel, find the highest page
// used to load boot code/data, so that we know how to set up the
// KSEG0 BAT.
//
Kseg0Pages = PageFromAddress(BlLoaderBlock->u.Ppc.Kseg0Top);
HighestKseg0Page = 0;
NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
NextDescriptor = CONTAINING_RECORD(NextEntry,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
if ((NextDescriptor->MemoryType != LoaderExceptionBlock) &&
(NextDescriptor->MemoryType != LoaderSystemBlock) &&
(NextDescriptor->MemoryType != LoaderFree) &&
(NextDescriptor->MemoryType != LoaderBad) &&
(NextDescriptor->MemoryType != LoaderLoadedProgram) &&
(NextDescriptor->MemoryType != LoaderFirmwareTemporary) &&
(NextDescriptor->MemoryType != LoaderFirmwarePermanent) &&
(NextDescriptor->MemoryType != LoaderOsloaderStack) &&
(NextDescriptor->MemoryType != LoaderSpecialMemory)) {
HighPage = NextDescriptor->BasePage + NextDescriptor->PageCount;
if (PageKernel) {
if (NextDescriptor->BasePage >= Kseg0Pages) {
BlLog((LOG_ALL,
"Setting up mapping for pages[%x:%x]",
NextDescriptor->BasePage,
HighPage-1));
for (Page = NextDescriptor->BasePage; Page < HighPage; Page++) {
Entry = AddressFromPage(Page) >> PDI_SHIFT;
if (PdePage[Entry].Valid == 0) {
PtePage = (PHARDWARE_PTE)AddressFromPage(FreePage);
RtlZeroMemory(PtePage, PAGE_SIZE);
PdePage[Entry].PageFrameNumber = FreePage;
PdePage[Entry].Valid = 1;
PdePage[Entry].Write = 1;
BlLog((LOG_ALL,
"PTE page mapped at PdePage[%x] = %x",
Entry,
*(PULONG)&PdePage[Entry]));
if (NextFreePage(&FreePage, &NumberFree, &FreeDescriptor) != ESUCCESS) {
BlLog((LOG_ALL,"Unable to find free memory for PTE pages"));
return ENOMEM;
}
} else {
PtePage = (PHARDWARE_PTE)AddressFromPage(PdePage[Entry].PageFrameNumber);
}
Entry = Page & ((1 << (PDI_SHIFT-PTI_SHIFT)) - 1);
PtePage[Entry].PageFrameNumber = Page;
PtePage[Entry].Valid = 1;
PtePage[Entry].Write = 1;
//BlLog((LOG_ALL,
// "Page %x mapped at PtePage[%x] (%x) = %x",
// Page,
// Entry,
// &PtePage[Entry],
// *(PULONG)&PtePage[Entry]));
}
//BlLogWaitForKeystroke();
}
} else { // not paging the kernel
HighestKseg0Page = HighPage;
}
}
NextEntry = NextEntry->Flink;
}
if (PageKernel) {
//
// Account for pages taken from FreeDescriptor for page table pages.
//
if (NumberFree != FreeDescriptor->PageCount) {
BlLog((LOG_ALL,"Generating FirmwarePermanent descriptor for %x pages at %x taken for PTE pages",FreeDescriptor->PageCount-NumberFree,FreeDescriptor->BasePage));
BlGenerateDescriptor(FreeDescriptor,
LoaderFirmwarePermanent,
FreeDescriptor->BasePage,
FreeDescriptor->PageCount - NumberFree);
}
} else {
//
// We're not paging the kernel. Tell the kernel how big the
// KSEG0 BAT needs to be -- it must cover all boot code/data.
// (If we're paging the kernel, BlPpcMemoryInitialize already
// set the KSEG0 BAT size.)
//
Kseg0Pages = PAGES(BlLoaderBlock->u.Ppc.MinimumBlockLength);
while (Kseg0Pages < HighestKseg0Page) {
Kseg0Pages <<= 1;
}
BlLoaderBlock->u.Ppc.Kseg0Top = AddressFromPage(Kseg0Pages);
BlLog((LOG_ALL,"Highest KSEG0 page: %x, KSEG0 pages: %x",HighestKseg0Page,Kseg0Pages));
}
BlLogWaitForKeystroke();
return(ESUCCESS);
}
ARC_STATUS
ReorganizeEisaConfigurationTree(
IN PCONFIGURATION_COMPONENT_DATA RootEntry
)
/*++
Routine Description:
This routine sorts the eisa adapter configuration tree based on
the slot the component resided in. It also creates a new configuration
data for EisaAdapter component to contain ALL the eisa slot and function
information. Finally the Eisa tree will be wiped out.
Arguments:
RootEntry - Supplies a pointer to a EisaAdapter component. This is
the root of Eisa adapter tree.
Returns:
ESUCCESS is returned if the reorganization is successfully complete.
Otherwise, an unsuccessful status is returned.
--*/
{
PCONFIGURATION_COMPONENT_DATA CurrentEntry, PreviousEntry;
PCONFIGURATION_COMPONENT_DATA EntryFound, EntryFoundPrevious;
PCONFIGURATION_COMPONENT_DATA AttachedEntry, DetachedList;
ARC_STATUS Status;
//
// We sort the direct children of EISA adapter tree based on the slot
// they reside in. Only the direct children of EISA root need to be
// sorted.
// Note the "Key" field of CONFIGURATION_COMPONENT contains
// EISA slot number.
//
//
// First, detach all the children from EISA root.
//
AttachedEntry = NULL; // Child list of Eisa root
DetachedList = RootEntry->Child; // Detached child list
PreviousEntry = NULL;
while (DetachedList) {
//
// Find the component with the smallest slot number from detached
// list.
//
EntryFound = DetachedList;
EntryFoundPrevious = NULL;
CurrentEntry = DetachedList->Sibling;
PreviousEntry = DetachedList;
while (CurrentEntry) {
if (CurrentEntry->ComponentEntry.Key <
EntryFound->ComponentEntry.Key) {
EntryFound = CurrentEntry;
EntryFoundPrevious = PreviousEntry;
}
PreviousEntry = CurrentEntry;
CurrentEntry = CurrentEntry->Sibling;
}
//
// Remove the component from the detached child list.
// If the component is not the head of the detached list, we remove it
// by setting its previous entry's sibling to the component's sibling.
// Otherwise, we simply update Detach list head to point to the
// component's sibling.
//
if (EntryFoundPrevious) {
EntryFoundPrevious->Sibling = EntryFound->Sibling;
} else {
DetachedList = EntryFound->Sibling;
}
//
// Attach the component to the child list of Eisa root.
//
if (AttachedEntry) {
AttachedEntry->Sibling = EntryFound;
} else {
RootEntry->Child = EntryFound;
}
AttachedEntry = EntryFound;
AttachedEntry->Sibling = NULL;
}
//
// Finally, we traverse the Eisa tree to collect all the Eisa slot
// and function information and put it to the configuration data of
// Eisa root entry.
//
Status = CreateEisaConfigurationData(RootEntry);
//
// Wipe out all the children of EISA tree.
// NOTE shielint - For each child component, we should convert its
// configuration data from EISA format to our CM_ format.
//
RootEntry->Child = NULL;
return(Status);
}
ARC_STATUS
CreateEisaConfigurationData (
IN PCONFIGURATION_COMPONENT_DATA RootEntry
)
/*++
Routine Description:
This routine traverses Eisa configuration tree to collect all the
slot and function information and attaches it to the configuration data
of Eisa RootEntry.
Note that this routine assumes that the EISA tree has been sorted based
on the slot number.
Arguments:
RootEntry - Supplies a pointer to the Eisa configuration
component entry.
Returns:
ESUCCESS is returned if the new EisaAdapter configuration data is
successfully created. Otherwise, an unsuccessful status is returned.
--*/
{
ULONG DataSize, NextSlot = 0, i;
PCM_PARTIAL_RESOURCE_LIST Descriptor;
PCONFIGURATION_COMPONENT Component;
PCONFIGURATION_COMPONENT_DATA CurrentEntry;
PUCHAR DataPointer;
CM_EISA_SLOT_INFORMATION EmptySlot =
{EISA_EMPTY_SLOT, 0, 0, 0, 0, 0, 0, 0};
//
// Remove the configuration data of Eisa Adapter
//
RootEntry->ConfigurationData = NULL;
RootEntry->ComponentEntry.ConfigurationDataLength = 0;
//
// If the EISA stree contains valid slot information, i.e.
// root has children attaching to it.
//
if (RootEntry->Child) {
//
// First find out how much memory is needed to store EISA config
// data.
//
DataSize = sizeof(CM_PARTIAL_RESOURCE_LIST);
CurrentEntry = RootEntry->Child;
while (CurrentEntry) {
Component = &CurrentEntry->ComponentEntry;
if (CurrentEntry->ConfigurationData) {
if (Component->Key > NextSlot) {
//
// If there is any empty slot between current slot
// and previous checked slot, we need to count the
// space for the empty slots.
//
DataSize += (Component->Key - NextSlot) *
sizeof(CM_EISA_SLOT_INFORMATION);
}
DataSize += Component->ConfigurationDataLength + 1 -
CONFIGURATION_DATA_HEADER_SIZE;
NextSlot = Component->Key + 1;
}
CurrentEntry = CurrentEntry->Sibling;
}
//
// Allocate memory from heap to hold the EISA configuration data.
//
DataPointer = BlAllocateHeap(DataSize);
if (DataPointer == NULL) {
return ENOMEM;
} else {
RootEntry->ConfigurationData = DataPointer;
RootEntry->ComponentEntry.ConfigurationDataLength = DataSize;
}
//
// Create a CM_PARTIAL_RESOURCE_LIST for the new configuration data.
//
Descriptor = (PCM_PARTIAL_RESOURCE_LIST)DataPointer;
Descriptor->Version = 0;
Descriptor->Revision = 0;
Descriptor->Count = 1;
Descriptor->PartialDescriptors[0].Type = CmResourceTypeDeviceSpecific;
Descriptor->PartialDescriptors[0].ShareDisposition = 0;
Descriptor->PartialDescriptors[0].Flags = 0;
Descriptor->PartialDescriptors[0].u.DeviceSpecificData.Reserved1 = 0;
Descriptor->PartialDescriptors[0].u.DeviceSpecificData.Reserved2 = 0;
Descriptor->PartialDescriptors[0].u.DeviceSpecificData.DataSize =
DataSize - sizeof(CM_PARTIAL_RESOURCE_LIST);
//
// Visit each child of the RootEntry and copy its ConfigurationData
// to the new configuration data area.
// N.B. The configuration data includes a slot information and zero
// or more function information. The slot information provided
// by ARC eisa data does not have "ReturnedCode" as defined in
// our CM_EISA_SLOT_INFORMATION. This code will convert the
// standard EISA slot information to our CM format.
//
CurrentEntry = RootEntry->Child;
DataPointer += sizeof(CM_PARTIAL_RESOURCE_LIST);
NextSlot = 0;
while (CurrentEntry) {
Component = &CurrentEntry->ComponentEntry;
if (CurrentEntry->ConfigurationData) {
//
// Check if there is any empty slot. If yes, create empty
// slot information. Also make sure the config data area is
// big enough.
//
if (Component->Key > NextSlot) {
for (i = NextSlot; i < CurrentEntry->ComponentEntry.Key; i++ ) {
*(PCM_EISA_SLOT_INFORMATION)DataPointer = EmptySlot;
DataPointer += sizeof(CM_EISA_SLOT_INFORMATION);
}
}
*DataPointer++ = 0; // See comment above
RtlMoveMemory( // Skip config data header
DataPointer,
(PUCHAR)CurrentEntry->ConfigurationData +
CONFIGURATION_DATA_HEADER_SIZE,
Component->ConfigurationDataLength -
CONFIGURATION_DATA_HEADER_SIZE
);
DataPointer += Component->ConfigurationDataLength -
CONFIGURATION_DATA_HEADER_SIZE;
NextSlot = Component->Key + 1;
}
CurrentEntry = CurrentEntry->Sibling;
}
}
return(ESUCCESS);
}
ARC_STATUS
BlPpcMemoryInitialize(
VOID
)
/*++
Routine Description:
Called by BlPpcInitialize to do platform-specific memory initialization.
This routine allocates all blocks that need to be in KSEG0 (mapped by a
BAT register from virtual 0x80000000 to physical 0). It also changes
MemoryLoadedProgram blocks above 8 MB to MemoryFree. This routine also
makes the decision about whether the kernel and other boot code is going
to be paged.
Arguments:
None.
Return Value:
None.
--*/
{
ARC_STATUS Status;
ULONG HighestKseg0Page;
ULONG TotalPages;
ULONG ContiguousLowMemoryPages;
ULONG HighPage;
PLIST_ENTRY NextEntry;
PMEMORY_ALLOCATION_DESCRIPTOR NextDescriptor;
PMEMORY_ALLOCATION_DESCRIPTOR PreviousDescriptor;
PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor;
ULONG Kseg0Length;
ULONG Kseg0Pages;
ULONG Kseg0PagesAdded;
PCHAR EnvironmentVariable;
//
// Determine the amount of memory in the system, as well as the
// amount of contiguous low memory at physical address 0.
//
// N.B. The ContiguousLowMemoryPages calculation depends on
// the memory descriptor list being sorted.
//
TotalPages = 0;
ContiguousLowMemoryPages = 0;
for (NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
NextEntry != &BlLoaderBlock->MemoryDescriptorListHead;
NextEntry = NextEntry->Flink) {
NextDescriptor = CONTAINING_RECORD(NextEntry,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
TotalPages += NextDescriptor->PageCount;
if (NextDescriptor->BasePage == ContiguousLowMemoryPages) {
ContiguousLowMemoryPages += NextDescriptor->PageCount;
}
}
//
// If there is enough memory in the system, don't page the kernel
// and the boot drivers -- use the KSEG0 BAT to cover all of it.
//
// The PAGEKERNEL environment variable can be used to override
// this calculation. If the variable doesn't exist, the
// calculation is used. If the variable exists and is equal to
// "FALSE", the kernel is not paged. If the variable exists and
// is not equal to "FALSE", the kernel is paged.
//
EnvironmentVariable = ArcGetEnvironmentVariable("PAGEKERNEL");
if (EnvironmentVariable != NULL) {
PageKernel = (BOOLEAN)(_stricmp(EnvironmentVariable, "FALSE") != 0);
} else {
PageKernel = (BOOLEAN)(TotalPages < PAGED_KERNEL_MEMORY_LIMIT);
}
//PageKernel = FALSE;
//
// Look for memory blocks marked LoadedProgram that are above 8 MB
// and below 256 MB. If there are any, that means that we are
// running with new firmware that maps free memory above 8 MB and
// marks it as LoadedProgram, and we can treat all such memory as
// free. Old firmware marks all memory above 8 MB, free or not, as
// FirmwareTemporary.
//
// N.B. Because of the way the original firmware/system interface
// was designed, new firmware cannot mark free memory above 8
// MB as free, because the old loader might use such memory,
// and when the old kernel mapped BAT0 to cover just the low 8
// MB, that memory would become inaccessible.
//
// N.B. We ignore memory above 256 MB because we only want to use
// one segment register to map boot code.
//
// N.B. If we're going to use the KSEG0 BAT to map the kernel, then
// we must limit our search for LoadedProgram blocks to the
// lower of the processor's BAT size limit and the amount of
// contiguous low memory.
//
if (PageKernel) {
Kseg0Pages = 256*MBpages;
} else {
Kseg0Pages = MIN(ContiguousLowMemoryPages,
PAGES(BlLoaderBlock->u.Ppc.MaximumBlockLength));
}
NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
NextDescriptor = CONTAINING_RECORD(NextEntry,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
if (NextDescriptor->BasePage >= Kseg0Pages) {
break;
}
if ((NextDescriptor->MemoryType == LoaderLoadedProgram) &&
(NextDescriptor->BasePage >= 8*MBpages)) {
//
// We have found a LoadedProgram block above 8 MB. If
// the block ends below 256 MB, simply mark the block as
// free, and remove the descriptor from the memory list and
// reinsert it, to allow the block to be merged with the
// preceeding block, if possible. If the block crosses 256
// MB, split the lower part of the block into a separate
// free block, leaving the upper part marked as
// LoadedProgram.
//
if ((NextDescriptor->BasePage + NextDescriptor->PageCount) <= Kseg0Pages) {
NextDescriptor->MemoryType = LoaderFree;
BlRemoveDescriptor(NextDescriptor);
BlInsertDescriptor(NextDescriptor);
} else {
//
// The descriptor crosses 256 MB. If the previous
// descriptor describes free memory (a likely scenario),
// then we can move the low part of the block into that
// descriptor.
//
Kseg0PagesAdded = Kseg0Pages - NextDescriptor->BasePage;
PreviousDescriptor = CONTAINING_RECORD(NextDescriptor->ListEntry.Blink,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
if ((&PreviousDescriptor->ListEntry != &BlLoaderBlock->MemoryDescriptorListHead) &&
(PreviousDescriptor->MemoryType == LoaderFree) &&
((PreviousDescriptor->BasePage + PreviousDescriptor->PageCount) ==
NextDescriptor->BasePage)) {
PreviousDescriptor->PageCount += Kseg0PagesAdded;
NextDescriptor->BasePage += Kseg0PagesAdded;
NextDescriptor->PageCount -= Kseg0PagesAdded;
} else {
//
// The previous descriptor does not describe free
// memory, so we need a new descriptor. If
// allocating a descriptor fails, we just don't
// change this block.
//
NewDescriptor = BlAllocateHeap(sizeof(MEMORY_ALLOCATION_DESCRIPTOR));
if (NewDescriptor != NULL) {
NewDescriptor->MemoryType = LoaderFree;
NewDescriptor->BasePage = NextDescriptor->BasePage;
NewDescriptor->PageCount = Kseg0PagesAdded;
NextDescriptor->BasePage += Kseg0PagesAdded;
NextDescriptor->PageCount -= Kseg0PagesAdded;
BlInsertDescriptor(NewDescriptor);
}
}
}
}
NextEntry = NextEntry->Flink;
}
#define IBAT_BASE 528
#define DBAT_BASE 536
BlLog((LOG_ALL,"IBAT0U: %08lx IBAT0L: %08lx IBAT1U: %08lx IBAT1L: %08lx",
__sregister_get(IBAT_BASE+0),
__sregister_get(IBAT_BASE+1),
__sregister_get(IBAT_BASE+2),
__sregister_get(IBAT_BASE+3)));
BlLog((LOG_ALL,"IBAT2U: %08lx IBAT2L: %08lx IBAT3U: %08lx IBAT3L: %08lx",
__sregister_get(IBAT_BASE+4),
__sregister_get(IBAT_BASE+5),
__sregister_get(IBAT_BASE+6),
__sregister_get(IBAT_BASE+7)));
BlLog((LOG_ALL,"DBAT0U: %08lx DBAT0L: %08lx DBAT1U: %08lx DBAT1L: %08lx",
__sregister_get(DBAT_BASE+0),
__sregister_get(DBAT_BASE+1),
__sregister_get(DBAT_BASE+2),
__sregister_get(DBAT_BASE+3)));
BlLog((LOG_ALL,"DBAT2U: %08lx DBAT2L: %08lx DBAT3U: %08lx DBAT3L: %08lx",
__sregister_get(DBAT_BASE+4),
__sregister_get(DBAT_BASE+5),
__sregister_get(DBAT_BASE+6),
__sregister_get(DBAT_BASE+7)));
#if DBG
{
ULONG sr[16];
VOID GetSegmentRegisters(ULONG sr[16]);
GetSegmentRegisters(sr);
BlLog((LOG_ALL,"SR0 : %08lx SR1 : %08lx SR2 : %08lx SR3 : %08lx",
sr[0], sr[1], sr[2], sr[3]));
BlLog((LOG_ALL,"SR4 : %08lx SR5 : %08lx SR6 : %08lx SR7 : %08lx",
sr[4], sr[5], sr[6], sr[7]));
BlLog((LOG_ALL,"SR8 : %08lx SR9 : %08lx SR10: %08lx SR11: %08lx",
sr[8], sr[9], sr[10], sr[11]));
BlLog((LOG_ALL,"SR12: %08lx SR13: %08lx SR14: %08lx SR15: %08lx",
sr[12], sr[13], sr[14], sr[15]));
}
#endif
BlLog((LOG_ALL,"SPRG0: %08lx SPRG1: %08lx SPRG2: %08lx SPRG3: %08lx",
__sregister_get(272),
__sregister_get(273),
__sregister_get(274),
__sregister_get(275)));
BlLog((LOG_ALL_W,"SDR1: %08lx",
__sregister_get(25)));
//
// Allow the HPTSIZE environment variable to override the default HPT size.
//
// The format of the translation is decimal-number[k|K|m|M]. If the format
// is incorrect, or if the number is not a valid HPT size, the override is
// silently ignored.
//
if (BlLoaderBlock->u.Ppc.HashedPageTableSize != 0) {
EnvironmentVariable = ArcGetEnvironmentVariable("HPTSIZE");
if (EnvironmentVariable != NULL) {
ULONG NewHptSize = 0;
PUCHAR p = EnvironmentVariable;
//
// Parse the decimal number portion of the string.
//
while ((*p >= '0') && (*p <= '9')) {
NewHptSize = (NewHptSize * 10) + (*p - '0');
p++;
}
//
// Check for a k or m suffix.
//
if ((*p == 'k') || (*p == 'K')) {
NewHptSize = NewHptSize * KB;
p++;
}
if ((*p == 'm') || (*p == 'M')) {
NewHptSize = NewHptSize * MB;
p++;
}
//
// We must be at the end of the string. The number must be a
// power of 2, and it must be a valid HPT size.
//
if ((*p == 0) &&
((NewHptSize & (NewHptSize - 1)) == 0) &&
((NewHptSize >= 64*KB) && (NewHptSize <= 32*MB))) {
//
// Override the default HPT size.
//
BlLoaderBlock->u.Ppc.HashedPageTableSize = PAGES(NewHptSize);
}
}
}
//
// Allocate blocks that must be in KSEG0.
//
Status = AllocateKseg0Blocks( &HighestKseg0Page );
if (Status != ESUCCESS) {
return Status;
}
#if DBG
EnvironmentVariable = ArcGetEnvironmentVariable("HIGHESTFIT");
if (EnvironmentVariable != NULL) {
if (_stricmp(EnvironmentVariable, "TRUE") == 0) {
BlSetAllocationPolicy(BlAllocateHighestFit, BlAllocateHighestFit);
}
}
#endif
//
// If we're going to page the kernel, calculate the amount of low
// memory we need to reserve for KSEG0. HighestKseg0Page-1 tells us
// the highest page actually used by blocks that must be in KSEG0.
// We round this up to the next legal BAT size.
//
// KSEG0 must be at least as big as the level 1 D-cache, because
// the HAL D-cache sweep routines fill the cache from KSEG0.
//
if (PageKernel) {
Kseg0Pages = PAGES(BlLoaderBlock->u.Ppc.MinimumBlockLength);
while (Kseg0Pages < PAGES(BlLoaderBlock->u.Ppc.FirstLevelDcacheSize)) {
Kseg0Pages <<= 1;
}
while (Kseg0Pages < HighestKseg0Page) {
Kseg0Pages <<= 1;
}
Kseg0Length = BYTES(Kseg0Pages);
BlLoaderBlock->u.Ppc.Kseg0Top = AddressFromPage(Kseg0Pages);
BlLog((LOG_ALL,"Highest KSEG0 page: %x, KSEG0 pages: %x",HighestKseg0Page,Kseg0Pages));
//
// KSEG0 must be at least as big as the level 1 D-cache, because
// the HAL D-cache sweep routines fille the cache from KSEG0.
//
//
// Ensure that we don't require a BAT bigger than the processor can
// handle.
//
if (Kseg0Length > BlLoaderBlock->u.Ppc.MaximumBlockLength) {
BlLog((LOG_ALL,"ACK! KSEG0 too big! %x vs. %x",
Kseg0Length,BlLoaderBlock->u.Ppc.MaximumBlockLength));
return ENOMEM;
}
//
// We should have allocated everything from very low memory. At the
// very least, there must not be any holes in the memory that we're
// going to map the KSEG0 BAT to, otherwise we'll have problems with
// speculative execution on 603.
//
if (ContiguousLowMemoryPages < Kseg0Pages) {
BlLog((LOG_ALL,"ACK! Not enough contiguous memory at 0! (%x, need %x)",
ContiguousLowMemoryPages,Kseg0Pages));
return ENOMEM;
}
//
// All remaining free memory in the range of KSEG0 must be marked as
// FirmwareTemporary so that we don't use it during boot. The OS
// will reclaim this memory (and map it outside of KSEG0) after
// booting.
//
NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
NextDescriptor = CONTAINING_RECORD(NextEntry,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
if (NextDescriptor->BasePage >= Kseg0Pages) {
break;
}
if (NextDescriptor->MemoryType == LoaderFree) {
HighPage = NextDescriptor->BasePage + NextDescriptor->PageCount;
HighPage = MIN(HighPage, Kseg0Pages);
BlLog((LOG_ALL,"Changing %x pages at %x to FirmwareTemporary",HighPage-NextDescriptor->BasePage,NextDescriptor->BasePage));
BlGenerateDescriptor(NextDescriptor,
LoaderFirmwareTemporary,
NextDescriptor->BasePage,
HighPage - NextDescriptor->BasePage);
}
NextEntry = NextEntry->Flink;
}
BlLogWaitForKeystroke();
}
BlLogMemoryDescriptors(LOG_ALL_W);
return ESUCCESS;
}
ARC_STATUS
BlPpcInitialize (
VOID
)
{
union {
PVR Pvr;
ULONG Ulong;
} Pvr;
BOOLEAN Is601;
BOOLEAN Is603;
BOOLEAN Is604;
BOOLEAN Is620;
ULONG MinBat;
ULONG MaxBat;
ULONG HptSize;
ULONG DcacheSize;
ULONG DcacheFill;
ULONG IcacheSize;
ULONG IcacheFill;
ULONG TlbSets;
Pvr.Ulong = KeGetPvr();
if (Pvr.Pvr.Version == 1) { // 601
MinBat = 128*KB;
MaxBat = 8*MB;
HptSize = 64*KB;
DcacheSize = 32*KB;
DcacheFill = 64;
IcacheSize = 32*KB;
IcacheFill = 64;
TlbSets = 128;
} else if (Pvr.Pvr.Version == 3) { // 603
MinBat = 128*KB;
MaxBat = 256*MB;
HptSize = 0;
DcacheSize = 8*KB;
DcacheFill = 32;
IcacheSize = 8*KB;
IcacheFill = 32;
TlbSets = 32;
} else if (Pvr.Pvr.Version == 4) { // 604
MinBat = 128*KB;
MaxBat = 256*MB;
HptSize = 64*KB;
DcacheSize = 16*KB;
DcacheFill = 32;
IcacheSize = 16*KB;
IcacheFill = 32;
TlbSets = 64;
} else if (Pvr.Pvr.Version == 6) { // 603+
MinBat = 128*KB;
MaxBat = 256*MB;
HptSize = 0;
DcacheSize = 16*KB;
DcacheFill = 32;
IcacheSize = 16*KB;
IcacheFill = 32;
TlbSets = 32;
} else if (Pvr.Pvr.Version == 7) { // 603++
MinBat = 128*KB;
MaxBat = 256*MB;
HptSize = 0;
DcacheSize = 16*KB;
DcacheFill = 32;
IcacheSize = 16*KB;
IcacheFill = 32;
TlbSets = 32;
} else if (Pvr.Pvr.Version == 8) { // Arthur or 613
MinBat = 128*KB;
MaxBat = 256*MB;
HptSize = 64*KB;
DcacheSize = 32*KB;
DcacheFill = 32;
IcacheSize = 32*KB;
IcacheFill = 32;
TlbSets = 64;
} else if (Pvr.Pvr.Version == 9) { // 604+
MinBat = 128*KB;
MaxBat = 256*MB;
HptSize = 64*KB;
DcacheSize = 32*KB;
DcacheFill = 32;
IcacheSize = 32*KB;
IcacheFill = 32;
TlbSets = 64;
} else if (Pvr.Pvr.Version == 20) { // 620+
MinBat = 128*KB;
MaxBat = 256*MB;
HptSize = 256*KB;
DcacheSize = 32*KB;
DcacheFill = 64;
IcacheSize = 32*KB;
IcacheFill = 64;
TlbSets = 64;
} else {
return EINVAL;
}
BlLoaderBlock->u.Ppc.MinimumBlockLength = MinBat;
BlLoaderBlock->u.Ppc.MaximumBlockLength = MaxBat;
BlLoaderBlock->u.Ppc.HashedPageTableSize = PAGES(HptSize);
BlLoaderBlock->u.Ppc.FirstLevelDcacheSize = DcacheSize;
BlLoaderBlock->u.Ppc.FirstLevelDcacheFillSize = DcacheFill;
BlLoaderBlock->u.Ppc.FirstLevelIcacheSize = IcacheSize;
BlLoaderBlock->u.Ppc.FirstLevelIcacheFillSize = IcacheFill;
BlLoaderBlock->u.Ppc.NumberCongruenceClasses = TlbSets;
BlLoaderBlock->u.Ppc.MajorVersion = 2;
BlLoaderBlock->u.Ppc.MinorVersion = 0;
return BlPpcMemoryInitialize();
}