mirror of
https://github.com/Wack0/entii-for-workcubes.git
synced 2025-12-20 02:15:05 -05:00
commit 39e237e99907449bac31254ceca13a2171cbe8ad
Author: stonedDiscord <Tukz@gmx.de>
Date: Mon Mar 3 03:25:37 2025 +0000
delete ci
commit 3bd4ecbbe904d8f39efbeea9b6fc49bc1ff4a98c
Author: stonedDiscord <Tukz@gmx.de>
Date: Mon Mar 3 03:18:53 2025 +0000
bracket
commit ecb3a8d077dc12c1df204366bb2637aaedb8c2ad
Merge: dfb1a56 0fd256c
Author: stonedDiscord <Tukz@gmx.de>
Date: Mon Mar 3 12:16:02 2025 +0900
Merge branch 'Wack0:main' into main
commit dfb1a567d3418550d102e1704a506d5bf70fe9af
Author: stonedDiscord <Tukz@gmx.de>
Date: Mon Mar 3 03:13:02 2025 +0000
component instead of type casting
commit 9a9233bbcb4fa5b60639284a7790e4fb278c9938
Author: stonedDiscord <Tukz@gmx.de>
Date: Mon Mar 3 02:56:48 2025 +0100
shutup wget
commit e2269523d81aa885b384a4fdb2c1b703790f156c
Author: stonedDiscord <Tukz@gmx.de>
Date: Mon Mar 3 02:55:10 2025 +0100
add caching
commit 7b7ec9d4441c53ef42e1a9d907734eab23dca54d
Author: stonedDiscord <Tukz@gmx.de>
Date: Mon Mar 3 02:49:45 2025 +0100
minor spelling mistake
commit 6023e330c073d580af73c605cec8579a6362fc57
Author: stonedDiscord <Tukz@gmx.de>
Date: Mon Mar 3 02:48:28 2025 +0100
upload fw
commit 15e43e774bc35f0984e8b9766c05857caeaab973
Author: stonedDiscord <Tukz@gmx.de>
Date: Mon Mar 3 02:45:20 2025 +0100
timer
commit de6347e81be38414109c658787c70a576b930995
Author: stonedDiscord <Tukz@gmx.de>
Date: Mon Mar 3 02:41:41 2025 +0100
udellay
commit 8f204e6b9ee4a32589b8524e733ad29a5e1e4de2
Author: stonedDiscord <Tukz@gmx.de>
Date: Mon Mar 3 02:39:08 2025 +0100
ulong
commit f88453f816d1eb2fdbe839bec7cc7e904bde40c7
Author: stonedDiscord <Tukz@gmx.de>
Date: Mon Mar 3 02:36:18 2025 +0100
diskio and alloc
commit 62a6bc38b626d0a136f217db698534301847ba8e
Author: stonedDiscord <Tukz@gmx.de>
Date: Mon Mar 3 02:30:55 2025 +0100
usb keyboard header
commit 97b51a1a6550d99fc38ec92740074df0a54e4c99
Author: stonedDiscord <Tukz@gmx.de>
Date: Mon Mar 3 02:26:32 2025 +0100
strcmp type
commit 849b110b09e42b0178c30ad61d98152a527de95f
Author: stonedDiscord <Tukz@gmx.de>
Date: Mon Mar 3 02:11:48 2025 +0100
void no bool
commit f0fb86f99589c50df2975534e16d62a0d986fd79
Author: stonedDiscord <Tukz@gmx.de>
Date: Mon Mar 3 02:08:36 2025 +0100
framebuffer type
commit 72012cac4b9fcde0489dccf848bec886a78f37bf
Author: stonedDiscord <Tukz@gmx.de>
Date: Mon Mar 3 02:05:08 2025 +0100
more components
commit 28e1766fa155d7c7906ff17c96a657eb6937b077
Author: stonedDiscord <Tukz@gmx.de>
Date: Mon Mar 3 02:00:46 2025 +0100
config component
commit 6d19c6a782adf5c1cb87035dfdc5fb060594c017
Author: Rairii <2650838+Wack0@users.noreply.github.com>
Date: Sun Mar 2 14:50:22 2025 +0000
arcfw(usb): when shutting down usb, ensure the device change callback is unlocked on the IOS side
this prevents deadlocks when loading iosusb.sys in NT
commit 04b1726461cb94d96bcaa12e5c051a58c74a4fa6
Author: Rairii <2650838+Wack0@users.noreply.github.com>
Date: Sun Mar 2 14:26:37 2025 +0000
arc(usb): if no devices are present after first poll, poll again with timeout
fixes scenarios with usb hubs etc
commit 14533184d7613756da674e038fb961cd9230333b
Author: stonedDiscord <Tukz@gmx.de>
Date: Sun Mar 2 12:51:09 2025 +0900
speling
commit 43861984bcde644d394b4fa90ac49c00db5e33e6
Author: stonedDiscord <Tukz@gmx.de>
Date: Sun Mar 2 12:41:46 2025 +0900
rearrange
commit 99064493f4d93900850bb74d18c14a17416b7d7a
Author: stonedDiscord <Tukz@gmx.de>
Date: Sun Mar 2 12:38:58 2025 +0900
loader artifact
commit da1a9c9628a47d77d8b04416cb1c7ad18f27b781
Author: stonedDiscord <Tukz@gmx.de>
Date: Sun Mar 2 12:17:00 2025 +0900
build folder
commit e6367d7f314238b4c3fe99585b2e360d36f60be2
Author: stonedDiscord <Tukz@gmx.de>
Date: Sun Mar 2 12:12:39 2025 +0900
zstd
commit 0202f7d95b2eaf1ec0c2e1bba34a997a4af9db38
Author: stonedDiscord <Tukz@gmx.de>
Date: Sun Mar 2 12:10:31 2025 +0900
libc
commit aac5fdb880108416b63736a1865f93c23f7b9e10
Author: Rairii <2650838+Wack0@users.noreply.github.com>
Date: Sat Mar 1 23:40:23 2025 +0000
fpexiblk: not using eximap for now, so don't try to finalise it on sad paths
this is probably what's causing bugchecks when no exi device is present
commit 80f88ecfa87aa70934a85ff960fc94d1038a7520
Author: Rairii <2650838+Wack0@users.noreply.github.com>
Date: Sat Mar 1 22:25:06 2025 +0000
fpgx35: work around GDI bug
GDI ExtFloodFill tries to convert a device specific bitmap to a normal bitmap for speed.
Prior to NT 4 this function has a bug, and so it will delete the device surface, which causes crashes and thus bugcheck (as it brings down csrss).
Do some pattern matching in DrvCopyBits and make it fail if it's being called by this conversion function. This causes a fallback to using the device specific bitmap, which is what is wanted.
Fixes bugcheck under NT 3.51 when running (at least) VC4 IDE.
commit b99ccd4406e5eb06cc00112d8de51af613a8eef7
Author: Rairii <2650838+Wack0@users.noreply.github.com>
Date: Sat Mar 1 21:36:47 2025 +0000
halartx: don't need this debug print anymore
commit e5e086d1f052f642ed06e3eee4230ec3e435bcab
Author: Rairii <2650838+Wack0@users.noreply.github.com>
Date: Sat Mar 1 01:10:33 2025 +0000
arcfw: disable return to loader, seems this only works under NT for some reason
commit e78be8a73eaba223f3318c2fea1ac5d27f0a0c42
Author: Rairii <2650838+Wack0@users.noreply.github.com>
Date: Sat Mar 1 01:00:03 2025 +0000
make: split up compile and asm-preproc
compiler errors are ignored by make when one is piped to the other
commit 4d501b30f20ecb67aed4c1bfa740ed517fb86e79
Author: Rairii <2650838+Wack0@users.noreply.github.com>
Date: Sat Mar 1 00:38:28 2025 +0000
iossdmc: enforce lock when fatfs calls GetStatus
commit a045ca7879040f3752d55d25bbbce4280068f525
Author: Rairii <2650838+Wack0@users.noreply.github.com>
Date: Sat Mar 1 00:00:38 2025 +0000
headers(ntddk): KeAcquireSpinLockRaiseToDpc was introduced in NT4, use KeAcquireSpinLock function instead
commit 3d0850ad707cbe02886ee7c36d454243cc73eafb
Author: Rairii <2650838+Wack0@users.noreply.github.com>
Date: Fri Feb 28 12:07:27 2025 +0000
gdi: only skip single pixel or line on bounds checks fail, add slight optimisation for copying two consecutive pixels
fixes #5
commit 9050ba4fd3334d815d9bb0e76f5bc19f90722d7e
Author: stonedDiscord <Tukz@gmx.de>
Date: Fri Feb 28 05:19:18 2025 +0100
sleep header
commit 27dff2d63a4640fbdeddeb914148641af24d5ab2
Author: stonedDiscord <Tukz@gmx.de>
Date: Fri Feb 28 05:17:30 2025 +0100
sleep and card
commit b1915a38e4723fcb0f1cc9d400e54ad5ee2b9557
Author: stonedDiscord <Tukz@gmx.de>
Date: Fri Feb 28 05:13:33 2025 +0100
missing header for gecko
commit 78a6c4a0fd493e42c1162e42667d03314ee06e26
Author: stonedDiscord <Tukz@gmx.de>
Date: Fri Feb 28 05:02:19 2025 +0100
usleep header
commit 24fcd1b0b280a408eff08949442b8dbf1d572988
Author: stonedDiscord <Tukz@gmx.de>
Date: Fri Feb 28 04:26:08 2025 +0100
update makefile name in readme
commit 78047b1d3f9970a5dfe70b7fb2fd217802719561
Author: stonedDiscord <Tukz@gmx.de>
Date: Fri Feb 28 04:25:04 2025 +0100
makefile name
commit fc8ab08b117dddec9c07607f870df56de882782a
Author: stonedDiscord <Tukz@gmx.de>
Date: Fri Feb 28 04:14:07 2025 +0100
arc firmware ci
838 lines
31 KiB
C
838 lines
31 KiB
C
#include <stddef.h>
|
|
#include <memory.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include "arc.h"
|
|
#include "arcio.h"
|
|
#include "arcmem.h"
|
|
#include "coff.h"
|
|
#include "ppcinst.h"
|
|
#include "oslhooks.h"
|
|
#include "runtime.h"
|
|
|
|
enum {
|
|
STYP_REG = 0x00000000,
|
|
STYP_TEXT = 0x00000020,
|
|
STYP_INIT = 0x80000000,
|
|
STYP_RDATA = 0x00000100,
|
|
STYP_DATA = 0x00000040,
|
|
STYP_LIT8 = 0x08000000,
|
|
STYP_LIT4 = 0x10000000,
|
|
STYP_SDATA = 0x00000200,
|
|
STYP_SBSS = 0x00000080,
|
|
STYP_BSS = 0x00000400,
|
|
STYP_LIB = 0x40000000,
|
|
STYP_UCODE = 0x00000800,
|
|
S_NRELOC_OVFL = 0x20000000,
|
|
|
|
SECTION_REQUIRES_LOAD = STYP_TEXT | STYP_INIT | STYP_RDATA | STYP_DATA | STYP_SDATA,
|
|
SECTION_REQUIRES_ZERO = STYP_BSS | STYP_SBSS,
|
|
|
|
SECTION_REQUIRES_LOAD_PE = IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA,
|
|
SECTION_REQUIRES_ZERO_PE = IMAGE_SCN_CNT_UNINITIALIZED_DATA
|
|
};
|
|
|
|
enum {
|
|
R_SN_TEXT = 1,
|
|
R_SN_RDATA,
|
|
R_SN_DATA,
|
|
R_SN_SDATA,
|
|
R_SN_SBSS,
|
|
R_SN_BSS,
|
|
R_SN_INIT,
|
|
R_SN_LIT8,
|
|
R_SN_LIT4,
|
|
R_SN_MAX
|
|
};
|
|
|
|
enum {
|
|
SECTOR_SIZE = 0x200
|
|
};
|
|
|
|
typedef struct _SECTION_RELOCATION_ENTRY {
|
|
ULONG FixupValue;
|
|
ULONG PointerToRelocations;
|
|
USHORT NumberOfRelocations;
|
|
} SECTION_RELOCATION_ENTRY, * PSECTION_RELOCATION_ENTRY;
|
|
|
|
#define MAX_ARGUMENT (512 - sizeof(ULONG) - 16*sizeof(PUCHAR))
|
|
typedef struct _SAVED_ARGUMENTS {
|
|
ULONG Argc;
|
|
U32LE Argv[16];
|
|
U32LE Envp[16];
|
|
UCHAR Arguments[MAX_ARGUMENT];
|
|
} SAVED_ARGUMENTS, * PSAVED_ARGUMENTS;
|
|
|
|
static SAVED_ARGUMENTS SavedArgs;
|
|
|
|
static PVOID ScratchAddress = NULL;
|
|
static bool s_OldCoffLoaded = false;
|
|
static bool s_MemoryMapFixedForOldCoff = false;
|
|
static bool s_MemoryMapFixedForAnyCoff = false;
|
|
|
|
static inline ARC_FORCEINLINE ULONG ScratchEnd() {
|
|
return (ULONG)ScratchAddress + ARCFW_MEM2_SIZE;
|
|
}
|
|
|
|
PVOID ArcLoadGetScratchAddress(void) {
|
|
return ScratchAddress;
|
|
}
|
|
|
|
#define mfpvr() ({u32 _rval; \
|
|
__asm__ __volatile__ ("mfpvr %0" : "=r"(_rval)); _rval;})
|
|
|
|
static void InstructionPerformPatch(
|
|
PU32LE SectionBaseLittle,
|
|
ULONG Offset
|
|
) {
|
|
ULONG instruction = SectionBaseLittle[Offset].v;
|
|
|
|
static ULONG PvrVersion = 0;
|
|
if (PvrVersion == 0) PvrVersion = mfpvr() >> 16;
|
|
// NT 4 osloader checks pvr, if it's not in hardcoded list then panic
|
|
// so patch this check :)
|
|
if (PvrVersion > 9 && PvrVersion != 20) {
|
|
PPC_INSTRUCTION Insn;
|
|
Insn.Long = instruction;
|
|
if (Insn.Primary_Op == X31_OP && Insn.XFXform_XO == MFSPR_OP && Insn.XFXform_spr == 1000) {
|
|
// Make NT believe this is an Arthur derivative
|
|
// addis rx, 0, 8
|
|
PPC_INSTRUCTION Patch;
|
|
Patch.Long = 0;
|
|
Patch.Primary_Op = ADDIS_OP;
|
|
Patch.Dform_RT = Insn.XFXform_RT;
|
|
Patch.Dform_RA = 0;
|
|
Patch.Dform_D = 8;
|
|
instruction = Patch.Long;
|
|
SectionBaseLittle[Offset].v = instruction;
|
|
}
|
|
}
|
|
}
|
|
|
|
static ARC_STATUS RelocatePEBlock(ULONG VirtualAddress, ULONG Length, PU16LE Block, LONG Diff, bool IsLittleEndian) {
|
|
for (ULONG Index = 0; Index < Length; Index++) {
|
|
USHORT Offset = Block[Index].v;
|
|
USHORT Type = Offset >> 12;
|
|
Offset &= (ARC_BIT(12) - 1);
|
|
ULONG FixupVA = VirtualAddress + Offset;
|
|
PU16BE DataBig = (PU16BE)FixupVA;
|
|
PU16LE DataLittle = (PU16LE)FixupVA;
|
|
switch (Type) {
|
|
case IMAGE_REL_BASED_HIGHLOW:
|
|
// 32-bit relocation
|
|
{
|
|
LONG Base;
|
|
memcpy(&Base, (PVOID)FixupVA, sizeof(Base));
|
|
if (!IsLittleEndian) {
|
|
Base = SwapEndianness32(Base);
|
|
}
|
|
Base += Diff;
|
|
if (!IsLittleEndian) {
|
|
Base = SwapEndianness32(Base);
|
|
}
|
|
memcpy((PVOID)FixupVA, &Base, sizeof(Base));
|
|
}
|
|
break;
|
|
|
|
case IMAGE_REL_BASED_HIGH:
|
|
// high 16-bit relocation
|
|
{
|
|
ULONG Temp = (IsLittleEndian ? DataLittle->v : DataBig->v) << 16;
|
|
Temp += Diff;
|
|
if (IsLittleEndian) DataLittle->v = (Temp >> 16);
|
|
else DataBig->v = (Temp >> 16);
|
|
}
|
|
break;
|
|
|
|
case IMAGE_REL_BASED_HIGHADJ:
|
|
// high 16-bit relocation with adjustment
|
|
{
|
|
if (Index == Length) {
|
|
// whoops, better not overflow
|
|
printf("HighAdj relocation overflows table\n");
|
|
return _EBADF;
|
|
}
|
|
ULONG Temp = (IsLittleEndian ? DataLittle->v : DataBig->v) << 16;
|
|
Index++;
|
|
PU16BE BlockBig = (PU16BE)(ULONG)Block;
|
|
// tfw MS seriously did this
|
|
Temp += (IsLittleEndian ? Block[Index].v : BlockBig[Index].v);
|
|
Temp += Diff;
|
|
Temp += INT16_MAX + 1;
|
|
|
|
if (IsLittleEndian) DataLittle->v = (Temp >> 16);
|
|
else DataBig->v = (Temp >> 16);
|
|
}
|
|
break;
|
|
|
|
case IMAGE_REL_BASED_LOW:
|
|
// low 16-bit relocation
|
|
{
|
|
ULONG Temp = (IsLittleEndian ? DataLittle->v : DataBig->v);
|
|
Temp += Diff;
|
|
if (IsLittleEndian) DataLittle->v = Temp;
|
|
else DataBig->v = Temp;
|
|
}
|
|
break;
|
|
|
|
//case IMAGE_REL_BASED_MIPS_JMPADDR: // not valid for PowerPC, osloader does it for all architectures for some reason
|
|
|
|
case IMAGE_REL_BASED_ABSOLUTE:
|
|
// no fixup required
|
|
break;
|
|
|
|
default:
|
|
// invalid for powerpc
|
|
printf("Invalid relocation %x\n", Type);
|
|
return _EBADF;
|
|
}
|
|
}
|
|
|
|
// all good
|
|
return _ESUCCESS;
|
|
}
|
|
|
|
static ARC_STATUS RelocatePE(ULONG ImageBase, PIMAGE_FILE_HEADER FileHeader, PIMAGE_OPTIONAL_HEADER OptionalHeader, PIMAGE_SECTION_HEADER Sections) {
|
|
bool IsLittleEndian = FileHeader->Machine == IMAGE_FILE_MACHINE_POWERPC;
|
|
|
|
PIMAGE_DATA_DIRECTORY RelocDir = &OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
|
|
bool HasRelocations = RelocDir->VirtualAddress != 0 && RelocDir->Size != 0;
|
|
PIMAGE_DATA_DIRECTORY ExceptionDir = &OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION];
|
|
bool HasExceptions = ExceptionDir->VirtualAddress != 0 && ExceptionDir->Size != 0;
|
|
|
|
if (ImageBase == OptionalHeader->ImageBase) {
|
|
// no need to relocate
|
|
HasRelocations = false;
|
|
}
|
|
else if (HasRelocations) {
|
|
// no relocations yet base moved
|
|
printf("Needs relocation but image has none\n");
|
|
return _EBADF;
|
|
}
|
|
|
|
if (!HasRelocations && !IsLittleEndian) {
|
|
// nothing needs to be done here
|
|
return _ESUCCESS;
|
|
}
|
|
|
|
ARC_STATUS Status;
|
|
|
|
// apply all PE relocations first. remember endianness.
|
|
if (HasRelocations) {
|
|
ULONG OldBase = OptionalHeader->ImageBase;
|
|
PIMAGE_BASE_RELOCATION Block = (PIMAGE_BASE_RELOCATION)(ImageBase + RelocDir->VirtualAddress);
|
|
ULONG BlockStart = (ULONG)Block;
|
|
ULONG RelocLength = RelocDir->Size;
|
|
|
|
for (ULONG Offset = 0; Offset < RelocLength;) {
|
|
Offset += Block->SizeOfBlock;
|
|
ULONG SizeOfBlock = Block->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION);
|
|
PU16LE Entries = (PU16LE)(ULONG)&Block[1];
|
|
|
|
Status = RelocatePEBlock(
|
|
ImageBase + Block->VirtualAddress,
|
|
SizeOfBlock / sizeof(USHORT),
|
|
Entries,
|
|
ImageBase - OldBase,
|
|
IsLittleEndian
|
|
);
|
|
|
|
if (ARC_FAIL(Status)) return Status;
|
|
|
|
Block = (PIMAGE_BASE_RELOCATION)(BlockStart + Offset);
|
|
}
|
|
}
|
|
|
|
// Instructions need patching here.
|
|
{
|
|
// Exception data is never present, just check every 32 bit value of every section containing code.
|
|
for (int i = 0; i < FileHeader->NumberOfSections - 1; i++) {
|
|
if ((Sections[i].Characteristics & IMAGE_SCN_CNT_CODE) == 0) continue;
|
|
|
|
ULONG SectionBase = ImageBase + Sections[i].VirtualAddress;
|
|
PU32BE SectionBaseBig = (PU32BE)SectionBase;
|
|
PU32LE SectionBaseLittle = (PU32LE)SectionBase;
|
|
|
|
for (ULONG off = 0; off < Sections[i].SizeOfRawData / sizeof(ULONG); off++) {
|
|
InstructionPerformPatch(SectionBaseLittle, off);
|
|
}
|
|
}
|
|
}
|
|
|
|
return _ESUCCESS;
|
|
}
|
|
|
|
// Reads the COFF symbol table and string table to scratch buffer
|
|
static ARC_STATUS ReadCoffSymbolTable(ULONG FileId, ULONG PointerToSymbolTable, ULONG NumberOfSymbols) {
|
|
PVENDOR_VECTOR_TABLE Api = ARC_VENDOR_VECTORS();
|
|
|
|
// If no scratch address was allocated, error
|
|
if (ScratchAddress == NULL) {
|
|
return _ENOMEM;
|
|
}
|
|
|
|
PULONG SymbolCount = (PULONG)ScratchAddress;
|
|
*SymbolCount = NumberOfSymbols;
|
|
|
|
PVOID ScratchAddress = (SymbolCount + 1);
|
|
|
|
// Get file length
|
|
FILE_INFORMATION Info;
|
|
ARC_STATUS Status = Api->GetFileInformationRoutine(FileId, &Info);
|
|
if (ARC_FAIL(Status)) return Status;
|
|
|
|
// Seek to symbol table
|
|
LARGE_INTEGER Offset = Int64ToLargeInteger(PointerToSymbolTable);
|
|
Status = Api->SeekRoutine(FileId, &Offset, SeekAbsolute);
|
|
if (ARC_FAIL(Status)) return Status;
|
|
|
|
int64_t ExpectedLength64 = Info.EndingAddress.QuadPart - PointerToSymbolTable;
|
|
// Needs to fit in ULONG
|
|
if (ExpectedLength64 > UINT32_MAX) return _E2BIG;
|
|
ULONG ExpectedLength = (ULONG)ExpectedLength64;
|
|
|
|
// If the symbol table is too long for the scratch memory, error
|
|
if ((ULONG)ScratchAddress + ExpectedLength > ScratchEnd()) {
|
|
return _ENOMEM;
|
|
}
|
|
|
|
// Read to scratch memory
|
|
U32LE Count;
|
|
Status = Api->ReadRoutine(FileId, ScratchAddress, ExpectedLength, &Count);
|
|
if (ARC_FAIL(Status)) return Status;
|
|
if (Count.v != ExpectedLength) return _EBADF;
|
|
|
|
return _ESUCCESS;
|
|
}
|
|
|
|
// Gets the address of a symbol using the loaded COFF symbol table in scratch
|
|
static PVOID GetSymbolEntryCoff(ULONG ImageBase, const char* SymbolName) {
|
|
PIMAGE_SYMBOL SymbolTable = (PIMAGE_SYMBOL)((ULONG)ScratchAddress + sizeof(ULONG));
|
|
ULONG SymbolCount = *(PULONG)ScratchAddress;
|
|
PCHAR StringTable = (PCHAR)&SymbolTable[SymbolCount];
|
|
|
|
// for each symbol
|
|
for (ULONG i = 0; i < SymbolCount; i += (1 + SymbolTable[i].NumberOfAuxSymbols)) {
|
|
// storage class must be external for a function
|
|
if (SymbolTable[i].StorageClass != IMAGE_SYM_CLASS_EXTERNAL) continue;
|
|
// symbol cannot be absolute
|
|
if (SymbolTable[i].SectionNumber == 0) continue;
|
|
if (SymbolTable[i].N.Name.Short == 0) {
|
|
// offset into string-table
|
|
if (!strcmp(SymbolName, &StringTable[SymbolTable[i].N.Name.Long])) {
|
|
// found it
|
|
return (PVOID)(ImageBase + SymbolTable[i].Value);
|
|
}
|
|
continue;
|
|
}
|
|
else {
|
|
// short symbol
|
|
if (
|
|
!memcmp(SymbolName, SymbolTable[i].N.ShortName, sizeof(SymbolTable[i].N.ShortName)) || // 8 character names aren't null terminated
|
|
!strcmp(SymbolName, SymbolTable[i].N.ShortName)
|
|
) {
|
|
// found it
|
|
return (PVOID)(ImageBase + SymbolTable[i].Value);
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static ARC_STATUS ArcLoadImpl(
|
|
IN PCHAR ImagePath,
|
|
IN ULONG TopAddress,
|
|
OUT PULONG EntryAddress,
|
|
OUT PULONG LowAddress,
|
|
OUT PULONG ImageBasePage,
|
|
OUT PULONG ImageSizePage
|
|
) {
|
|
if (EntryAddress == NULL || LowAddress == NULL) {
|
|
printf("Required pointers are NULL\n");
|
|
return _EFAULT;
|
|
}
|
|
PSECTION_RELOCATION_ENTRY RelocationTable = NULL;
|
|
BYTE LocalBuffer[2 * SECTOR_SIZE + 0x40];
|
|
// Align the COFF header to a dcache line.
|
|
PBYTE LocalPointer = (PVOID)(((ULONG)(&LocalBuffer[DCACHE_LINE_SIZE - 1])) & ~(DCACHE_LINE_SIZE - 1));
|
|
|
|
// Initialise the entry address to NULL.
|
|
*EntryAddress = 0;
|
|
|
|
PVENDOR_VECTOR_TABLE Api = ARC_VENDOR_VECTORS();
|
|
|
|
// Open the file to load readonly.
|
|
U32LE _FileId;
|
|
ARC_STATUS Status = Api->OpenRoutine(ImagePath, ArcOpenReadOnly, &_FileId);
|
|
if (ARC_FAIL(Status)) {
|
|
return Status;
|
|
}
|
|
ULONG FileId = _FileId.v;
|
|
|
|
do {
|
|
// Read two sectors to get the COFF header.
|
|
// Two sectors can fit COFF file header + full PE optional header + 19 section headers.
|
|
U32LE Count;
|
|
Status = Api->ReadRoutine(FileId, LocalPointer, SECTOR_SIZE * 2, &Count);
|
|
if (ARC_FAIL(Status)) break;
|
|
if (Count.v != SECTOR_SIZE * 2) {
|
|
printf("Tried to read %x bytes and read %x bytes", SECTOR_SIZE * 2, Count.v);
|
|
Status = _EFAULT;
|
|
break;
|
|
}
|
|
|
|
PIMAGE_FILE_HEADER FileHeader = (PIMAGE_FILE_HEADER)LocalPointer;
|
|
PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)LocalPointer;
|
|
bool IsFullPE = (DosHeader->e_magic == IMAGE_DOS_SIGNATURE);
|
|
if (IsFullPE) {
|
|
// this is full PE
|
|
Status = _EBADF;
|
|
break;
|
|
#if 0
|
|
if ((DosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS)) > Count.v) {
|
|
printf("Bad PE\n");
|
|
Status = _EBADF;
|
|
break;
|
|
}
|
|
NtHeaders = (PIMAGE_NT_HEADERS)(LocalPointer + DosHeader->e_lfanew);
|
|
FileHeader = &NtHeaders->FileHeader;
|
|
#endif
|
|
}
|
|
if (
|
|
// Don't accept any COFF that isn't for PPC(LE).
|
|
(FileHeader->Machine != IMAGE_FILE_MACHINE_POWERPC) || // && FileHeader->Machine != IMAGE_FILE_MACHINE_POWERPCBE) ||
|
|
// Don't accept a COFF that isn't executable.
|
|
(FileHeader->Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0 ||
|
|
// Don't accept a COFF with an optional header that's too small.
|
|
FileHeader->SizeOfOptionalHeader < sizeof(IMAGE_OPTIONAL_HEADER) // sizeof(IMAGE_OPTIONAL_HEADER_COFF)
|
|
) {
|
|
printf("Bad COFF\n");
|
|
Status = _EBADF;
|
|
break;
|
|
}
|
|
|
|
// NT kernels before (somewhere between 1234 and 1314) hardcode setting BATs to the first 8MB of RAM.
|
|
// So we need to set our memchunks up to handle this if we load an older NT bootloader.
|
|
// 1314 bootloaders were compiled mid-April 1996.
|
|
// NT 3.51 SP5 provides a newer veneer, but not a newer osloader.
|
|
// Thus, we can rely on the TimeDateStamp for this.
|
|
bool IsOldCoff = FileHeader->TimeDateStamp < 828316800; // 1996-04-01
|
|
|
|
bool IsLittleEndian = FileHeader->Machine == IMAGE_FILE_MACHINE_POWERPC;
|
|
//bool HasPEOptionalHeader = FileHeader->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER);
|
|
bool HasRelocations = (FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) == 0;
|
|
bool HasExceptions = false;
|
|
USHORT NumberOfSections = FileHeader->NumberOfSections;
|
|
PIMAGE_OPTIONAL_HEADER OptionalHeader = (PIMAGE_OPTIONAL_HEADER)&FileHeader[1];
|
|
PIMAGE_SECTION_HEADER Sections = (PIMAGE_SECTION_HEADER)((size_t)OptionalHeader + FileHeader->SizeOfOptionalHeader);
|
|
|
|
//if (HasPEOptionalHeader)
|
|
{
|
|
if (
|
|
// Optional header magic must be PE32
|
|
OptionalHeader->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC ||
|
|
// With the full PE optional header, the header size is known.
|
|
// If this is greater than what was read, then don't accept this file.
|
|
OptionalHeader->SizeOfHeaders > Count.v
|
|
) {
|
|
printf("Bad opthdr\n");
|
|
Status = _EBADF;
|
|
break;
|
|
}
|
|
|
|
// If base relocation directory addr or size is 0, then this executable has no relocations
|
|
PIMAGE_DATA_DIRECTORY RelocDir = &OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
|
|
HasRelocations = RelocDir->VirtualAddress != 0 && RelocDir->Size != 0;
|
|
PIMAGE_DATA_DIRECTORY ExceptionDir = &OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION];
|
|
HasExceptions = ExceptionDir->VirtualAddress != 0 && ExceptionDir->Size != 0;
|
|
}
|
|
#if 0
|
|
else if (HasRelocations) {
|
|
// Walk through all sections, if one section has relocations then reloc is allowed.
|
|
HasRelocations = false;
|
|
for (int i = 0; i < NumberOfSections; i++) {
|
|
if (Sections[i].NumberOfRelocations != 0) {
|
|
HasRelocations = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
ULONG SizeOfImage;
|
|
ULONG ImageBase;
|
|
|
|
//if (HasPEOptionalHeader)
|
|
{
|
|
// Ignore the caller.
|
|
// This is a COFF with a full PE optional header, and has a known base.
|
|
ImageBase = OptionalHeader->ImageBase & ~0xC0000000;
|
|
SizeOfImage = OptionalHeader->SizeOfImage;
|
|
}
|
|
#if 0
|
|
else if (HasRelocations) {
|
|
SizeOfImage = OptionalHeader->SizeOfCode + OptionalHeader->SizeOfInitializedData + OptionalHeader->SizeOfUninitializedData;
|
|
ImageBase = (TopAddress - SizeOfImage) - ~(PAGE_SIZE - 1);
|
|
}
|
|
else {
|
|
// a COFF with no relocations
|
|
ImageBase = OptionalHeader->BaseOfCode;
|
|
SizeOfImage = OptionalHeader->BaseOfData + OptionalHeader->SizeOfInitializedData - ImageBase;
|
|
}
|
|
#endif
|
|
|
|
//ULONG ImageBasePage = (ImageBase & 0x1FFFFFFF) >> PAGE_SHIFT;
|
|
|
|
// If the last section is named ".debug", don't load it
|
|
if (!strcmp((const char*)Sections[NumberOfSections - 1].Name, ".debug")) {
|
|
NumberOfSections--;
|
|
SizeOfImage -= Sections[NumberOfSections].SizeOfRawData;
|
|
OptionalHeader->SizeOfImage = SizeOfImage;
|
|
FileHeader->NumberOfSections = NumberOfSections;
|
|
}
|
|
|
|
if (NumberOfSections == 0) {
|
|
// nothing to load?
|
|
printf("No sections to load\n");
|
|
Status = _EBADF;
|
|
break;
|
|
}
|
|
|
|
ULONG ImageBaseK0 = (ULONG)MEM_PHYSICAL_TO_K0(ImageBase);
|
|
*LowAddress = ImageBaseK0;
|
|
*EntryAddress = ImageBaseK0 + OptionalHeader->AddressOfEntryPoint - OptionalHeader->BaseOfCode;
|
|
if (ImageBasePage) *ImageBasePage = ImageBase >> PAGE_SHIFT;
|
|
if (ImageSizePage) *ImageSizePage = (SizeOfImage + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
|
|
|
// Allocate and zero the relocation table if needed.
|
|
#if 0
|
|
if (HasRelocations && !HasPEOptionalHeader) {
|
|
size_t LenRelocs = sizeof(RelocationTable[0]) * NumberOfSections;
|
|
RelocationTable = malloc(LenRelocs);
|
|
if (RelocationTable == NULL) {
|
|
Status = _ENOMEM;
|
|
break;
|
|
}
|
|
memset(RelocationTable, 0, LenRelocs);
|
|
}
|
|
#endif
|
|
|
|
ULONG SectionOffset = 0;
|
|
|
|
// Load sections into memory.
|
|
USHORT NumberOfSectionsToLoad = NumberOfSections;
|
|
//if (IsLittleEndian) NumberOfSectionsToLoad--;
|
|
for (int i = 0; i < NumberOfSectionsToLoad; i++) {
|
|
ULONG Flags = Sections[i].Characteristics;
|
|
ULONG SectionBase = ImageBaseK0 + SectionOffset;
|
|
|
|
#if 0
|
|
if (HasRelocations && !HasPEOptionalHeader) {
|
|
PSECTION_RELOCATION_ENTRY RelocEntry = &RelocationTable[i];
|
|
RelocEntry->FixupValue = SectionBase - Sections[i].VirtualAddress;
|
|
RelocEntry->NumberOfRelocations = Sections[i].NumberOfRelocations;
|
|
RelocEntry->PointerToRelocations = Sections[i].PointerToRelocations;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
SectionBase = Sections[i].VirtualAddress;
|
|
//if (HasPEOptionalHeader)
|
|
{
|
|
SectionBase += ImageBaseK0;
|
|
}
|
|
}
|
|
|
|
// If needed, read this section into memory
|
|
bool IncreaseOffset = false;
|
|
if ((Flags & SECTION_REQUIRES_LOAD) != 0) {
|
|
LARGE_INTEGER SeekPosition = Int64ToLargeInteger(Sections[i].PointerToRawData);
|
|
Status = Api->SeekRoutine(FileId, &SeekPosition, SeekAbsolute);
|
|
if (ARC_FAIL(Status)) break;
|
|
Status = Api->ReadRoutine(FileId, (PVOID)SectionBase, Sections[i].SizeOfRawData, &Count);
|
|
if (ARC_FAIL(Status)) break;
|
|
if (Count.v != Sections[i].SizeOfRawData) {
|
|
printf("Tried to read %x bytes and read %x bytes\n", Sections[i].SizeOfRawData, Count.v);
|
|
Status = _EFAULT;
|
|
break;
|
|
}
|
|
IncreaseOffset = true;
|
|
}
|
|
else if ((Flags & SECTION_REQUIRES_ZERO) != 0) {
|
|
memset((PVOID)SectionBase, 0, Sections[i].SizeOfRawData);
|
|
IncreaseOffset = true;
|
|
}
|
|
|
|
if (IncreaseOffset) {
|
|
SectionOffset += Sections[i].SizeOfRawData;
|
|
}
|
|
}
|
|
if (ARC_FAIL(Status)) break;
|
|
|
|
// Relocate the COFF.
|
|
#if 0 // Required code patching is done here (to fix overly strict processor checks). Enforce it.
|
|
if (HasRelocations || IsLittleEndian)
|
|
#endif
|
|
{
|
|
Status = RelocatePE(ImageBaseK0, FileHeader, OptionalHeader, Sections);
|
|
#if 0
|
|
if (HasPEOptionalHeader) {
|
|
Status = RelocatePE(ImageBaseK0, FileHeader, OptionalHeader, Sections);
|
|
}
|
|
else {
|
|
Status = RelocateCoff(FileId, RelocationTable, NumberOfSections, FileHeader->PointerToSymbolTable);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (ARC_FAIL(Status)) break;
|
|
s_OldCoffLoaded = IsOldCoff;
|
|
|
|
#if 1 // no more hooking any more, no more hooking any more
|
|
// For a COFF binary with a PE optional header; we need to hook things.
|
|
if (s_RuntimePointers[RUNTIME_SYSTEM_TYPE].v >= ARTX_SYSTEM_VEGAS)
|
|
{
|
|
// Read entire symbol table to scratch memory in DDR
|
|
Status = ReadCoffSymbolTable(FileId, FileHeader->PointerToSymbolTable, FileHeader->NumberOfSymbols);
|
|
if (ARC_FAIL(Status)) break;
|
|
|
|
//printf("Image Base: %08x\r\n", ImageBaseK0);
|
|
// Get address of BlOpen, BlFileTable, BlSetupForNt using COFF symbol table
|
|
PVOID BlOpen = GetSymbolEntryCoff(ImageBaseK0, "..BlOpen");
|
|
PVOID BlFileTable = GetSymbolEntryCoff(ImageBaseK0, "BlFileTable");
|
|
PVOID BlSetupForNt = GetSymbolEntryCoff(ImageBaseK0, "..BlSetupForNt");
|
|
PVOID BlReadSignature = GetSymbolEntryCoff(ImageBaseK0, "..BlReadSignature");
|
|
if (BlOpen != NULL && BlFileTable != NULL && BlSetupForNt != NULL && BlReadSignature != NULL) {
|
|
// This must be an osloader binary (linked with ARC bootlib)
|
|
OslHookInit(BlOpen, BlFileTable, BlSetupForNt, BlReadSignature);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Flush all caches.
|
|
Api->FlushAllCachesRoutine();
|
|
} while (false);
|
|
if (RelocationTable != NULL) free(RelocationTable);
|
|
Api->CloseRoutine(FileId);
|
|
return Status;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Loads a COFF executable.
|
|
/// </summary>
|
|
/// <param name="ImagePath">Path of the executable to load.</param>
|
|
/// <param name="TopAddress">Address to load the COFF to</param>
|
|
/// <param name="EntryAddress">Entry point is written here</param>
|
|
/// <param name="LowAddress">End address of the loaded executable is written here</param>
|
|
/// <returns>ARC status code</returns>
|
|
static ARC_STATUS ArcLoad(
|
|
IN PCHAR ImagePath,
|
|
IN ULONG TopAddress,
|
|
OUT PU32LE EntryAddress,
|
|
OUT PU32LE LowAddress
|
|
) {
|
|
ULONG LocalEntry, LocalLow;
|
|
ARC_STATUS Status = ArcLoadImpl(ImagePath, TopAddress, &LocalEntry, &LocalLow, NULL, NULL);
|
|
if (ARC_FAIL(Status)) return Status;
|
|
if (EntryAddress != NULL) EntryAddress->v = LocalEntry;
|
|
if (LowAddress != NULL) LowAddress->v = LocalLow;
|
|
return Status;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calls the entry point of a previously loaded program.
|
|
/// </summary>
|
|
/// <param name="EntryAddress">Entry point to call.</param>
|
|
/// <param name="StackAddress">Stack pointer to set.</param>
|
|
/// <param name="Argc">Number of arguments.</param>
|
|
/// <param name="Argv">Array of arguments.</param>
|
|
/// <param name="Envp">Environment variables.</param>
|
|
/// <returns>ARC status code.</returns>
|
|
static ARC_STATUS ArcInvoke(
|
|
IN ULONG EntryAddress,
|
|
IN ULONG StackAddress,
|
|
IN ULONG Argc,
|
|
IN PCHAR Argv[],
|
|
IN PCHAR Envp[]
|
|
) {
|
|
// Both entry point and stack pointer must be aligned to 32 bits.
|
|
if ((EntryAddress & 3) != 0 || (StackAddress & 3) != 0) {
|
|
printf("Unaligned entry/stack addrs\n");
|
|
return _EFAULT;
|
|
}
|
|
|
|
// If we have loaded an older COFF executable, fix the memory chunks to set anything > 8MB and < 256MB as LoadedProgram.
|
|
if (s_OldCoffLoaded && !s_MemoryMapFixedForOldCoff) {
|
|
PVENDOR_VECTOR_TABLE Api = ARC_VENDOR_VECTORS();
|
|
for (
|
|
PMEMORY_DESCRIPTOR MemChunk = Api->MemoryRoutine(NULL);
|
|
MemChunk != NULL;
|
|
MemChunk = Api->MemoryRoutine(MemChunk)
|
|
) {
|
|
// Looking for a free memchunk
|
|
if (MemChunk->MemoryType != MemoryFree) continue;
|
|
|
|
// Starting from 8MB
|
|
if (MemChunk->BasePage < (0x800000 / PAGE_SIZE)) continue;
|
|
|
|
// Ending at or before 256MB
|
|
ULONG ChunkEnd = MemChunk->BasePage + MemChunk->PageCount;
|
|
if (ChunkEnd > (256 * (0x100000 / PAGE_SIZE))) continue;
|
|
|
|
// Mark it as LoadedProgram.
|
|
// (Motorola and IBM ARC firmware implementations do this)
|
|
// Older implementations use FirmwareTemporary, but if we have a false positive then newer NT bootloaders will detect LoadedProgram here and treat it as free.
|
|
MemChunk->MemoryType = MemoryLoadedProgram;
|
|
}
|
|
|
|
s_MemoryMapFixedForOldCoff = true;
|
|
}
|
|
|
|
if (!s_MemoryMapFixedForAnyCoff) {
|
|
PVENDOR_VECTOR_TABLE Api = ARC_VENDOR_VECTORS();
|
|
for (
|
|
PMEMORY_DESCRIPTOR MemChunk = Api->MemoryRoutine(NULL);
|
|
MemChunk != NULL;
|
|
MemChunk = Api->MemoryRoutine(MemChunk)
|
|
) {
|
|
// Looking for a free memchunk
|
|
if (MemChunk->MemoryType != MemoryFree) continue;
|
|
|
|
// Starting from 256MB
|
|
if (MemChunk->BasePage < (0x10000000 / PAGE_SIZE)) continue;
|
|
|
|
// Mark it as FirmwareTemporary
|
|
MemChunk->MemoryType = MemoryFirmwareTemporary;
|
|
}
|
|
|
|
s_MemoryMapFixedForAnyCoff = true;
|
|
}
|
|
|
|
|
|
// Stack pointer is otherwise unused, do not change it.
|
|
|
|
PU32LE CallingConv = (PU32LE)EntryAddress;
|
|
//printf("Entry point: %08x - toc: %08x\r\n", CallingConv[0].v, CallingConv[1].v);
|
|
// Read from the entry point to make sure it's mapped, yay for having pagetables instead of BATs!
|
|
*(volatile ULONG*)(CallingConv[0].v);
|
|
extern void __ArcInvokeImpl(ULONG EntryAddress, ULONG Toc, ULONG Argc, PCHAR Argv[], PCHAR Envp[]);
|
|
__ArcInvokeImpl(CallingConv[0].v, CallingConv[1].v, Argc, Argv, Envp);
|
|
return _ESUCCESS;
|
|
}
|
|
|
|
// Copy arguments to a buffer handled by the ARC firmware implementation
|
|
static ARC_STATUS CopyArguments(ULONG Argc, PCHAR Argv[], PCHAR Envp[]) {
|
|
SavedArgs.Argc = Argc;
|
|
memset(SavedArgs.Arguments, 0, sizeof(SavedArgs.Arguments));
|
|
ULONG Length = sizeof(SavedArgs.Arguments);
|
|
ULONG Offset = 0;
|
|
for (ULONG Arg = 0; Arg < Argc; Arg++) {
|
|
ULONG RemainingLength = Length - Offset;
|
|
int err = snprintf(&SavedArgs.Arguments[Offset], RemainingLength, "%s", Argv[Arg]);
|
|
if (err < 0) {
|
|
printf("Could not copy argument %d\n", Arg);
|
|
return _EFAULT;
|
|
}
|
|
if (err >= RemainingLength) return _E2BIG;
|
|
SavedArgs.Argv[Arg].v = (ULONG)&SavedArgs.Arguments[Offset];
|
|
Offset += err;
|
|
SavedArgs.Arguments[Offset] = 0;
|
|
Offset++;
|
|
}
|
|
memset(SavedArgs.Envp, 0, sizeof(SavedArgs.Envp));
|
|
for (ULONG Arg = 0; Envp[Arg] != NULL; Arg++) {
|
|
SavedArgs.Envp[Arg].v = (ULONG)Envp[Arg];
|
|
}
|
|
return _ESUCCESS;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Loads and executes a COFF executable.
|
|
/// </summary>
|
|
/// <param name="ImagePath">Path of the executable to load.</param>
|
|
/// <param name="Argc">Number of arguments.</param>
|
|
/// <param name="Argv">Array of arguments.</param>
|
|
/// <param name="Envp">Environment variables.</param>
|
|
/// <returns>ARC status code.</returns>
|
|
static ARC_STATUS ArcExecute(
|
|
IN PCHAR ImagePath,
|
|
IN ULONG Argc,
|
|
IN PCHAR Argv[],
|
|
IN PCHAR Envp[]
|
|
) {
|
|
PVENDOR_VECTOR_TABLE Api = ARC_VENDOR_VECTORS();
|
|
char CopyPath[260];
|
|
|
|
// Copy the arguments and path so the provided buffers can be overwritten if needed
|
|
ARC_STATUS Status = CopyArguments(Argc, Argv, Envp);
|
|
if (ARC_FAIL(Status)) return Status;
|
|
int err = snprintf(CopyPath, sizeof(CopyPath), "%s", ImagePath);
|
|
if (err < 0) return _EFAULT;
|
|
if (err >= sizeof(CopyPath)) return _E2BIG;
|
|
|
|
// Find an area of memory.
|
|
for (
|
|
PMEMORY_DESCRIPTOR MemChunk = Api->MemoryRoutine(NULL);
|
|
MemChunk != NULL;
|
|
MemChunk = Api->MemoryRoutine(MemChunk)
|
|
) {
|
|
// Looking for a free memchunk
|
|
if (MemChunk->MemoryType != MemoryFree) continue;
|
|
// At least 4MB
|
|
if (MemChunk->PageCount < (ARC_MB(4) / PAGE_SIZE)) continue;
|
|
|
|
// Try to load here
|
|
ULONG EntryPoint, BaseAddress, ImageBasePage, ImageSizePage;
|
|
Status = ArcLoadImpl(CopyPath, MemChunk->BasePage + MemChunk->PageCount, &EntryPoint, &BaseAddress, &ImageBasePage, &ImageSizePage);
|
|
if (ARC_FAIL(Status)) {
|
|
if (Status != _ENOMEM) return Status;
|
|
continue;
|
|
}
|
|
|
|
// Find the memory descriptor used.
|
|
PMEMORY_DESCRIPTOR UsedChunk = ArcMemFindChunk(ImageBasePage, ImageSizePage);
|
|
|
|
if (UsedChunk == NULL) {
|
|
// what?
|
|
printf("Could not find used mem chunk\n");
|
|
return _EFAULT;
|
|
}
|
|
|
|
// Initialise a memchunk for this executable
|
|
Status = ArcMemAllocateFromFreeChunk(UsedChunk, ImageBasePage, ImageSizePage, MemoryLoadedProgram);
|
|
if (ARC_FAIL(Status)) return Status;
|
|
|
|
// Dump memchunks for debug.
|
|
#if 0
|
|
printf("Prg: %08x-%08x\r\n", ImageBasePage * PAGE_SIZE, (ImageBasePage + ImageSizePage) * PAGE_SIZE);
|
|
for (PMEMORY_DESCRIPTOR MemChunk = Api->MemoryRoutine(NULL); MemChunk != NULL; MemChunk = Api->MemoryRoutine(MemChunk)) {
|
|
printf("%x: %08x-%08x\r\n", MemChunk->MemoryType, MemChunk->BasePage * PAGE_SIZE, (MemChunk->BasePage + MemChunk->PageCount) * PAGE_SIZE);
|
|
}
|
|
IOSKBD_ReadChar();
|
|
#endif
|
|
|
|
Status = Api->InvokeRoutine(EntryPoint, BaseAddress, SavedArgs.Argc, (PCHAR*) SavedArgs.Argv, (PCHAR*) SavedArgs.Envp);
|
|
if (ARC_SUCCESS(Status)) UsedChunk->MemoryType = MemoryLoadedProgram;
|
|
return Status;
|
|
}
|
|
|
|
return _ENOMEM;
|
|
}
|
|
|
|
void ArcLoadInit(void) {
|
|
PVENDOR_VECTOR_TABLE Api = ARC_VENDOR_VECTORS();
|
|
Api->LoadRoutine = ArcLoad;
|
|
Api->InvokeRoutine = ArcInvoke;
|
|
Api->ExecuteRoutine = ArcExecute;
|
|
|
|
// Initialise the scratch address.
|
|
// Try to allocate some memory for this, hopefully in an area that cannot be used by boot.
|
|
ScratchAddress = ArcMemAllocTemp(ARCFW_MEM2_SIZE, true);
|
|
if (ScratchAddress == NULL) ScratchAddress = ArcMemAllocTemp(ARCFW_MEM2_SIZE, false);
|
|
}
|