mirror of
https://github.com/ksherlock/mpw.git
synced 2025-08-10 10:25:13 +00:00
Merge branch 'FarJump'
This commit is contained in:
@@ -82,19 +82,47 @@ void code0(uint32_t data_size)
|
||||
|
||||
offset = 16;
|
||||
|
||||
bool longA5 = false;
|
||||
while (offset < data_size)
|
||||
{
|
||||
uint16_t off = memoryReadWord(offset);
|
||||
if (memoryReadWord(offset + 2) == 0x3F3C && memoryReadWord(offset + 6) == 0xA9F0)
|
||||
{
|
||||
uint16_t seg = memoryReadWord(offset + 4);
|
||||
|
||||
// pc +2 since the first byte is the offset, not code.
|
||||
printf("$%08X %04X : %04X\n", pc + 2, seg, off);
|
||||
if (longA5)
|
||||
{
|
||||
uint16_t segment = memoryReadWord(offset);
|
||||
uint32_t segOffset = memoryReadLong(offset + 4);
|
||||
|
||||
if (memoryReadWord(offset + 2) == 0xA9F0)
|
||||
{
|
||||
printf("$%08X %04X : %08X\n", pc + 2, segment, segOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("$%08X ???\n", pc + 2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("$%08X ???\n", pc + 2);
|
||||
uint16_t data[4];
|
||||
for (unsigned i = 0; i < 4; ++i)
|
||||
data[i] = memoryReadWord(offset + 2 * i);
|
||||
|
||||
if (data[1] == 0xffff)
|
||||
{
|
||||
longA5 = true;
|
||||
printf("--------\n");
|
||||
}
|
||||
else if (data[1] == 0x3F3C && data[3] == 0xA9F0)
|
||||
{
|
||||
uint16_t segOffset = data[0];
|
||||
uint16_t segment = data[2];
|
||||
|
||||
// pc +2 since the first byte is the offset, not code.
|
||||
printf("$%08X %04X : %04X\n", pc + 2, segment, segOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("$%08X ???\n", pc + 2);
|
||||
}
|
||||
}
|
||||
offset += 8;
|
||||
pc += 8;
|
||||
@@ -252,9 +280,18 @@ int main(int argc, char **argv)
|
||||
}
|
||||
else
|
||||
{
|
||||
// 4-byte header for segment stuff.
|
||||
data += 4;
|
||||
size -= 4;
|
||||
// near model uses a $4-byte header.
|
||||
// far model uses a $28-byte header.
|
||||
if (data[0] == 0xff && data[1] == 0xff)
|
||||
{
|
||||
data += 0x28;
|
||||
size -= 0x28;
|
||||
}
|
||||
else
|
||||
{
|
||||
data += 0x04;
|
||||
size -= 0x04;
|
||||
}
|
||||
memorySetMemory(data, size);
|
||||
disasm(cname.c_str(), resID, size);
|
||||
}
|
||||
|
156
bin/loader.cpp
156
bin/loader.cpp
@@ -47,6 +47,7 @@
|
||||
#include <toolbox/toolbox.h>
|
||||
#include <toolbox/mm.h>
|
||||
#include <toolbox/os.h>
|
||||
#include <toolbox/loader.h>
|
||||
|
||||
#include <mpw/mpw.h>
|
||||
|
||||
@@ -58,6 +59,9 @@
|
||||
#include "loader.h"
|
||||
#include "debugger.h"
|
||||
|
||||
|
||||
#define LOADER_LOAD
|
||||
|
||||
Settings Flags;
|
||||
|
||||
const uint32_t kGlobalSize = 0x10000;
|
||||
@@ -130,7 +134,68 @@ void WriteLong(void *data, uint32_t offset, uint32_t value)
|
||||
((uint8_t *)data)[offset++] = value;
|
||||
}
|
||||
|
||||
#ifndef LOADER_LOAD
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t load(const char *file)
|
||||
{
|
||||
@@ -140,7 +205,22 @@ uint32_t load(const char *file)
|
||||
|
||||
uint32_t returnAddress = 0;
|
||||
|
||||
std::vector< std::pair<uint32_t, uint32_t> > segments; // segment, address
|
||||
struct SegInfo {
|
||||
public:
|
||||
|
||||
SegInfo()
|
||||
{}
|
||||
|
||||
SegInfo(uint32_t a, uint32_t s, bool f) :
|
||||
address(a), size(s), farModel(f)
|
||||
{}
|
||||
|
||||
uint32_t address = 0;
|
||||
uint32_t size = 0;
|
||||
bool farModel = 0;
|
||||
|
||||
};
|
||||
std::vector< SegInfo> segments;
|
||||
|
||||
|
||||
uint32_t a5 = 0;
|
||||
@@ -151,6 +231,8 @@ uint32_t load(const char *file)
|
||||
// todo -- call RM::Native to open and load the Resource File.
|
||||
|
||||
assert(FSPathMakeRef( (const UInt8 *)file, &ref, NULL) == noErr);
|
||||
// todo -- if it wasn't a resource file, this will fail
|
||||
// should provide a nicer error message.
|
||||
refNum = FSOpenResFile(&ref, fsRdPerm);
|
||||
assert(refNum != -1 );
|
||||
|
||||
@@ -209,7 +291,7 @@ uint32_t load(const char *file)
|
||||
a5 = address + below;
|
||||
std::memcpy(memoryPointer(a5 + jtOffset), data + 16 , jtSize);
|
||||
|
||||
segments[resID] = std::make_pair(address, a5size);
|
||||
segments[resID] = SegInfo(address, a5size, false);
|
||||
|
||||
jtStart = a5 + jtOffset;
|
||||
jtEnd = jtStart + jtSize;
|
||||
@@ -224,6 +306,9 @@ uint32_t load(const char *file)
|
||||
}
|
||||
else
|
||||
{
|
||||
bool farModel = false;
|
||||
if (data[0] == 0xff && data[1] == 0xff) farModel = true;
|
||||
|
||||
error = MM::Native::NewPtr(size, false, address);
|
||||
if (error)
|
||||
{
|
||||
@@ -233,7 +318,7 @@ uint32_t load(const char *file)
|
||||
|
||||
std::memcpy(memoryPointer(address), data, size);
|
||||
|
||||
segments[resID] = std::make_pair(address, size);
|
||||
segments[resID] = SegInfo(address, size, farModel);
|
||||
}
|
||||
|
||||
ReleaseResource(h);
|
||||
@@ -243,22 +328,46 @@ uint32_t load(const char *file)
|
||||
assert(a5);
|
||||
|
||||
bool first = true;
|
||||
bool farModel = false;
|
||||
for (; jtStart < jtEnd; jtStart += 8)
|
||||
{
|
||||
uint16_t offset = memoryReadWord(jtStart);
|
||||
uint16_t seg = memoryReadWord(jtStart + 4);
|
||||
uint16_t seg;
|
||||
uint32_t offset;
|
||||
if (farModel)
|
||||
{
|
||||
seg = memoryReadWord(jtStart + 0);
|
||||
offset = memoryReadLong(jtStart + 4);
|
||||
|
||||
assert(memoryReadWord(jtStart + 2) == 0x3F3C);
|
||||
assert(memoryReadWord(jtStart + 6) == 0xA9F0);
|
||||
assert(memoryReadWord(jtStart + 2) == 0xA9F0);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t farModelCheck;
|
||||
offset = memoryReadWord(jtStart);
|
||||
farModelCheck = memoryReadWord(jtStart + 2);
|
||||
seg = memoryReadWord(jtStart + 4);
|
||||
|
||||
assert(seg < segments.size());
|
||||
if (farModelCheck == 0xffff)
|
||||
{
|
||||
farModel = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(memoryReadWord(jtStart + 2) == 0x3F3C);
|
||||
assert(memoryReadWord(jtStart + 6) == 0xA9F0);
|
||||
}
|
||||
|
||||
assert(seg < segments.size());
|
||||
|
||||
auto p = segments[seg];
|
||||
assert(p.first); // missing segment?!
|
||||
assert(offset < p.second);
|
||||
//assert(p.first); // missing segment?!
|
||||
//assert(offset < p.second);
|
||||
|
||||
// +4 for the jump table info header.
|
||||
uint32_t address = p.first + offset + 4;
|
||||
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
|
||||
|
||||
// JMP absolute long
|
||||
memoryWriteWord(0x4EF9, jtStart + 2);
|
||||
@@ -272,11 +381,21 @@ uint32_t load(const char *file)
|
||||
}
|
||||
}
|
||||
|
||||
// far-model relocation. This happens here, after a5 is loaded.
|
||||
|
||||
for (const auto &seg : segments)
|
||||
{
|
||||
if (seg.farModel)
|
||||
{
|
||||
relocate(seg.address, seg.size, a5);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// set pc to jump table entry 0.
|
||||
return returnAddress;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void GlobalInit()
|
||||
@@ -785,10 +904,13 @@ int main(int argc, char **argv)
|
||||
|
||||
CreateStack();
|
||||
|
||||
|
||||
#ifdef LOADER_LOAD
|
||||
uint16_t err = Loader::Native::LoadFile(command);
|
||||
if (err) exit(EX_CONFIG);
|
||||
#else
|
||||
uint32_t address = load(command.c_str());
|
||||
if (!address) exit(EX_CONFIG);
|
||||
|
||||
#endif
|
||||
GlobalInit();
|
||||
|
||||
|
||||
@@ -811,9 +933,9 @@ int main(int argc, char **argv)
|
||||
// else do it manually below.
|
||||
}
|
||||
|
||||
|
||||
#ifndef LOADER_LOAD
|
||||
cpuInitializeFromNewPC(address);
|
||||
|
||||
#endif
|
||||
|
||||
if (Flags.debugger) Debug::Shell();
|
||||
else MainLoop();
|
||||
|
@@ -6,8 +6,9 @@ add_definitions(-I ${CMAKE_SOURCE_DIR}/)
|
||||
|
||||
set(TOOLBOX_SRC
|
||||
toolbox.cpp
|
||||
rm.cpp
|
||||
mm.cpp
|
||||
loader.cpp
|
||||
rm.cpp
|
||||
os.cpp
|
||||
os_internal.cpp
|
||||
os_hfs_dispatch.cpp
|
||||
|
395
toolbox/loader.cpp
Normal file
395
toolbox/loader.cpp
Normal file
@@ -0,0 +1,395 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Kelvin W Sherlock
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <CoreServices/CoreServices.h>
|
||||
|
||||
#include <cpu/defs.h>
|
||||
#include <cpu/CpuModule.h>
|
||||
#include <cpu/fmem.h>
|
||||
|
||||
#include "loader.h"
|
||||
#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; };
|
||||
* future state: Native::LoadFile(const std::string &path, a5pc) ->
|
||||
* load file, set global page variables, set A5, return PC.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
uint16_t UnloadSeg(uint16_t trap)
|
||||
{
|
||||
// UnloadSeg (routineAddr: Ptr);
|
||||
|
||||
/*
|
||||
* ------------
|
||||
* +0 routineAddr
|
||||
* ------------
|
||||
*
|
||||
*/
|
||||
|
||||
uint32_t sp;
|
||||
uint32_t routineAddr;
|
||||
|
||||
sp = StackFrame<4>(routineAddr);
|
||||
|
||||
Log("%04x UnloadSeg(%08x)\n", trap, routineAddr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
25
toolbox/loader.h
Normal file
25
toolbox/loader.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef __mpw_loader_h__
|
||||
#define __mpw_loader_h__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@@ -158,12 +158,13 @@ namespace MM
|
||||
if (iter != HandleMap.end())
|
||||
{
|
||||
const HandleInfo &info = iter->second;
|
||||
printf("Handle $%08x Pointer: $%08x Size: $%08x Flags: %c %c\n",
|
||||
printf("Handle $%08x Pointer: $%08x Size: $%08x Flags: %c %c %c\n",
|
||||
iter->first,
|
||||
info.address,
|
||||
info.size,
|
||||
info.locked ? 'L' : ' ',
|
||||
info.purgeable ? 'P' : ' '
|
||||
info.purgeable ? 'P' : ' ',
|
||||
info.resource ? 'R' : ' '
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -182,12 +183,13 @@ namespace MM
|
||||
if (!info.size) end++;
|
||||
if (address >= begin && address < end)
|
||||
{
|
||||
printf("Handle $%08x Pointer: $%08x Size: $%08x Flags: %c %c\n",
|
||||
printf("Handle $%08x Pointer: $%08x Size: $%08x Flags: %c %c %c\n",
|
||||
kv.first,
|
||||
info.address,
|
||||
info.size,
|
||||
info.locked ? 'L' : ' ',
|
||||
info.purgeable ? 'P' : ' '
|
||||
info.purgeable ? 'P' : ' ',
|
||||
info.resource ? 'R' : ' '
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -206,9 +208,14 @@ namespace MM
|
||||
{
|
||||
const auto h = kv.first;
|
||||
const auto & info = kv.second;
|
||||
fprintf(stdout, "%08x %08x %08x %c %c\n",
|
||||
h, info.address, info.size,
|
||||
info.locked? 'L' : ' ', info.purgeable? 'P' : ' ');
|
||||
fprintf(stdout, "%08x %08x %08x %c %c %c\n",
|
||||
h,
|
||||
info.address,
|
||||
info.size,
|
||||
info.locked? 'L' : ' ',
|
||||
info.purgeable? 'P' : ' ',
|
||||
info.resource ? 'R' : ' '
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -488,6 +495,19 @@ namespace MM
|
||||
|
||||
}
|
||||
|
||||
// template class to validate handle and work on it.
|
||||
template<class FX>
|
||||
uint16_t HandleIt(uint32_t handle, FX fx)
|
||||
{
|
||||
const auto iter = HandleMap.find(handle);
|
||||
|
||||
if (iter == HandleMap.end()) return SetMemError(MacOS::memWZErr);
|
||||
|
||||
auto &info = iter->second;
|
||||
fx(info);
|
||||
return SetMemError(0);
|
||||
}
|
||||
|
||||
uint16_t HSetRBit(uint32_t handle)
|
||||
{
|
||||
const auto iter = HandleMap.find(handle);
|
||||
@@ -510,6 +530,29 @@ namespace MM
|
||||
return SetMemError(0);
|
||||
}
|
||||
|
||||
uint16_t HLock(uint32_t handle)
|
||||
{
|
||||
const auto iter = HandleMap.find(handle);
|
||||
|
||||
if (iter == HandleMap.end()) return SetMemError(MacOS::memWZErr);
|
||||
|
||||
auto &info = iter->second;
|
||||
info.locked = true;
|
||||
return SetMemError(0);
|
||||
}
|
||||
|
||||
uint16_t HUnlock(uint32_t handle)
|
||||
{
|
||||
const auto iter = HandleMap.find(handle);
|
||||
|
||||
if (iter == HandleMap.end()) return SetMemError(MacOS::memWZErr);
|
||||
|
||||
auto &info = iter->second;
|
||||
info.locked = false;
|
||||
return SetMemError(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@@ -28,6 +28,8 @@ namespace MM
|
||||
uint16_t HSetRBit(uint32_t handle);
|
||||
uint16_t HClrRBit(uint32_t handle);
|
||||
|
||||
uint16_t HLock(uint32_t handle);
|
||||
uint16_t HUnlock(uint32_t handle);
|
||||
}
|
||||
|
||||
bool Init(uint8_t *memory, uint32_t memorySize, uint32_t reserved);
|
||||
|
@@ -149,6 +149,8 @@ namespace OS
|
||||
case 'c':
|
||||
if (ext == "c")
|
||||
return true;
|
||||
if (ext == "cpp")
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
@@ -1109,6 +1111,32 @@ namespace OS
|
||||
return MacOS::dsCoreErr;
|
||||
}
|
||||
|
||||
uint16_t SetToolTrapAddress(uint16_t trap)
|
||||
{
|
||||
//pascal void SetToolTrapAddress(long trapAddr, short trapNum);
|
||||
|
||||
/*
|
||||
* on entry:
|
||||
* A0 Address of patch
|
||||
* D0 trap number
|
||||
*
|
||||
* on exit:
|
||||
*
|
||||
*/
|
||||
|
||||
// this is used by the far model stub, presumably
|
||||
// to replace LoadSeg.
|
||||
|
||||
uint16_t trapNumber = cpuGetDReg(0);
|
||||
uint32_t trapAddress = cpuGetAReg(0);
|
||||
|
||||
Log("%04x SetToolTrapAddress($%08x, $%04x)\n",
|
||||
trap, trapAddress, trapNumber);
|
||||
|
||||
|
||||
return MacOS::dsCoreErr;
|
||||
}
|
||||
|
||||
uint16_t GetOSTrapAddress(uint16_t trap)
|
||||
{
|
||||
/*
|
||||
|
@@ -81,6 +81,8 @@ namespace OS
|
||||
#pragma mark - Trap Manager
|
||||
|
||||
uint16_t GetToolTrapAddress(uint16_t trap);
|
||||
uint16_t SetToolTrapAddress(uint16_t trap);
|
||||
|
||||
uint16_t GetOSTrapAddress(uint16_t trap);
|
||||
|
||||
#pragma mark - Alias Manager
|
||||
|
@@ -101,6 +101,10 @@ namespace
|
||||
|
||||
bool LoadResType(uint32_t type)
|
||||
{
|
||||
// this filtering was originally to
|
||||
// block cursors ('acur'). Can probably
|
||||
// change it to a blacklist rather than
|
||||
// a whitelist at some point.
|
||||
|
||||
switch (type)
|
||||
{
|
||||
@@ -113,6 +117,7 @@ namespace
|
||||
case 0x756e6974: // 'unit' (Pascal)
|
||||
case 0x434f4445: // 'CODE' (Link)
|
||||
case 0x5041434b: // 'PACK' (PascalIIgs)
|
||||
case 0x4b4f4445: // 'KODE' (Link 32-bit Startup)
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -156,6 +161,7 @@ namespace RM
|
||||
|
||||
size = ::GetHandleSize(nativeHandle);
|
||||
error = MM::Native::NewHandle(size, false, theHandle, ptr);
|
||||
// TODO -- need to lock if native handle locked.
|
||||
|
||||
if (!theHandle)
|
||||
{
|
||||
@@ -176,6 +182,7 @@ namespace RM
|
||||
|
||||
|
||||
// used by GetString (utility.h)
|
||||
// used by Loader.
|
||||
uint16_t GetResource(uint32_t type, uint16_t id, uint32_t &theHandle)
|
||||
{
|
||||
return LoadResource(type, theHandle,
|
||||
@@ -184,6 +191,17 @@ namespace RM
|
||||
});
|
||||
}
|
||||
|
||||
uint16_t SetResLoad(bool load)
|
||||
{
|
||||
|
||||
ResLoad = load;
|
||||
::SetResLoad(load);
|
||||
|
||||
memoryWriteByte(load ? 0xff : 0x00, MacOS::ResLoad); // word or byte?
|
||||
return SetResError(0);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
uint16_t CloseResFile(uint16_t trap)
|
||||
@@ -906,6 +924,8 @@ namespace RM
|
||||
err = MM::Native::ReallocHandle(theResource, size);
|
||||
if (err) return SetResError(err);
|
||||
|
||||
// todo -- need to lock if resource locked.
|
||||
|
||||
if (size)
|
||||
{
|
||||
uint32_t ptr = memoryReadLong(theResource);
|
||||
@@ -916,29 +936,4 @@ namespace RM
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// todo -- move since it's not RM related.
|
||||
uint16_t UnloadSeg(uint16_t trap)
|
||||
{
|
||||
// UnloadSeg (routineAddr: Ptr);
|
||||
|
||||
/*
|
||||
* ------------
|
||||
* +0 routineAddr
|
||||
* ------------
|
||||
*
|
||||
*/
|
||||
|
||||
uint32_t sp;
|
||||
uint32_t routineAddr;
|
||||
|
||||
sp = StackFrame<4>(routineAddr);
|
||||
|
||||
Log("%04x UnloadSeg(%08x)\n", trap, routineAddr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@ namespace RM
|
||||
|
||||
namespace Native
|
||||
{
|
||||
uint16_t SetResLoad(bool tf);
|
||||
uint16_t GetResource(uint32_t type, uint16_t id, uint32_t &theHandle);
|
||||
}
|
||||
|
||||
@@ -19,8 +20,6 @@ namespace RM
|
||||
uint16_t Get1Resource(uint16_t trap);
|
||||
uint16_t Get1IndResource(uint16_t trap);
|
||||
|
||||
uint16_t UnloadSeg(uint16_t trap);
|
||||
|
||||
uint16_t ReleaseResource(uint16_t trap);
|
||||
uint16_t ResError(uint16_t trap);
|
||||
|
||||
|
@@ -40,7 +40,7 @@
|
||||
#include "qd.h"
|
||||
#include "sane.h"
|
||||
#include "utility.h"
|
||||
|
||||
#include "loader.h"
|
||||
// yuck. TST.W d0
|
||||
extern "C" void cpuSetFlagsNZ00NewW(UWO res);
|
||||
|
||||
@@ -148,6 +148,10 @@ namespace ToolBox {
|
||||
d0 = OS::GetToolTrapAddress(trap);
|
||||
break;
|
||||
|
||||
case 0xa647:
|
||||
d0 = OS::SetToolTrapAddress(trap);
|
||||
break;
|
||||
|
||||
case 0xA346:
|
||||
d0 = OS::GetOSTrapAddress(trap);
|
||||
break;
|
||||
@@ -417,11 +421,6 @@ namespace ToolBox {
|
||||
d0 = RM::OpenRFPerm(trap);
|
||||
break;
|
||||
|
||||
// UnloadSeg (routineAddr: Ptr);
|
||||
case 0xa9f1:
|
||||
d0 = RM::UnloadSeg(trap);
|
||||
break;
|
||||
|
||||
case 0xa9f6:
|
||||
d0 = RM::GetResFileAttrs(trap);
|
||||
break;
|
||||
@@ -431,6 +430,12 @@ namespace ToolBox {
|
||||
break;
|
||||
|
||||
|
||||
// UnloadSeg (routineAddr: Ptr);
|
||||
case 0xa9f1:
|
||||
d0 = Loader::UnloadSeg(trap);
|
||||
break;
|
||||
|
||||
|
||||
// quickdraw (AsmIIgs ... )
|
||||
|
||||
// _ShowCursor();
|
||||
|
Reference in New Issue
Block a user