/* * * Copyright (c) 1995 FirePower Systems, Inc. * Copyright (c) 1994 FirePower Systems Inc. * * $RCSfile: vrload.c $ * $Revision: 1.12 $ * $Date: 1996/04/15 02:55:48 $ * $Locker: $ * * * Module Name: * vrload.c * * Author: * Shin Iwamoto at FirePower Systems Inc. * * History: * 28-Jul-94 Shin Iwamoto at FirePower Systems Inc. * Added for DOS signature of PE in VrLoad(); * 18-Jul-94 Shin Iwamoto at FirePower Systems Inc. * Created. */ #include "veneer.h" #define XXX_MAKE_DESCRIPTOR // // This must be defined in some header file. But for 3.5 it is not defined. // #define IMAGE_FILE_16BIT_MACHINE 0x0040 typedef struct _VR_MEMORY_DESCRIPTOR { struct _VR_MEMORY_DESCRIPTOR *NextEntry; MEMORY_DESCRIPTOR MemoryEntry; } VR_MEMORY_DESCRIPTOR, *PVR_MEMORY_DESCRIPTOR; extern PVR_MEMORY_DESCRIPTOR VrMemoryListOrig; // // Some type definitions. // typedef struct _SECTION_RELOCATION_ENTRY { ULONG FixupValue; ULONG PointerToRelocations; USHORT NumberOfRelocations; } SECTION_RELOCATION_ENTRY, *PSECTION_RELOCATION_ENTRY; // // Some definitions. // // These must be defined in veneer.h or ntimage.h? // #define HEADER_CHAR (IMAGE_FILE_EXECUTABLE_IMAGE | \ IMAGE_FILE_BYTES_REVERSED_LO | \ IMAGE_FILE_32BIT_MACHINE | \ IMAGE_FILE_BYTES_REVERSED_HI) #define HEADER_NOCHAR (IMAGE_FILE_16BIT_MACHINE | \ IMAGE_FILE_DLL) #define OPTIONAL_MAGIC_STD 0x010B // // Section numbers for local relocation entries // #define R_SN_TEXT 0 #define R_SN_DATA 1 #define R_SN_BSS 2 #define R_SN_MAX 3 #define MAX_ARGUMENT (512 - sizeof(ULONG) - 16*sizeof(PUCHAR)) typedef struct _SAVED_ARGUMENTS { ULONG Argc; PUCHAR Argv[16]; UCHAR Arguments[MAX_ARGUMENT]; } SAVED_ARGUMENTS, *PSAVED_ARGUMENTS; STATIC PSAVED_ARGUMENTS SavedArgs; STATIC ULONG VrActualBasePage; STATIC ULONG VrPageCount; // // Function declarations. // ARC_STATUS VrRelocateImage( IN ULONG FileId, IN PSECTION_RELOCATION_ENTRY RelocationTable, IN ULONG NumberOfSections, IN ULONG PointerToSymbolTable ); VOID VrCopyArguments( IN ULONG Argc, IN PCHAR Argv[] ); ARC_STATUS VrGenerateDescriptor( IN PMEMORY_DESCRIPTOR MemoryDescriptor, IN MEMORY_TYPE MemoryType, IN ULONG BasePage, IN ULONG PageCount ); VOID VrResetMemory( VOID ); VOID PxInvoke( IN ULONG EntryAddress, IN ULONG StackAddress, IN ULONG Argc, IN PCHAR Argv[], IN PCHAR Envp[] ); VOID InsertMemDescriptor( IN PVR_MEMORY_DESCRIPTOR MemDescriptor ); /* * Name: VrLoad * * Description: * This function reads a program into memory at a specified address * an;d stores the execution address. * * Arguments: * ImagePath - Supplies a pointer to the path of the file to load. * TopAddress - Supplies the top address of a region of memory into * which the file is to be loaded. * EntryAddress- Supplies a pointer to a variable to receive the entry * point of the image, if defined. * LoaAddress - Supplies a pointer to a variable to receive the low address * of the loaded file. * * Return Value: * ESUCCESS is returned if the specified image file is loaded successfully. * Otherwise, an unsuccessufl status is returned that describes the reason * for failure. * */ ARC_STATUS VrLoad( IN PCHAR ImagePath, IN ULONG TopAddress, OUT PULONG EntryAddress, OUT PULONG LowAddress ) { PSECTION_RELOCATION_ENTRY RelocationTable; IMAGE_DOS_HEADER DosHeader; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER OptionalHeader; PIMAGE_SECTION_HEADER SectionHeader, SHeader; ULONG FileId, NumberOfSections, Count; ULONG ActualBase, ClaimSize, SectionOffset; LARGE_INTEGER SeekPosition; ARC_STATUS Status; LONG NT_Signature; LONG size, i; PCHAR ReadAddr; ULONG ReadSize; debug(VRDBG_LOAD, "VrLoad: Entry - ImagePath: %s TopAddress: %x\n", ImagePath, TopAddress); // // Attempt to open the load file. // if ((Status = VrOpen(ImagePath, ArcOpenReadOnly, &FileId)) != ESUCCESS) { return Status; } // // Read DOS Signature. // if ((Status = VrRead(FileId, &DosHeader, 2, &Count)) != ESUCCESS) { (VOID)VrClose(FileId); return Status; } // // If the file isn't a PE file including DOS header, // it's probably a COFF file. // if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE) { bcopy((char *)&DosHeader, (char *)&FileHeader, 2); ReadAddr = (PCHAR)&FileHeader + 2; ReadSize = IMAGE_SIZEOF_FILE_HEADER - 2; goto DirectCOFF; } // // Read the remainder of DOS header. // if ((Status = VrRead(FileId, (PCHAR)&DosHeader+2, sizeof(DosHeader) - 2, &Count)) != ESUCCESS) { (VOID)VrClose(FileId); return Status; } if (Count != sizeof(DosHeader) - 2) { (VOID)VrClose(FileId); return EBADF; // XXXX } SeekPosition.HighPart = 0; SeekPosition.LowPart = DosHeader.e_lfanew; if (Status = VrSeek(FileId, &SeekPosition, SeekAbsolute)) { (VOID)VrClose(FileId); return EBADF; // XXXX } // // Read NT Signature and confirm it. // if ((Status = VrRead(FileId, &NT_Signature, sizeof(NT_Signature), &Count)) != ESUCCESS) { (VOID)VrClose(FileId); return Status; } if (Count != sizeof(NT_Signature) || NT_Signature != IMAGE_NT_SIGNATURE) { (VOID)VrClose(FileId); return EBADF; // XXXX } ReadAddr = (PCHAR)&FileHeader; ReadSize = IMAGE_SIZEOF_FILE_HEADER; DirectCOFF: // // Read the image header from the file. // if ((Status = VrRead(FileId, ReadAddr, ReadSize, &Count)) != ESUCCESS) { (VOID)VrClose(FileId); return Status; } if (Count != ReadSize) { (VOID)VrClose(FileId); return EBADF; // XXXX } // // Check the header. // if ((FileHeader.Machine != IMAGE_FILE_MACHINE_POWERPC) || ((FileHeader.Characteristics & HEADER_CHAR) != HEADER_CHAR) || ((FileHeader.Characteristics & HEADER_NOCHAR) != 0) ) { (VOID)VrClose(FileId); return ENOEXEC; } // // Read the optional header. // if ((Status = VrRead(FileId, &OptionalHeader, FileHeader.SizeOfOptionalHeader, &Count)) != ESUCCESS) { (VOID)VrClose(FileId); return Status; } if (Count != FileHeader.SizeOfOptionalHeader) { (VOID)VrClose(FileId); return EBADF; // XXXX } // // More check with the optional header. // if (OptionalHeader.Magic != OPTIONAL_MAGIC_STD) { (VOID)VrClose(FileId); return ENOEXEC; } // // If the image cannot be relocated, set the ActualBase to the code // base, and compute the image size by subtracting the code base from // the data base plus the data size. If the image can be relocated, // set ActualBase to the TopAddress minus the image size, compute // image size by adding the code size, initialized data, and // uninitialized data. // if ((FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) != 0) { ActualBase = OptionalHeader.BaseOfCode; ClaimSize = OptionalHeader.BaseOfData + OptionalHeader.SizeOfInitializedData - ActualBase; } else { ClaimSize = OptionalHeader.SizeOfCode + OptionalHeader.SizeOfInitializedData + OptionalHeader.SizeOfUninitializedData; // ActualBase = OptionalHeader.ImageBase; #ifdef XXX_I_KNOW_PE ActualBase = (TopAddress - ClaimSize) & ~(PAGE_SIZE - 1); #else ActualBase = OptionalHeader.ImageBase; ActualBase &= 0x7fffffff; #endif XXX_I_KNOW_PE } // // Allocate and read the section headers. // size = FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER); SectionHeader = (PIMAGE_SECTION_HEADER)malloc(size); if ((Status = VrRead(FileId, (PCHAR)SectionHeader, size, &Count)) != ESUCCESS) { (VOID)VrClose(FileId); return Status; } if (Count != (ULONG) size) { (VOID)VrClose(FileId); return EBADF; // XXXX } // // // NumberOfSections = FileHeader.NumberOfSections; if (strcmp((PCHAR)(SectionHeader[NumberOfSections-1].Name), ".debug") == 0) { NumberOfSections--; ClaimSize -= SectionHeader[NumberOfSections].SizeOfRawData; } // // Allocate the relocation table. // size = NumberOfSections * sizeof(SECTION_RELOCATION_ENTRY); RelocationTable = (PSECTION_RELOCATION_ENTRY) malloc(size); // // Zero the relocation table. // bzero((char *)RelocationTable, size); // // Convert ClaimSize to be page-aligned. // ClaimSize = (ClaimSize + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); // // Convert ActualBase and ClaimSize to be in units of pages instead of // bytes. This is the interface between VrExecute and VrLoad. // VrActualBasePage = (ActualBase & 0x7fffffff) >> PAGE_SHIFT; VrPageCount = ClaimSize >> PAGE_SHIFT; // // Claim memory at specified virtual address // if (claim((void *)ActualBase, ClaimSize) == -1) { fatal("Veneer: Couldn't claim %x bytes of VM at %x\n", ClaimSize, ActualBase); } // // Set output parametes. // *LowAddress = ActualBase; #ifdef XXX_I_KNOW_PE *EntryAddress = ActualBase + (OptionalHeader.AddressOfEntryPoint - OptionalHeader.BaseOfCode); #else *EntryAddress = ActualBase + OptionalHeader.AddressOfEntryPoint; #endif XXX_I_KNOW_PE // // Scan through the sections and either read them into memory or // clear the memory as appropriate. // SectionOffset = 0; for (i = 0, SHeader = SectionHeader; (ULONG) i < NumberOfSections; i++, SHeader++) { ULONG SectionBase; if ((FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) != 0) { SectionBase = SHeader->VirtualAddress; } else { #ifdef XXX_I_KNOW_PE SectionBase = ActualBase + SectionOffset; #else SectionBase = ActualBase + SHeader->VirtualAddress; #endif XXX_I_KNOW_PE (RelocationTable+i)->PointerToRelocations = SHeader->PointerToRelocations; (RelocationTable+i)->NumberOfRelocations = SHeader->NumberOfRelocations; (RelocationTable+i)->FixupValue = SectionBase - SHeader->VirtualAddress; } // // If the section is code or initialized data, then read // the code or data into memory. // if ((SHeader->Characteristics & ( IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA) ) != 0) { SeekPosition.LowPart = SHeader->PointerToRawData; SeekPosition.HighPart = 0; if ((Status = VrSeek(FileId, &SeekPosition, SeekAbsolute)) != ESUCCESS) { break; } if ((Status = VrRead(FileId, (PVOID)SectionBase, SHeader->SizeOfRawData, &Count)) != ESUCCESS) { break; } if (Count != SHeader->SizeOfRawData) { Status = EBADF; // XXXX break; } // // Set the offset of the next section. // SectionOffset += SHeader->SizeOfRawData; } else if ((SHeader->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) != 0) { bzero((PVOID)SectionBase, SHeader->SizeOfRawData); // // Set the offset of the next section. // SectionOffset += SHeader->SizeOfRawData; } } // // If code has to be relocated, do so. // if ((FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) == 0) { if (ActualBase != OptionalHeader.ImageBase) { Status = VrRelocateImage( FileId, RelocationTable, NumberOfSections, FileHeader.PointerToSymbolTable); } } // // Deallocate allocated area and close the file. // free((char*) SectionHeader); free((char*) RelocationTable); (VOID)VrClose(FileId); debug(VRDBG_LOAD, "VrLoad: Exit - EntryAddress: %x LowAddress: %x Status:%d\n", *EntryAddress, *LowAddress, Status); return Status; } /* * Name: VrInvoke * * Description: * This function invokes a previously loaded program. * * Arguments: * EntryAddress- Supplies the execution address of the program to be loaded. * StackAddress- Supplies the stack address that is used to reset the stack * pointer before the program is invoked. * Argc - Supplies the argument count for the program. * Argv - Supplies a pointer to the argument list for the program. * Envp - Supplies a pointer to the environment for the program. * * Return Value: * ESUCCESS is returned if the address is invalid. * EFAULT indicates an invalid address. * */ ARC_STATUS VrInvoke( IN ULONG EntryAddress, IN ULONG StackAddress, IN ULONG Argc, IN PCHAR Argv[], IN PCHAR Envp[] ) { // // Check for aligend address. // if ((EntryAddress & 0x3) == 0 && (StackAddress & 0x3) == 0) { #ifdef notdef free(VrDescriptorMemory); VrMemoryListOrig = (PVR_MEMORY_DESCRIPTOR)NULL; #endif // notdef PxInvoke(EntryAddress, StackAddress, Argc, Argv, Envp); } else { return EFAULT; } return ESUCCESS; } /* * Name: VrExecute * * Description: * This function reads the program specified by ImagePath into memory * and then starts the program. If the loaded program returns, then * control returns to the platform firmware, not to the caller. * * Arguments: * ImagePath - Supplies a pointer to the pathname of the program * to be loaded. * Argc - Supplies the argument count for the program. * Argv - Supplies a pointer to the argument list for the program. * Envp - Supplies a pointer to the environment for the program. * * Return Value: * ESUCCESS is returned if the address is invalid. * EFAULT indicates an invalid address. * */ ARC_STATUS VrExecute( IN PCHAR ImagePath, IN ULONG Argc, IN PCHAR Argv[], IN PCHAR Envp[] ) { ARC_STATUS Status; PMEMORY_DESCRIPTOR MemoryDescriptor; ULONG BottomAddress; CHAR TempPath[256]; PULONG TransferRoutine; if (strlen(ImagePath) >= sizeof(TempPath)) { return ENAMETOOLONG; } // // Copy the Arguments to a safe place as they can be in the running // program space which can be overwritten by the program about // to be loaded. // (VOID)VrCopyArguments(Argc, Argv); strcpy(TempPath, ImagePath); // // Reinitialize the memory descriptors // VrResetMemory(); // // Look for a piece of free memory. // MemoryDescriptor = VrGetMemoryDescriptor(NULL); while (MemoryDescriptor != NULL ) { // // If the memory is at least 4 megabytes and is free attempt to // load the program. // if ((MemoryDescriptor->MemoryType == MemoryFree) && (MemoryDescriptor->PageCount >= 1024)) { // // Set the top address to the top of the descriptor. // Status = VrLoad(TempPath, ((MemoryDescriptor->BasePage + MemoryDescriptor->PageCount) << PAGE_SHIFT), (PULONG)&TransferRoutine, &BottomAddress); if (Status == ESUCCESS) { // // Find the actual area of memory that was used, and generate // a descriptor for it. Also, claim the according memory // from OpenFirmware. // #ifdef XXX_MAKE_DESCRIPTOR MemoryDescriptor = VrGetMemoryDescriptor(NULL); while (MemoryDescriptor != NULL) { if ((MemoryDescriptor->MemoryType == MemoryFree) && (VrActualBasePage >= MemoryDescriptor->BasePage) && ((VrActualBasePage + VrPageCount) <= (MemoryDescriptor->BasePage + MemoryDescriptor->PageCount)) ) { break; } MemoryDescriptor = VrGetMemoryDescriptor(MemoryDescriptor); } if (MemoryDescriptor != NULL) { Status = VrGenerateDescriptor(MemoryDescriptor, #ifdef EXEC_MEM_TO_LOADED MemoryLoadedProgram, #else MemoryFirmwareTemporary, #endif // EXEC_MEM_TO_LOADED VrActualBasePage, VrPageCount); if (Status != ESUCCESS) { return Status; } #endif // XXX_MAKE_DESCRIPTOR Status = VrInvoke((ULONG)TransferRoutine, BottomAddress, SavedArgs->Argc, SavedArgs->Argv, Envp ); #ifdef EXEC_MEM_TO_LOADED #else MemoryDescriptor->MemoryType = MemoryLoadedProgram; #endif // EXEC_MEM_TO_LOADED return Status; #ifdef XXX_MAKE_DESCRIPTOR } #endif // XXX_MAKE_DESCRIPTOR } if (Status != ENOMEM) { return Status; } } MemoryDescriptor = VrGetMemoryDescriptor(MemoryDescriptor); } return ENOMEM; } /* * Name: VrLoadInitialize * * Description: * This routine initializes the firmware load services. * * Arguments: * None. * * Return Value: * None. * */ VOID VrLoadInitialize( VOID ) { debug(VRDBG_ENTRY, "VrLoadInitialize BEGIN....\n"); (PARC_LOAD_ROUTINE) SYSTEM_BLOCK->FirmwareVector[LoadRoutine] = VrLoad; (PARC_INVOKE_ROUTINE) SYSTEM_BLOCK->FirmwareVector[InvokeRoutine] = VrInvoke; (PARC_EXECUTE_ROUTINE) SYSTEM_BLOCK->FirmwareVector[ExecuteRoutine] = VrExecute; SavedArgs = new(SAVED_ARGUMENTS); debug(VRDBG_ENTRY, "VrLoadInitialize ....END\n"); } /* * Name: VrRelocateImage * * Description: * This function relocates an image file that was not loaded into memory * at the prefered address. * * Arguments: * FileId - Supplies the file identifier for the image file. * RelocationTable * - Supplies a pointer to a table of section relocation info. * * Return Value: * ESUCCESS is returned in the scan if\s successful. Otherwise, return * an unsuccessful status. * */ STATIC ARC_STATUS VrRelocateImage( IN ULONG FileId, IN PSECTION_RELOCATION_ENTRY RelocationTable, IN ULONG NumberOfSections, IN ULONG PointerToSymbolTable ) { IMAGE_RELOCATION RelocationEntry; IMAGE_SYMBOL ImageSymbol; LARGE_INTEGER SeekPosition; ULONG Section, Index, Count, Offset; PULONG FixupAddress; ARC_STATUS Status; // // Read the relocation table for each section. // for (Section = 0; Section < NumberOfSections; Section++) { for (Index = 0; Index < RelocationTable[Section].NumberOfRelocations; Index++) { if (Index == 0) { SeekPosition.LowPart = RelocationTable[Section].PointerToRelocations; SeekPosition.HighPart = 0; if ((Status = VrSeek(FileId, &SeekPosition, SeekAbsolute)) != ESUCCESS) { return Status; } } if ((Status = VrRead(FileId, (PCHAR)&RelocationEntry, sizeof(RelocationEntry), &Count)) != ESUCCESS) { return Status; } if (Count != sizeof(RelocationEntry)) { return EBADF; } // // Get the address for the fixup. // FixupAddress = (PULONG)RelocationEntry.VirtualAddress + RelocationTable[Section].FixupValue; // // Read the symbol table. // SeekPosition.LowPart = PointerToSymbolTable + RelocationEntry.SymbolTableIndex * sizeof(IMAGE_SYMBOL); if ((Status = VrRead(FileId, (PCHAR)&ImageSymbol, sizeof(ImageSymbol), &Count)) != ESUCCESS) { return Status; } if (Count != sizeof(ImageSymbol)) { return EBADF; } // // Apply the fixup. // if (ImageSymbol.StorageClass != IMAGE_SYM_CLASS_EXTERNAL) { Offset = RelocationTable[ImageSymbol.SectionNumber].FixupValue; } else { Offset = 0; } switch (RelocationEntry.Type) { // // Absolute - no fixup required. // case IMAGE_REL_PPC_ABSOLUTE: break; // // 32-bit address - relocate the entire address. // case IMAGE_REL_PPC_ADDR32: *FixupAddress += (ULONG)Offset; break; // // 26-bit address, 26-bit PC-relative offset // case IMAGE_REL_PPC_ADDR24: case IMAGE_REL_PPC_REL24: *FixupAddress = ((*FixupAddress) & 0xfc000003) + ((*FixupAddress) & 0x03fffffc + (Offset << 2)) & 0x03fffffc; break; // // 16-bit address, 16-bit offset from TOC base // case IMAGE_REL_PPC_ADDR16: case IMAGE_REL_PPC_TOCREL16: *FixupAddress = ((*FixupAddress) & 0xffff0000) + ((*FixupAddress) & 0x0000ffff + Offset) & 0x0000ffff; break; // // 14-bit address, 14-bit PC-relative offset, // 14-bit offset from TOC base // case IMAGE_REL_PPC_ADDR14: case IMAGE_REL_PPC_REL14: case IMAGE_REL_PPC_TOCREL14: *FixupAddress = ((*FixupAddress) & 0xffff0003) + ((*FixupAddress) & 0x0000fffc + (Offset << 2)) & 0x0000fffc; break; default: fatal("Veneer: unknown relocation type %d\n", RelocationEntry.Type); } } } return ESUCCESS; } /* * Name: VrCopyArguments * * Description: * This routine copies the supplied arguments into the Veneer space. * * Arguments: * Argc, Argv - Supply the arguments to be copied. * * Return Value: * None. * */ STATIC VOID VrCopyArguments( IN ULONG Argc, IN PCHAR Argv[] ) { PUCHAR Source, Destination; ULONG Index; SavedArgs->Argc = Argc; Destination = &SavedArgs->Arguments[0]; for (Index = 0; Index < Argc; Index++) { Source = Argv[Index]; SavedArgs->Argv[Index] = Destination; while (*Destination++ = *Source++) ; } } /* * Name: VrResetMemory * * Description: * This loops through and clears all of the appropriate memory, * releasing the memory to OpenFirmware, and then calls VrCreateMemory * to reset the memory descriptors. * * Arguments: * None. * * Return Value: * None. * */ VOID VrResetMemory( VOID ) { PMEMORY_DESCRIPTOR MemoryDescriptor; PVR_MEMORY_DESCRIPTOR CurDesc, FreeDesc; // // Release all memory not used by the firmware. // MemoryDescriptor = VrGetMemoryDescriptor(NULL); while (MemoryDescriptor != NULL) { #ifdef notdef DisplayMemoryDescriptor(MemoryDescriptor); #endif // notdef if ((MemoryDescriptor->MemoryType == MemoryLoadedProgram) || (MemoryDescriptor->MemoryType == MemoryFreeContiguous)) { bzero((PVOID) (MemoryDescriptor->BasePage << PAGE_SHIFT), (MemoryDescriptor->PageCount << PAGE_SHIFT)); OFRelease((PVOID)(MemoryDescriptor->BasePage << PAGE_SHIFT), (MemoryDescriptor->PageCount << PAGE_SHIFT)); } MemoryDescriptor = VrGetMemoryDescriptor(MemoryDescriptor); } CurDesc = VrMemoryListOrig; while(CurDesc != NULL) { FreeDesc = CurDesc; CurDesc = CurDesc->NextEntry; free((char*)FreeDesc); } VrMemoryListOrig = (PVR_MEMORY_DESCRIPTOR) NULL; VrCreateMemoryDescriptors(); } /* * Name: VrGenerateDescriptor * * Description: * This routine allocates a new memory descriptor to describe the * specified region of memory. * * 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: * */ ARC_STATUS VrGenerateDescriptor( IN PMEMORY_DESCRIPTOR MemoryDescriptor, IN MEMORY_TYPE MemoryType, IN ULONG BasePage, IN ULONG PageCount ) { PVR_MEMORY_DESCRIPTOR MemDescriptor, NewDescriptor; ULONG Offset; MemDescriptor = (PVR_MEMORY_DESCRIPTOR) MemoryDescriptor; // // Claim the memory from OpenFirmware. // if ((claim((void *)(BasePage << PAGE_SHIFT), PageCount << PAGE_SHIFT)) == -1) { return ENOMEM; } // // 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 - MemDescriptor->MemoryEntry.BasePage; if ((Offset == 0) && (PageCount == MemDescriptor->MemoryEntry.PageCount)) { // // The specified region totally consumes the free region. // MemDescriptor->MemoryEntry.MemoryType = MemoryType; } else { // // A memory descriptor must be generated to describe the allocated // memory. // NewDescriptor = new(VR_MEMORY_DESCRIPTOR); NewDescriptor->MemoryEntry.MemoryType = MemoryType; NewDescriptor->MemoryEntry.BasePage = BasePage; NewDescriptor->MemoryEntry.PageCount = PageCount; // // Insert Memory Descriptor List. // InsertMemDescriptor(NewDescriptor); // // Determine whether an additional memory descriptor must be generated. // if (BasePage == MemDescriptor->MemoryEntry.BasePage) { MemDescriptor->MemoryEntry.BasePage += PageCount; MemDescriptor->MemoryEntry.PageCount -= PageCount; } else { if ((Offset + PageCount) == (MemDescriptor->MemoryEntry.BasePage + MemDescriptor->MemoryEntry.PageCount)) { // // The specified region lies at the end of the free region. // MemDescriptor->MemoryEntry.PageCount -= PageCount; } else { // // The specified region lies in the middle of the free region. // Another memory descriptor must be generated. // NewDescriptor = new(VR_MEMORY_DESCRIPTOR); NewDescriptor->MemoryEntry.MemoryType = MemoryFree; NewDescriptor->MemoryEntry.BasePage = BasePage + PageCount; NewDescriptor->MemoryEntry.PageCount = MemDescriptor->MemoryEntry.PageCount - PageCount - Offset; // // Insert Memory Descriptor List. // InsertMemDescriptor(NewDescriptor); MemDescriptor->MemoryEntry.PageCount = Offset; } } } return ESUCCESS; } VOID InsertMemDescriptor( IN PVR_MEMORY_DESCRIPTOR MemDescriptor ) { PVR_MEMORY_DESCRIPTOR Entry; for (Entry = VrMemoryListOrig; Entry; Entry = Entry->NextEntry) { if ((Entry->MemoryEntry.BasePage < MemDescriptor->MemoryEntry.BasePage) && ((Entry->NextEntry == NULL) || (Entry->NextEntry->MemoryEntry.BasePage > MemDescriptor->MemoryEntry.BasePage))) { MemDescriptor->NextEntry = Entry->NextEntry; Entry->NextEntry = MemDescriptor; break; } } }