mirror of https://github.com/lianthony/NT4.0
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.
1043 lines
28 KiB
1043 lines
28 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
fwload.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the ARC software loadable functions.
|
|
|
|
Author:
|
|
|
|
Lluis Abello (lluis) 19-Sep-1991
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "fwp.h"
|
|
#include "string.h"
|
|
#include "ntimage.h"
|
|
#include "selftest.h"
|
|
#include "fwstring.h"
|
|
|
|
extern BOOLEAN FirstLoadedProgram;
|
|
|
|
VOID
|
|
FwpRestart(
|
|
);
|
|
|
|
//
|
|
// Declare external variables.
|
|
//
|
|
|
|
extern BOOLEAN BreakAfterLoad;
|
|
|
|
#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 variables.
|
|
//
|
|
|
|
PSAVED_ARGUMENTS PSavedArgs;
|
|
ULONG FwTemporaryStack;
|
|
ULONG FwActualBasePage;
|
|
ULONG FwPageCount;
|
|
BOOLEAN MatchedReflo;
|
|
|
|
ARC_STATUS
|
|
FwExecute(
|
|
IN PCHAR Path,
|
|
IN ULONG Argc,
|
|
IN PCHAR Argv[],
|
|
IN PCHAR Envp[]
|
|
);
|
|
|
|
|
|
//
|
|
// s_flags values
|
|
//
|
|
|
|
#define STYP_REG 0x00000000
|
|
#define STYP_TEXT 0x00000020
|
|
#define STYP_INIT 0x80000000
|
|
#define STYP_RDATA 0x00000100
|
|
#define STYP_DATA 0x00000040
|
|
#define STYP_LIT8 0x08000000
|
|
#define STYP_LIT4 0x10000000
|
|
#define STYP_SDATA 0x00000200
|
|
#define STYP_SBSS 0x00000080
|
|
#define STYP_BSS 0x00000400
|
|
#define STYP_LIB 0x40000000
|
|
#define STYP_UCODE 0x00000800
|
|
#define S_NRELOC_OVFL 0x20000000
|
|
|
|
//
|
|
// Section numbers for local relocation entries
|
|
//
|
|
|
|
#define R_SN_TEXT 1
|
|
#define R_SN_INIT 7
|
|
#define R_SN_RDATA 2
|
|
#define R_SN_DATA 3
|
|
#define R_SN_SDATA 4
|
|
#define R_SN_SBSS 5
|
|
#define R_SN_BSS 6
|
|
#define R_SN_LIT8 8
|
|
#define R_SN_LIT4 9
|
|
#define R_SN_MAX 10
|
|
|
|
typedef struct _MIPS_RELOCATION_TYPE {
|
|
ULONG SymbolIndex:24;
|
|
ULONG Reserved:3;
|
|
ULONG Type:4;
|
|
ULONG External:1;
|
|
} MIPS_RELOCATION_TYPE, *PMIPS_RELOCATION_TYPE;
|
|
|
|
typedef struct _MIPS_RELOCATION_ENTRY {
|
|
ULONG VirtualAddress;
|
|
MIPS_RELOCATION_TYPE Type;
|
|
} MIPS_RELOCATION_ENTRY, *PMIPS_RELOCATION_ENTRY;
|
|
|
|
typedef struct _MIPS_SYMBOLIC_HEADER {
|
|
SHORT Magic;
|
|
SHORT VersionStamp;
|
|
ULONG NumOfLineNumberEntries;
|
|
ULONG BytesForLineNumberEntries;
|
|
ULONG PointerToLineNumberEntries;
|
|
ULONG NumOfDenseNumbers;
|
|
ULONG PointerToDenseNumbers;
|
|
ULONG NumOfProcedures;
|
|
ULONG PointerToProcedures;
|
|
ULONG NumOfLocalSymbols;
|
|
ULONG PointerToLocalSymbols;
|
|
ULONG NumOfOptimizationEntries;
|
|
ULONG PointerToOptimizationEntries;
|
|
ULONG NumOfAuxSymbols;
|
|
ULONG PointerToAuxSymbols;
|
|
ULONG NumOfLocalStrings;
|
|
ULONG PointerToLocalStrings;
|
|
ULONG NumOfExternalStrings;
|
|
ULONG PointerToExternalStrings;
|
|
ULONG NumOfFileDescriptors;
|
|
ULONG PointerToFileDescriptors;
|
|
ULONG NumOfRelativeFileDescriptors;
|
|
ULONG PointerToRelativeFileDescriptors;
|
|
ULONG NumOfExternalSymbols;
|
|
ULONG PointerToExternalSymbols;
|
|
} MIPS_SYMBOLIC_HEADER, *PMIPS_SYMBOLIC_HEADER;
|
|
|
|
typedef struct _MIPS_LOCAL_SYMBOL {
|
|
ULONG IndexToSymbolString;
|
|
ULONG Value;
|
|
ULONG Type:6;
|
|
ULONG StorageClass:5;
|
|
ULONG Reserved:1;
|
|
ULONG Index:20;
|
|
} MIPS_LOCAL_SYMBOL, *PMIPS_LOCAL_SYMBOL;
|
|
|
|
//
|
|
// Types for external symbols
|
|
//
|
|
#define EST_NIL 0
|
|
#define EST_GLOBAL 1
|
|
#define EST_STATIC 2
|
|
#define EST_PARAM 3
|
|
#define EST_LOCAL 4
|
|
#define EST_LABEL 5
|
|
#define EST_PROC 6
|
|
#define EST_BLOCK 7
|
|
#define EST_END 8
|
|
#define EST_MEMBER 9
|
|
#define EST_TYPEDEF 10
|
|
#define EST_FILE 11
|
|
#define EST_STATICPROC 14
|
|
#define EST_CONSTANT 15
|
|
|
|
//
|
|
// Storage class for external symbols
|
|
//
|
|
#define ESSC_NIL 0
|
|
#define ESSC_TEXT 1
|
|
#define ESSC_DATA 2
|
|
#define ESSC_BSS 3
|
|
#define ESSC_REGISTER 4
|
|
#define ESSC_ABS 5
|
|
#define ESSC_UNDEFINED 6
|
|
#define ESSC_BITS 8
|
|
#define ESSC_DBX 9
|
|
#define ESSC_REGIMAX 10
|
|
#define ESSC_INFO 11
|
|
#define ESSC_USER_STRUCT 12
|
|
#define ESSC_SDATA 13
|
|
#define ESSC_SBSS 14
|
|
#define ESSC_SRDATA 15
|
|
#define ESSC_VAR 16
|
|
#define ESSC_COMMON 17
|
|
#define ESSC_SCOMMON 18
|
|
#define ESSC_VARREGISTER 19
|
|
#define ESSC_VARIANT 20
|
|
#define ESSC_SUNDEFINED 21
|
|
#define ESSC_INIT 22
|
|
|
|
typedef struct _MIPS_EXTERNAL_SYMBOL {
|
|
USHORT Reserved;
|
|
USHORT PointerToFileDescriptor;
|
|
MIPS_LOCAL_SYMBOL Symbol;
|
|
} MIPS_EXTERNAL_SYMBOL, *PMIPS_EXTERNAL_SYMBOL;
|
|
|
|
typedef struct _SECTION_RELOCATION_ENTRY {
|
|
ULONG FixupValue;
|
|
ULONG PointerToRelocations;
|
|
USHORT NumberOfRelocations;
|
|
} SECTION_RELOCATION_ENTRY, *PSECTION_RELOCATION_ENTRY;
|
|
|
|
typedef
|
|
VOID
|
|
(*PTRANSFER_ROUTINE) (
|
|
IN ULONG Argc,
|
|
IN PCHAR Argv[],
|
|
IN PCHAR Envp[]
|
|
);
|
|
|
|
ARC_STATUS
|
|
FwRelocateImage (
|
|
IN ULONG FileId,
|
|
PSECTION_RELOCATION_ENTRY RelocationTable
|
|
);
|
|
|
|
VOID
|
|
FwGenerateDescriptor (
|
|
IN PFW_MEMORY_DESCRIPTOR MemoryDescriptor,
|
|
IN MEMORY_TYPE MemoryType,
|
|
IN ULONG BasePage,
|
|
IN ULONG PageCount
|
|
);
|
|
|
|
|
|
ARC_STATUS
|
|
FwLoad (
|
|
IN PCHAR ImagePath,
|
|
IN ULONG TopAddress,
|
|
OUT PULONG EntryAddress,
|
|
OUT PULONG LowAddress
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine attempts to load the specified file from the specified
|
|
device.
|
|
|
|
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.
|
|
|
|
LowAddress - 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 unsuccessful status is returned
|
|
that describes the reason for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
SECTION_RELOCATION_ENTRY RelocationTable[R_SN_MAX];
|
|
ULONG ActualBase;
|
|
ULONG SectionBase;
|
|
ULONG SectionOffset;
|
|
ULONG SectionIndex;
|
|
ULONG Count;
|
|
PIMAGE_FILE_HEADER FileHeader;
|
|
ULONG FileId;
|
|
ULONG Index;
|
|
UCHAR LocalBuffer[SECTOR_SIZE+64];
|
|
PUCHAR LocalPointer;
|
|
ULONG NumberOfSections;
|
|
PIMAGE_OPTIONAL_HEADER OptionalHeader;
|
|
PIMAGE_SECTION_HEADER SectionHeader;
|
|
ARC_STATUS Status;
|
|
LARGE_INTEGER SeekPosition;
|
|
ULONG SectionFlags;
|
|
|
|
//
|
|
// Zero The relocation table
|
|
//
|
|
RtlZeroMemory((PVOID)RelocationTable,sizeof(RelocationTable));
|
|
|
|
//
|
|
// Align the buffer on a Dcache line size.
|
|
//
|
|
|
|
LocalPointer = (PVOID) ((ULONG) ((PCHAR) LocalBuffer + KeGetDcacheFillSize() - 1)
|
|
& ~(KeGetDcacheFillSize() - 1));
|
|
|
|
//
|
|
// Set the image start address to null.
|
|
//
|
|
|
|
*EntryAddress = 0;
|
|
|
|
//
|
|
// Attempt to open the load file.
|
|
//
|
|
|
|
Status = ArcOpen(ImagePath, ArcOpenReadOnly, &FileId);
|
|
if (Status != ESUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Read the image header from the file.
|
|
//
|
|
|
|
Status = ArcRead(FileId, LocalPointer, SECTOR_SIZE, &Count);
|
|
if (Status != ESUCCESS) {
|
|
ArcClose(FileId);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Get a pointer to the file header and begin processing it.
|
|
//
|
|
|
|
FileHeader = (PIMAGE_FILE_HEADER)LocalPointer;
|
|
OptionalHeader =
|
|
(PIMAGE_OPTIONAL_HEADER)(LocalPointer + sizeof(IMAGE_FILE_HEADER));
|
|
SectionHeader =
|
|
(PIMAGE_SECTION_HEADER)(LocalPointer + sizeof(IMAGE_FILE_HEADER) +
|
|
FileHeader->SizeOfOptionalHeader);
|
|
|
|
//
|
|
// If the image file is not the specified type, then return bad image
|
|
// type status.
|
|
//
|
|
|
|
if (!((FileHeader->Machine == IMAGE_FILE_MACHINE_R3000) ||
|
|
(FileHeader->Machine == IMAGE_FILE_MACHINE_R4000)) ||
|
|
((FileHeader->Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0)) {
|
|
ArcClose(FileId);
|
|
return EBADF;
|
|
}
|
|
|
|
//
|
|
// 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 size of the data. If the image can be relocated,
|
|
// set ActualBase to the TopAddress minus the image size, and compute the
|
|
// image size by adding the size of the code, initialized data, and
|
|
// uninitialized data.
|
|
//
|
|
|
|
NumberOfSections = FileHeader->NumberOfSections;
|
|
|
|
if ((FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) != 0) {
|
|
ActualBase = OptionalHeader->BaseOfCode;
|
|
FwPageCount = (OptionalHeader->BaseOfData + OptionalHeader->SizeOfInitializedData) -
|
|
ActualBase;
|
|
} else {
|
|
FwPageCount = OptionalHeader->SizeOfCode +
|
|
OptionalHeader->SizeOfInitializedData +
|
|
OptionalHeader->SizeOfUninitializedData;
|
|
|
|
ActualBase = (TopAddress - FwPageCount) & ~(PAGE_SIZE - 1);
|
|
}
|
|
|
|
//
|
|
// Convert ActualBasePage and PageCount to be in units of pages instead of
|
|
// bytes.
|
|
//
|
|
|
|
FwActualBasePage = (ActualBase & 0x1fffffff) >> PAGE_SHIFT;
|
|
|
|
if (strcmp((PCHAR)&SectionHeader[NumberOfSections - 1].Name, ".debug") == 0) {
|
|
NumberOfSections -= 1;
|
|
FwPageCount -= SectionHeader[NumberOfSections].SizeOfRawData;
|
|
}
|
|
FwPageCount = (FwPageCount + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
|
|
|
*LowAddress = ActualBase | KSEG0_BASE;
|
|
|
|
//
|
|
// Return the entry address to the caller.
|
|
//
|
|
|
|
*EntryAddress = ((ActualBase | KSEG0_BASE) +
|
|
(OptionalHeader->AddressOfEntryPoint - OptionalHeader->BaseOfCode)
|
|
);
|
|
|
|
|
|
//
|
|
// Scan through the sections and either read them into memory or clear
|
|
// the memory as appropriate.
|
|
//
|
|
|
|
SectionOffset = 0;
|
|
for (Index = 0; Index < NumberOfSections; Index += 1) {
|
|
|
|
//
|
|
// Compute the destination address for the current section.
|
|
//
|
|
if ((FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) != 0) {
|
|
SectionBase = SectionHeader->VirtualAddress | KSEG0_BASE;
|
|
} else {
|
|
SectionBase = ActualBase + SectionOffset;
|
|
//
|
|
// Store the section relocation information in the table.
|
|
//
|
|
SectionFlags = SectionHeader->Characteristics;
|
|
if (SectionFlags & STYP_TEXT) {
|
|
SectionIndex = R_SN_TEXT;
|
|
} else if (SectionFlags & STYP_INIT) {
|
|
SectionIndex = R_SN_INIT;
|
|
} else if (SectionFlags & STYP_RDATA) {
|
|
SectionIndex = R_SN_RDATA;
|
|
} else if (SectionFlags & STYP_DATA) {
|
|
SectionIndex = R_SN_DATA;
|
|
} else if (SectionFlags & STYP_SDATA) {
|
|
SectionIndex = R_SN_SDATA;
|
|
} else if (SectionFlags & STYP_SBSS) {
|
|
SectionIndex = R_SN_SBSS;
|
|
} else if (SectionFlags & STYP_BSS) {
|
|
SectionIndex = R_SN_BSS;
|
|
} else {
|
|
VenPrint(FW_UNKNOWN_SECTION_TYPE_MSG);
|
|
return EBADF;
|
|
}
|
|
RelocationTable[SectionIndex].PointerToRelocations = SectionHeader->PointerToRelocations;
|
|
RelocationTable[SectionIndex].NumberOfRelocations = SectionHeader->NumberOfRelocations;
|
|
RelocationTable[SectionIndex].FixupValue = SectionBase - SectionHeader->VirtualAddress;
|
|
}
|
|
|
|
//
|
|
// If the section is code, initialized data, or other, then read
|
|
// the code or data into memory.
|
|
//
|
|
|
|
if ((SectionHeader->Characteristics &
|
|
(STYP_TEXT | STYP_INIT | STYP_RDATA | STYP_DATA | STYP_SDATA)) != 0) {
|
|
|
|
SeekPosition.LowPart = SectionHeader->PointerToRawData;
|
|
SeekPosition.HighPart = 0;
|
|
Status = ArcSeek(FileId,
|
|
&SeekPosition,
|
|
SeekAbsolute);
|
|
|
|
if (Status != ESUCCESS) {
|
|
break;
|
|
}
|
|
|
|
Status = ArcRead(FileId,
|
|
(PVOID)SectionBase,
|
|
SectionHeader->SizeOfRawData,
|
|
&Count);
|
|
|
|
if (Status != ESUCCESS) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set the offset of the next section
|
|
//
|
|
SectionOffset += SectionHeader->SizeOfRawData;
|
|
|
|
//
|
|
// If the section is uninitialized data, then zero the specifed memory.
|
|
//
|
|
|
|
} else if ((SectionHeader->Characteristics & (STYP_BSS | STYP_SBSS)) != 0) {
|
|
|
|
RtlZeroMemory((PVOID)(SectionBase), SectionHeader->SizeOfRawData);
|
|
|
|
//
|
|
// Set the offset of the next section
|
|
//
|
|
|
|
SectionOffset += SectionHeader->SizeOfRawData;
|
|
|
|
}
|
|
|
|
SectionHeader += 1;
|
|
}
|
|
|
|
//
|
|
// If code has to be relocated do so.
|
|
//
|
|
if ((FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) == 0) {
|
|
Status=FwRelocateImage(FileId,RelocationTable);
|
|
|
|
//
|
|
// Flush the data cache.
|
|
//
|
|
|
|
HalSweepDcache();
|
|
}
|
|
//
|
|
// Close file and return completion status.
|
|
//
|
|
ArcClose(FileId);
|
|
if (Status == ESUCCESS) {
|
|
|
|
//
|
|
// Flush the instruction cache.
|
|
//
|
|
|
|
HalSweepIcache();
|
|
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
ARC_STATUS
|
|
FwRelocateImage (
|
|
IN ULONG FileId,
|
|
PSECTION_RELOCATION_ENTRY RelocationTable
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine 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 is successful. Otherwise, return an
|
|
unsuccessful status.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PULONG FixupAddress;
|
|
PUSHORT FixupAddressHi;
|
|
ULONG FixupValue;
|
|
ULONG Index,Section;
|
|
ULONG Count;
|
|
ULONG NumberOfRelocations;
|
|
PMIPS_RELOCATION_ENTRY RelocationEntry;
|
|
UCHAR LocalBuffer[SECTOR_SIZE+64];
|
|
PUCHAR LocalPointer;
|
|
ULONG Offset;
|
|
ARC_STATUS Status;
|
|
MIPS_EXTERNAL_SYMBOL MipsExternalSymbol;
|
|
ULONG PointerToSymbolicHeader;
|
|
ULONG PointerToExternalSymbols;
|
|
ULONG NumberOfExternalSymbols;
|
|
LARGE_INTEGER SeekPosition;
|
|
BOOLEAN MatchedReflo;
|
|
|
|
//
|
|
// Align the buffer on a Dcache line size.
|
|
//
|
|
|
|
LocalPointer = (PVOID) ((ULONG) ((PCHAR) LocalBuffer + KeGetDcacheFillSize() - 1)
|
|
& ~(KeGetDcacheFillSize() - 1));
|
|
|
|
//
|
|
// Read the File Header To find out where the symbols are.
|
|
//
|
|
|
|
SeekPosition.LowPart = 0;
|
|
SeekPosition.HighPart = 0;
|
|
|
|
if ((Status = ArcSeek(FileId,&SeekPosition,SeekAbsolute)) != ESUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
if ((Status = ArcRead(FileId,LocalPointer,SECTOR_SIZE,&Count)) != ESUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
PointerToSymbolicHeader = ((PIMAGE_FILE_HEADER)LocalPointer)->PointerToSymbolTable;
|
|
// SizeOfSymbolicHeader = ((PIMAGE_FILE_HEADER)LocalPointer)->NumberOfSymbols;
|
|
|
|
//
|
|
// Read the symbolic haeder to find out where the external symbols are.
|
|
//
|
|
|
|
SeekPosition.LowPart = PointerToSymbolicHeader;
|
|
|
|
if ((Status = ArcSeek(FileId,&SeekPosition ,SeekAbsolute)) != ESUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
if ((Status = ArcRead(FileId,LocalPointer,SECTOR_SIZE,&Count)) != ESUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
PointerToExternalSymbols = ((PMIPS_SYMBOLIC_HEADER)LocalPointer)->PointerToExternalSymbols;
|
|
NumberOfExternalSymbols = ((PMIPS_SYMBOLIC_HEADER)LocalPointer)->NumOfExternalSymbols;
|
|
|
|
|
|
//
|
|
// Read the relocation table for each section.
|
|
//
|
|
|
|
MatchedReflo = FALSE;
|
|
for (Section=0; Section < R_SN_MAX; Section++) {
|
|
NumberOfRelocations = RelocationTable[Section].NumberOfRelocations;
|
|
for (Index = 0; Index < NumberOfRelocations; Index ++) {
|
|
if ((Index % (SECTOR_SIZE/sizeof(MIPS_RELOCATION_ENTRY))) == 0) {
|
|
//
|
|
// read a sector worth of relocation entries.
|
|
//
|
|
SeekPosition.LowPart = RelocationTable[Section].PointerToRelocations+Index*sizeof(MIPS_RELOCATION_ENTRY);
|
|
ArcSeek(FileId,
|
|
&SeekPosition,
|
|
SeekAbsolute);
|
|
|
|
Status = ArcRead(FileId,
|
|
LocalPointer,
|
|
SECTOR_SIZE,
|
|
&Count);
|
|
if (Status != ESUCCESS) {
|
|
return Status;
|
|
}
|
|
RelocationEntry = (PMIPS_RELOCATION_ENTRY)LocalPointer;
|
|
}
|
|
|
|
//
|
|
// Get the address for the fixup.
|
|
//
|
|
|
|
FixupAddress = (PULONG)(RelocationEntry->VirtualAddress +
|
|
RelocationTable[Section].FixupValue);
|
|
//
|
|
// Apply the fixup.
|
|
//
|
|
|
|
if (RelocationEntry->Type.External == 0) {
|
|
|
|
//
|
|
// If the relocation is internal, SymbolIndex
|
|
// supplies the number of the section containing the symbol.
|
|
// Compute the Offset for that section.
|
|
//
|
|
|
|
Offset = RelocationTable[RelocationEntry->Type.SymbolIndex].FixupValue;
|
|
} else {
|
|
|
|
// sprintf(Message,"External Relocation at:%lx\r\n",FixupAddress);
|
|
// VenPrint(Message);
|
|
//
|
|
// This is an external reference. Read the symbol table.
|
|
//
|
|
|
|
SeekPosition.LowPart = PointerToExternalSymbols+
|
|
RelocationEntry->Type.SymbolIndex*sizeof(MIPS_EXTERNAL_SYMBOL);
|
|
if ((Status =
|
|
ArcSeek(FileId,
|
|
&SeekPosition,
|
|
SeekAbsolute)) != ESUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
if ((Status = ArcRead(FileId,
|
|
&MipsExternalSymbol,
|
|
sizeof(MIPS_EXTERNAL_SYMBOL),
|
|
&Count)) != ESUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Check that the value of the symbol is an address.
|
|
//
|
|
|
|
Offset = MipsExternalSymbol.Symbol.Value;
|
|
|
|
if ((MipsExternalSymbol.Symbol.StorageClass == ESSC_TEXT) ||
|
|
(MipsExternalSymbol.Symbol.StorageClass == ESSC_DATA)) {
|
|
Offset+= RelocationTable[Section].FixupValue;
|
|
} else {
|
|
return EBADF;
|
|
}
|
|
}
|
|
|
|
switch (RelocationEntry->Type.Type) {
|
|
|
|
//
|
|
// Absolute - no fixup required.
|
|
//
|
|
|
|
case IMAGE_REL_MIPS_ABSOLUTE:
|
|
break;
|
|
|
|
//
|
|
// Word - (32-bits) relocate the entire address.
|
|
//
|
|
|
|
case IMAGE_REL_MIPS_REFWORD:
|
|
|
|
*FixupAddress += (ULONG)Offset;
|
|
break;
|
|
|
|
//
|
|
// Adjust high - (16-bits) relocate the high half of an
|
|
// address and adjust for sign extension of low half.
|
|
//
|
|
|
|
case IMAGE_REL_MIPS_JMPADDR:
|
|
|
|
FixupValue = ((*FixupAddress)&0x03fffff) + (Offset >> 2);
|
|
*FixupAddress = (*FixupAddress & 0xfc000000) | (FixupValue & 0x03fffff);
|
|
break;
|
|
|
|
case IMAGE_REL_MIPS_REFHI:
|
|
|
|
//
|
|
// Save the address and go to get REF_LO paired with this one
|
|
//
|
|
|
|
FixupAddressHi = (PSHORT)FixupAddress;
|
|
MatchedReflo = TRUE;
|
|
break;
|
|
|
|
//
|
|
// Low - (16-bit) relocate high part too.
|
|
//
|
|
|
|
case IMAGE_REL_MIPS_REFLO:
|
|
|
|
if (MatchedReflo) {
|
|
FixupValue = (ULONG)(LONG)((*FixupAddressHi) << 16) +
|
|
*(PSHORT)FixupAddress +
|
|
Offset;
|
|
|
|
//
|
|
// Fix the High part
|
|
//
|
|
|
|
*FixupAddressHi = (SHORT)((FixupValue + 0x8000) >> 16);
|
|
MatchedReflo = FALSE;
|
|
} else {
|
|
FixupValue = *(PSHORT)FixupAddress + Offset;
|
|
}
|
|
|
|
//
|
|
// Fix the lower part.
|
|
//
|
|
|
|
*(PUSHORT)FixupAddress = (USHORT)(FixupValue & 0xffff);
|
|
break;
|
|
|
|
//
|
|
// Illegal - illegal relocation type.
|
|
//
|
|
|
|
default :
|
|
VenPrint(FW_UNKNOWN_RELOC_TYPE_MSG);
|
|
return EBADF;
|
|
|
|
}
|
|
RelocationEntry++;
|
|
}
|
|
}
|
|
return ESUCCESS;
|
|
}
|
|
//
|
|
//ARC_STATUS
|
|
//FwInvoke(
|
|
// IN ULONG ExecAddr,
|
|
// IN ULONG StackAddr,
|
|
// IN ULONG Argc,
|
|
// IN PCHAR Argv[],
|
|
// IN PCHAR Envp[]
|
|
// )
|
|
//
|
|
///*++
|
|
//
|
|
//Routine Description:
|
|
//
|
|
// This routine invokes a loaded program.
|
|
//
|
|
//Arguments:
|
|
//
|
|
// ExecAddr - Supplies the address of the routine to call.
|
|
//
|
|
// StackAddr - Supplies the address to which the stack pointer is set.
|
|
//
|
|
// Argc, Argv, Envp - Supply the arguments and endvironment to pass to
|
|
// Loaded program.
|
|
//
|
|
//
|
|
//Return Value:
|
|
//
|
|
// ESUCCESS is returned if the address is valid.
|
|
// EFAULT indicates an invalid addres.
|
|
//
|
|
//--*/
|
|
//
|
|
//{
|
|
// //
|
|
// // Check for aligned address.
|
|
// //
|
|
// if ((ExecAddr & 0x3) == 0) {
|
|
// ((PTRANSFER_ROUTINE)ExecAddr)(Argc, Argv, Envp);
|
|
// return ESUCCESS;
|
|
// } else {
|
|
// return EFAULT;
|
|
// }
|
|
//}
|
|
|
|
|
|
VOID
|
|
FwCopyArguments(
|
|
IN ULONG Argc,
|
|
IN PCHAR Argv[]
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine copies the supplied arguments into the Fw
|
|
space.
|
|
|
|
Arguments:
|
|
|
|
Argc, Argv, - Supply the arguments to be copied.
|
|
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS is returned if the arguments were successfully copied.
|
|
EFAULT if there is not enough room for them.
|
|
|
|
--*/
|
|
|
|
{
|
|
PUCHAR Source,Destination;
|
|
ULONG Arg;
|
|
|
|
PSavedArgs->Argc = Argc;
|
|
Destination = &PSavedArgs->Arguments[0];
|
|
for (Arg = 0; Arg < Argc; Arg++) {
|
|
Source = Argv[Arg];
|
|
PSavedArgs->Argv[Arg] = Destination;
|
|
while(*Destination++ = *Source++) {
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
ARC_STATUS
|
|
FwPrivateExecute(
|
|
IN PCHAR Path,
|
|
IN ULONG Argc,
|
|
IN PCHAR Argv[],
|
|
IN PCHAR Envp[]
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine loads and invokes a program.
|
|
FwExecute sets the right stack pointer and calls this routine which
|
|
does all the work. When this routine returns (after the loaded
|
|
program has been executed) the stack is restored to the Fw stack
|
|
and control is returned to the firmware.
|
|
Therefore a loaded program that executes another program does not
|
|
get control back once the executed program is finished.
|
|
|
|
Arguments:
|
|
|
|
Path - Supplies a pointer to the path of the file to load.
|
|
|
|
Argc, Argv, Envp - Supply the arguments and endvironment to pass to
|
|
Loaded program.
|
|
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS is returned if the address is valid.
|
|
EFAULT indicates an invalid addres.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PULONG TransferRoutine;
|
|
ULONG BottomAddress;
|
|
ARC_STATUS Status;
|
|
PMEMORY_DESCRIPTOR MemoryDescriptor;
|
|
PFW_MEMORY_DESCRIPTOR FwMemoryDescriptor;
|
|
CHAR TempPath[256];
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
FwCopyArguments(Argc,Argv);
|
|
strcpy(TempPath, Path);
|
|
|
|
//
|
|
// Reinitialize the memory descriptors
|
|
//
|
|
FwResetMemory();
|
|
|
|
//
|
|
// Look for a piece of free memory.
|
|
//
|
|
MemoryDescriptor = ArcGetMemoryDescriptor(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 = FwLoad(TempPath,
|
|
((MemoryDescriptor->BasePage +
|
|
MemoryDescriptor->PageCount) << PAGE_SHIFT) | KSEG0_BASE,
|
|
(PULONG)&TransferRoutine,
|
|
&BottomAddress);
|
|
|
|
if (Status == ESUCCESS) {
|
|
|
|
//
|
|
// Find the actual area of memory that was used, and generate a
|
|
// descriptor for it.
|
|
//
|
|
|
|
MemoryDescriptor = ArcGetMemoryDescriptor(NULL);
|
|
while (MemoryDescriptor != NULL){
|
|
if ((MemoryDescriptor->MemoryType == MemoryFree) &&
|
|
(FwActualBasePage >= MemoryDescriptor->BasePage) &&
|
|
((FwActualBasePage + FwPageCount) <=
|
|
(MemoryDescriptor->BasePage + MemoryDescriptor->PageCount))) {
|
|
break;
|
|
}
|
|
|
|
MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor);
|
|
}
|
|
|
|
if (MemoryDescriptor != NULL) {
|
|
FwMemoryDescriptor = CONTAINING_RECORD(MemoryDescriptor,
|
|
FW_MEMORY_DESCRIPTOR,
|
|
MemoryEntry);
|
|
|
|
FwGenerateDescriptor(FwMemoryDescriptor,
|
|
MemoryLoadedProgram,
|
|
FwActualBasePage,
|
|
FwPageCount);
|
|
}
|
|
|
|
#ifdef DUO
|
|
//
|
|
// Set the boot task to be run by processor B and
|
|
// wake him up.
|
|
//
|
|
{
|
|
PPROCESSOR_B_TASK_VECTOR TaskVector;
|
|
if (FirstLoadedProgram) {
|
|
FirstLoadedProgram = FALSE;
|
|
TaskVector = (PPROCESSOR_B_TASK_VECTOR)&ProcessorBTask;
|
|
TaskVector->Routine = (PPROCESSOR_TASK_ROUTINE)FwpRestart;
|
|
TaskVector->Data = 0;
|
|
WRITE_REGISTER_ULONG(&DMA_CONTROL->IpInterruptRequest.Long,2);
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
if (BreakAfterLoad == TRUE) {
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
Status = FwInvoke((ULONG)TransferRoutine,
|
|
BottomAddress,
|
|
PSavedArgs->Argc,
|
|
PSavedArgs->Argv,
|
|
Envp
|
|
);
|
|
#ifdef DUO
|
|
//
|
|
// The Invoked program returned or it could not be loaded.
|
|
// Issue another IP interrupt to processor B to notify him to
|
|
// give up the boot process.
|
|
// Wait for an IP interrupt from B which indicates processor B
|
|
// is back into it's main loop.
|
|
//
|
|
WRITE_REGISTER_ULONG(&DMA_CONTROL->IpInterruptRequest.Long,2);
|
|
WaitForIpInterrupt(500);
|
|
#endif
|
|
return Status;
|
|
|
|
}
|
|
|
|
if (Status != ENOMEM) {
|
|
return Status;
|
|
}
|
|
}
|
|
MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor);
|
|
}
|
|
return ENOMEM;
|
|
}
|
|
|
|
VOID
|
|
FwLoadInitialize(
|
|
IN VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the firmware load services.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
(PARC_LOAD_ROUTINE)SYSTEM_BLOCK->FirmwareVector[LoadRoutine] = FwLoad;
|
|
(PARC_INVOKE_ROUTINE)SYSTEM_BLOCK->FirmwareVector[InvokeRoutine] = FwInvoke;
|
|
(PARC_EXECUTE_ROUTINE)SYSTEM_BLOCK->FirmwareVector[ExecuteRoutine] = FwExecute;
|
|
FwTemporaryStack = (ULONG) FwAllocatePool(0x3000) + 0x2FD0;
|
|
PSavedArgs = (PSAVED_ARGUMENTS) FwAllocatePool(sizeof(SAVED_ARGUMENTS));
|
|
}
|