1036 lines
24 KiB
C
1036 lines
24 KiB
C
/*
|
|
*
|
|
* 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;
|
|
}
|
|
}
|
|
}
|