mirror of
https://github.com/ksherlock/mpw.git
synced 2024-12-22 15:29:45 +00:00
Loader::Native::LoadFile
This commit is contained in:
parent
60869a697a
commit
49dcba4173
@ -24,6 +24,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <CoreServices/CoreServices.h>
|
||||
|
||||
#include <cpu/defs.h>
|
||||
#include <cpu/CpuModule.h>
|
||||
#include <cpu/fmem.h>
|
||||
@ -32,12 +37,329 @@
|
||||
#include "toolbox.h"
|
||||
#include "stackframe.h"
|
||||
|
||||
#include "RM.h"
|
||||
#include "MM.h"
|
||||
|
||||
#include <macos/sysequ.h>
|
||||
|
||||
using ToolBox::Log;
|
||||
|
||||
namespace Loader {
|
||||
|
||||
namespace {
|
||||
|
||||
const uint32_t kCODE = 0x434f4445;
|
||||
|
||||
struct SegmentInfo
|
||||
{
|
||||
SegmentInfo()
|
||||
{}
|
||||
|
||||
SegmentInfo(uint32_t h, uint32_t a, uint32_t s, bool fm = false):
|
||||
handle(h), address(a), size(s), farModel(fm)
|
||||
{}
|
||||
|
||||
uint32_t handle = 0;
|
||||
uint32_t address = 0;
|
||||
uint32_t size = 0;
|
||||
bool farModel = false;
|
||||
};
|
||||
|
||||
struct Segment0Info
|
||||
{
|
||||
Segment0Info()
|
||||
{}
|
||||
uint32_t a5 = 0;
|
||||
uint32_t jtOffset = 0;
|
||||
uint32_t jtSize = 0;
|
||||
uint32_t jtStart = 0;
|
||||
uint32_t jtEnd = 0;
|
||||
};
|
||||
|
||||
std::vector<SegmentInfo> Segments;
|
||||
|
||||
void reloc1(const uint8_t *r, uint32_t address, uint32_t offset)
|
||||
{
|
||||
// %00000000 00000000 -> break
|
||||
// %0xxxxxxx -> 7-bit value
|
||||
// %1xxxxxxx xxxxxxxx -> 15-bit value
|
||||
// %00000000 1xxxxxxx x{8} x{8} x{8} -> 31 bit value
|
||||
// ^ that's what the documentation says..
|
||||
// that's how the 32-bit bootstrap works
|
||||
// DumpCode ignores the high 2 bytes.
|
||||
for(;;)
|
||||
{
|
||||
uint32_t x;
|
||||
uint32_t value;
|
||||
|
||||
x = *r++;
|
||||
|
||||
if (x == 0x00)
|
||||
{
|
||||
x = *r++;
|
||||
if (x == 0x00) break;
|
||||
|
||||
x = (x << 8) | *r++;
|
||||
x = (x << 8) | *r++;
|
||||
x = (x << 8) | *r++;
|
||||
}
|
||||
else if (x & 0x80)
|
||||
{
|
||||
x &= 0x7f;
|
||||
x = (x << 8) | *r++;
|
||||
}
|
||||
|
||||
x <<= 1; // * 2
|
||||
|
||||
address += x;
|
||||
|
||||
value = memoryReadLong(address);
|
||||
memoryWriteLong(value + offset, address);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// relocate a far model segment.
|
||||
void relocate(uint32_t address, uint32_t size, uint32_t a5)
|
||||
{
|
||||
// see MacOS RT Architecture, 10-23 .. 10-26
|
||||
uint32_t offset;
|
||||
|
||||
offset = memoryReadLong(address + 0x14);
|
||||
if (memoryReadLong(address + 0x18) != a5 && offset != 0)
|
||||
{
|
||||
memoryWriteLong(a5, address + 0x18); // current value of A5
|
||||
reloc1(memoryPointer(address + offset), address, a5);
|
||||
}
|
||||
|
||||
offset = memoryReadLong(address + 0x1c);
|
||||
if (memoryReadLong(address + 0x20) != address && offset != 0)
|
||||
{
|
||||
memoryWriteLong(address, address + 0x20); // segment load address.
|
||||
reloc1(memoryPointer(address + offset), address, address + 0x28);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// load code seg 0.
|
||||
uint16_t LoadCode0(Segment0Info &rv)
|
||||
{
|
||||
uint16_t err;
|
||||
uint32_t rHandle;
|
||||
uint32_t size;
|
||||
uint32_t address;
|
||||
|
||||
SegmentInfo si;
|
||||
|
||||
err = RM::Native::GetResource(kCODE, 0, rHandle);
|
||||
if (err) return err;
|
||||
|
||||
|
||||
MM::Native::HLock(rHandle);
|
||||
MM::Native::GetHandleSize(rHandle, size);
|
||||
|
||||
address = memoryReadLong(rHandle);
|
||||
|
||||
uint32_t above = memoryReadLong(address);
|
||||
uint32_t below = memoryReadLong(address + 4);
|
||||
rv.jtSize = memoryReadLong(address + 8);
|
||||
rv.jtOffset = memoryReadLong(address + 12);
|
||||
|
||||
si.size = above + below;
|
||||
|
||||
|
||||
// create a new handle for the a5 segment.
|
||||
err = MM::Native::NewHandle(si.size, true, si.handle, si.address);
|
||||
if (err) return err;
|
||||
|
||||
MM::Native::HLock(si.handle);
|
||||
|
||||
rv.a5 = si.address + below;
|
||||
|
||||
// copy jump table data from the CODE segment
|
||||
// to the new handle.
|
||||
std::memcpy(memoryPointer(rv.a5 + rv.jtOffset), memoryPointer(address + 16), rv.jtSize);
|
||||
|
||||
if (Segments.size() <= 0)
|
||||
Segments.resize(0 + 1);
|
||||
Segments[0] = si;
|
||||
|
||||
rv.jtStart = rv.a5 + rv.jtOffset;
|
||||
rv.jtEnd = rv.jtStart + rv.jtSize;
|
||||
|
||||
// TODO -- should ReleaseResource on rHandle.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// load a standard code segment.
|
||||
uint16_t LoadCode(uint16_t segment)
|
||||
{
|
||||
uint16_t err;
|
||||
|
||||
SegmentInfo si;
|
||||
|
||||
err = RM::Native::GetResource(kCODE, segment, si.handle);
|
||||
if (err) return err;
|
||||
|
||||
MM::Native::HLock(si.handle);
|
||||
MM::Native::GetHandleSize(si.handle, si.size);
|
||||
|
||||
si.address = memoryReadLong(si.handle);
|
||||
|
||||
if (memoryReadWord(si.address) == 0xffff)
|
||||
si.farModel = true;
|
||||
|
||||
if (Segments.size() <= segment)
|
||||
Segments.resize(segment + 1);
|
||||
|
||||
Segments[segment] = si;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
namespace Native
|
||||
{
|
||||
|
||||
uint16_t LoadFile(const std::string &path)
|
||||
{
|
||||
|
||||
HFSUniStr255 fork = {0,{0}};
|
||||
ResFileRefNum refNum;
|
||||
FSRef ref;
|
||||
OSErr err;
|
||||
|
||||
// open the file
|
||||
// load code seg 0
|
||||
// iterate and load other segments
|
||||
|
||||
|
||||
// TODO -- call RM::Native::OpenResourceFile(...);
|
||||
|
||||
err = FSPathMakeRef( (const UInt8 *)path.c_str(), &ref, NULL);
|
||||
if (err) return err;
|
||||
|
||||
|
||||
::FSGetResourceForkName(&fork);
|
||||
|
||||
err = ::FSOpenResourceFile(&ref,
|
||||
fork.length,
|
||||
fork.unicode,
|
||||
fsRdPerm,
|
||||
&refNum);
|
||||
|
||||
if (err) return err;
|
||||
|
||||
|
||||
// in case of restart?
|
||||
Segments.clear();
|
||||
|
||||
RM::Native::SetResLoad(true);
|
||||
|
||||
// load code 0.
|
||||
Segment0Info seg0;
|
||||
err = LoadCode0(seg0);
|
||||
|
||||
// iterate through the jump table to get the other
|
||||
// code segments to load
|
||||
bool farModel = false;
|
||||
for (uint32_t jtEntry = seg0.jtStart; jtEntry < seg0.jtEnd; jtEntry += 8)
|
||||
{
|
||||
uint16_t seg;
|
||||
uint32_t offset;
|
||||
|
||||
if (farModel)
|
||||
{
|
||||
seg = memoryReadWord(jtEntry + 0);
|
||||
offset = memoryReadLong(jtEntry + 4);
|
||||
|
||||
assert(memoryReadWord(jtEntry + 2) == 0xA9F0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (memoryReadWord(jtEntry + 2) == 0xffff)
|
||||
{
|
||||
farModel = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
offset = memoryReadWord(jtEntry + 0);
|
||||
seg = memoryReadWord(jtEntry + 4);
|
||||
|
||||
assert(memoryReadWord(jtEntry + 2) == 0x3F3C);
|
||||
assert(memoryReadWord(jtEntry + 6) == 0xA9F0);
|
||||
}
|
||||
|
||||
// load, if necessary.
|
||||
assert(seg);
|
||||
|
||||
if (seg >= Segments.size() || Segments[seg].address == 0)
|
||||
{
|
||||
err = LoadCode(seg);
|
||||
if (err) return err;
|
||||
|
||||
const auto &p = Segments[seg];
|
||||
if (p.farModel)
|
||||
{
|
||||
relocate(p.address, p.size, seg0.a5);
|
||||
}
|
||||
}
|
||||
|
||||
const auto &p = Segments[seg];
|
||||
|
||||
assert(p.address); // missing segment?!
|
||||
assert(offset < p.size);
|
||||
|
||||
// +$4/$28 for the jump table info header.
|
||||
uint32_t address = p.address + offset + (p.farModel ? 0x00 : 0x04); // was 0x28
|
||||
|
||||
if (!p.farModel)
|
||||
memoryWriteWord(seg, jtEntry + 0);
|
||||
|
||||
memoryWriteWord(0x4EF9, jtEntry + 2);
|
||||
memoryWriteLong(address, jtEntry + 4);
|
||||
}
|
||||
|
||||
// seg:16, jmp:16, address:32
|
||||
uint32_t pc = memoryReadLong(seg0.jtStart + 4);
|
||||
|
||||
cpuSetAReg(5, seg0.a5);
|
||||
cpuInitializeFromNewPC(pc);
|
||||
|
||||
|
||||
// 0x0934 - CurJTOffset (16-bit)
|
||||
memoryWriteWord(seg0.jtOffset, MacOS::CurJTOffset);
|
||||
|
||||
// 0x0904 -- CurrentA5 (32-bit)
|
||||
memoryWriteLong(seg0.a5, MacOS::CurrentA5);
|
||||
|
||||
// 0x0910 CurApName (31-char max pstring.)
|
||||
{
|
||||
std::string s;
|
||||
|
||||
auto ix = path.rfind('/');
|
||||
if (ix == path.npos)
|
||||
{
|
||||
s = path.substr(0, 31);
|
||||
}
|
||||
else
|
||||
{
|
||||
s = path.substr(ix + 1, 31);
|
||||
}
|
||||
|
||||
ToolBox::WritePString(MacOS::CurApName, s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
} // Internal namespace
|
||||
|
||||
|
||||
/*
|
||||
* struct { uint32_t a5; uint32_t pc; };
|
||||
|
@ -5,6 +5,19 @@
|
||||
|
||||
namespace Loader {
|
||||
|
||||
namespace Native {
|
||||
|
||||
/*
|
||||
* loads the file
|
||||
* sets registers PC and A5.
|
||||
* sets certain globals.
|
||||
*
|
||||
* Dependencies: MM, RM
|
||||
*/
|
||||
uint16_t LoadFile(const std::string &path);
|
||||
|
||||
}
|
||||
|
||||
uint16_t UnloadSeg(uint16_t trap);
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user