/* * ReallocHandle (h: Handle; logicalSize: Size); * * ReallocHandle allocates a new relocatable block with a logical * size of logicalSize bytes. It then updates handle h by setting * its master pointer to point to the new block. The main use of * this procedure is to reallocate space for a block that has * been purged. Normally h is an empty handle, but it need not * be: If it points to an existing block, that block is released * before the new block is created. * * In case of an error, no new block is allocated and handle h is * left unchanged. */ uint16_t ReallocHandle(uint16_t trap) { /* * on entry: * A0 Handle to be disposed of * D0 Logical Size * * on exit: * D0 Result code * */ uint32_t hh = cpuGetAReg(0); uint32_t logicalSize = cpuGetDReg(0); Log("%04x ReallocHandle(%08x, %08x)\n", trap, hh, logicalSize); return Native::ReallocHandle(hh, logicalSize); #if 0 auto iter = HandleMap.find(hh); if (iter == HandleMap.end()) return SetMemError(MacOS::memWZErr); auto& info = iter->second; if (info.locked) return SetMemError(MacOS::memLockedErr); if (info.address) { void *address = Memory + info.address; mplite_free(&pool, address); info.address = 0; info.size = 0; memoryWriteLong(0, hh); } // allocate a new block... if (logicalSize == 0) return SetMemError(0); void *address = mplite_malloc(&pool, logicalSize); if (!address) return SetMemError(MacOS::memFullErr); uint32_t mcptr = (uint8_t *)address - Memory; info.size = logicalSize; info.address = mcptr; memoryWriteLong(mcptr, hh); // lock? clear purged flag? return 0; #endif }
static void fhfileOpen(void) { if (cpuGetDReg(0) < FHFILE_MAX_DEVICES) { memoryWriteByte(7, cpuGetAReg(1) + 8); /* ln_type (NT_REPLYMSG) */ memoryWriteByte(0, cpuGetAReg(1) + 31); /* io_error */ memoryWriteLong(cpuGetDReg(0), cpuGetAReg(1) + 24); /* io_unit */ memoryWriteLong(memoryReadLong(cpuGetAReg(6) + 32) + 1, cpuGetAReg(6) + 32); /* LIB_OPENCNT */ cpuSetDReg(0, 0); /* ? */ } else { memoryWriteLong(-1, cpuGetAReg(1) + 20); memoryWriteByte(-1, cpuGetAReg(1) + 31); /* io_error */ cpuSetDReg(0, -1); /* ? */ } }
static void cpuFrame2(UWO vector_offset, ULO pc) { // save inst address cpuSetAReg(7, cpuGetAReg(7) - 4); memoryWriteLong(cpuGetOriginalPC(), cpuGetAReg(7)); cpuFrame4Words(0x2000, vector_offset, pc); }
static BYT fhfileWrite(ULO index) { ULO dest = memoryReadLong(cpuGetAReg(1) + 40); ULO offset = memoryReadLong(cpuGetAReg(1) + 44); ULO length = memoryReadLong(cpuGetAReg(1) + 36); if (fhfile_devs[index].readonly || ((offset + length) > fhfile_devs[index].size)) { return -3; } fhfileSetLed(true); #ifdef RETRO_PLATFORM if(RP.GetHeadlessMode()) RP.PostHardDriveLED(index, true, true); #endif fseek(fhfile_devs[index].F, offset, SEEK_SET); fwrite(memoryAddressToPtr(dest),1, length, fhfile_devs[index].F); memoryWriteLong(length, cpuGetAReg(1) + 32); fhfileSetLed(false); #ifdef RETRO_PLATFORM if(RP.GetHeadlessMode()) RP.PostHardDriveLED(index, false, true); #endif return 0; }
uint16_t EmptyHandle(uint16_t trap) { /* * on entry: * A0 Handle to be disposed of * * on exit: * D0 Result code * */ uint32_t hh = cpuGetAReg(0); Log("%04x EmptyHandle(%08x)\n", trap, hh); auto iter = HandleMap.find(hh); if (iter == HandleMap.end()) return SetMemError(MacOS::memWZErr); auto &info = iter->second; if (info.address == 0) return SetMemError(0); if (info.locked) return SetMemError(MacOS::memLockedErr); // ? void *address = Memory + info.address; mplite_free(&pool, address); info.address = 0; info.size = 0; memoryWriteLong(0, hh); return 0; }
static void cpuFrameGroup2(UWO vector_offset, ULO pcPtr) { // save PC cpuSetAReg(7, cpuGetAReg(7) - 4); memoryWriteLong(pcPtr, cpuGetAReg(7)); // save SR cpuSetAReg(7, cpuGetAReg(7) - 2); memoryWriteWord((UWO)cpuGetSR(), cpuGetAReg(7)); // fault address, skip ireg cpuSetAReg(7, cpuGetAReg(7) - 6); memoryWriteLong(memory_fault_address, cpuGetAReg(7)); cpuSetAReg(7, cpuGetAReg(7) - 2); memoryWriteLong(memory_fault_read << 4, cpuGetAReg(7)); }
static void cpuFrameGroup1(UWO vector_offset, ULO pcPtr) { // save PC cpuSetAReg(7, cpuGetAReg(7) - 4); memoryWriteLong(pcPtr, cpuGetAReg(7)); // save SR cpuSetAReg(7, cpuGetAReg(7) - 2); memoryWriteWord((UWO)cpuGetSR(), cpuGetAReg(7)); }
uint32_t ftrap_get_font_info(uint32_t name, uint32_t parm) { // get_font_info(const char *name, uint32 *fontSize) std::string sname = ToolBox::ReadCString(name, true); Log(" get_font_info(%s, %04x)\n", sname.c_str(), parm); // default to 9pt if (parm) memoryWriteLong(9, parm); return 0; }
static void cpuFrame4Words(UWO frame_code, UWO vector_offset, ULO pc) { // save vector_offset word cpuSetAReg(7, cpuGetAReg(7) - 2); memoryWriteWord(frame_code | vector_offset, cpuGetAReg(7)); // save PC cpuSetAReg(7, cpuGetAReg(7) - 4); memoryWriteLong(pc, cpuGetAReg(7)); // save SR cpuSetAReg(7, cpuGetAReg(7) - 2); memoryWriteWord((UWO)cpuGetSR(), cpuGetAReg(7)); }
uint16_t TempMaxMem(void) { // FUNCTION TempMaxMem (VAR grow: Size): Size; uint32_t address; uint32_t sp = StackFrame<4>(address); Log(" TempMaxMem(%08x)\n", address); if (address) memoryWriteLong(0, address); ToolReturn<4>(sp, mplite_maxmem(&pool)); return SetMemError(0); }
uint16_t NewHandle(uint32_t size, bool clear, uint32_t &handle, uint32_t &mcptr) { uint8_t *ptr; uint32_t hh; handle = 0; mcptr = 0; if (!HandleQueue.size()) { if (!alloc_handle_block()) { return SetMemError(MacOS::memFullErr); } } hh = HandleQueue.front(); HandleQueue.pop_front(); ptr = nullptr; // todo -- size 0 should have a ptr to differentiate // from purged. // PPCLink calls NewHandle(0) but expects a valid pointer // Assertion failed: *fHandle != NULL //if (size) //{ ptr = (uint8_t *)mplite_malloc(&pool, size ? size : 1); if (!ptr) { HandleQueue.push_back(hh); return SetMemError(MacOS::memFullErr); } mcptr = ptr - Memory; if (clear) std::memset(ptr, 0, size); //} // need a handle -> ptr map? HandleMap.emplace(std::make_pair(hh, HandleInfo(mcptr, size))); memoryWriteLong(mcptr, hh); handle = hh; return SetMemError(0); }
uint32_t ftrap_get_tab_info(uint32_t name, uint32_t parm) { // get_tab_info(const char *name, uint32_t *tabSize) // hard code for now. // Could check xattr for actual value. // That would be rather pointless unless some editor respected // it. // Could check an environment variable. std::string sname = ToolBox::ReadCString(name, true); Log(" get_tab_info(%s)\n", sname.c_str()); if (parm) memoryWriteLong(8, parm); return 0; }
uint16_t ReallocHandle(uint32_t handle, uint32_t logicalSize) { auto iter = HandleMap.find(handle); if (iter == HandleMap.end()) return SetMemError(MacOS::memWZErr); auto& info = iter->second; if (info.locked) return SetMemError(MacOS::memLockedErr); uint32_t mcptr = 0; if (logicalSize) { // todo -- purge & retry on failure. void *address = mplite_malloc(&pool, logicalSize); if (!address) return SetMemError(MacOS::memFullErr); mcptr = (uint8_t *)address - Memory; } // the handle is not altered in the event of an error. if (info.address) { void *address = Memory + info.address; mplite_free(&pool, address); } info.address = mcptr; info.size = logicalSize; memoryWriteLong(mcptr, handle); // lock? clear purged flag? return 0; }
static void fhfileClose(void) { memoryWriteLong(memoryReadLong(cpuGetAReg(6) + 32) - 1, cpuGetAReg(6) + 32); /* LIB_OPENCNT */ cpuSetDReg(0, 0); /* ? */ }
uint16_t Init(int argc, char **argv) { /* FDTable.resize(16); FDTable[STDIN_FILENO] = 1; FDTable[STDOUT_FILENO] = 1; FDTable[STDERR_FILENO] = 1; */ /* OS::Internal::FDTable.resize(3); FDTable[STDIN_FILENO].refcount = 1; FDTable[STDIN_FILENO].text = true; FDTable[STDOUT_FILENO].refcount = 1; FDTable[STDOUT_FILENO].text = true; FDTable[STDERR_FILENO].refcount = 1; FDTable[STDERR_FILENO].text = true; */ OS::Internal::FDEntry::allocate(STDIN_FILENO).text = true; OS::Internal::FDEntry::allocate(STDOUT_FILENO).text = true; OS::Internal::FDEntry::allocate(STDERR_FILENO).text = true; std::string command = argv[0]; command = ToolBox::UnixToMac(command); //std::replace(command.begin(), command.end(), '/', ':'); argv[0] = basename(argv[0]); // 0x0910 CurApName { char str32[32]; char * name = argv[0]; int l = strlen(name); l = std::min(l, 32); str32[0] = l; std::memcpy(str32 + 1, name, l); while (l < 32) str32[l++] = 0; std::memcpy(memoryPointer(MacOS::CurApName), str32, 32); } uint32_t argvptr = 0; uint32_t envptr = 0; uint32_t ioptr = 0; uint32_t devptr = 0; uint32_t fptr = 0; uint16_t error; // create the argv-data. { uint32_t size = 0; size = 4 * (argc + 1); // argv data. for (int i = 0; i < argc; ++i) { int l = strlen(argv[i]) + 1; if (l & 0x01) l++; size += l; } error = MM::Native::NewPtr(size, true, argvptr); if (error) return error; uint8_t *xptr = memoryPointer(argvptr); uint32_t offset = 0; offset = 4 * (argc + 1); for (int i = 0; i < argc; ++i) { memoryWriteLong(argvptr + offset, argvptr + 4 * i); // just use strcat? int l = strlen(argv[i]) + 1; if (l & 0x01) l++; strcpy((char *)xptr + offset, argv[i]); offset += l; } // null-terminate it. memoryWriteLong(0, argvptr + 4 * argc); } // environment { Environment.emplace(std::string("Command"), command); std::deque<std::string> e; for (const auto &iter : Environment) { std::string tmp; tmp.append(iter.first); tmp.push_back(0); tmp.append(iter.second); e.emplace_back(std::move(tmp)); } uint32_t size = 0; for (const std::string &s : e) { int l = s.length() + 1; if (l & 0x01) l++; size = size + l + 4; } size += 4; // space for null terminator. error = MM::Native::NewPtr(size, true, envptr); if (error) return error; uint8_t *xptr = memoryPointer(envptr); uint32_t offset = 0; offset = 4 * (e.size() + 1); unsigned i = 0; for (const std::string &s : e) { // ptr memoryWriteLong(envptr + offset, envptr + i * 4); int l = s.length() + 1; std::memcpy(xptr + offset, s.c_str(), l); if (l & 0x01) l++; offset += l; ++i; } // null-terminate it. memoryWriteLong(0, envptr + 4 * e.size()); } // ftable { // these are ftraps for emulated/native function ptrs. uint32_t size = 6 * 4; error = MM::Native::NewPtr(size, true, fptr); if (error) return error; memoryWriteWord(fQuit, fptr + 0); memoryWriteWord(0x4E75, fptr + 2); // rts memoryWriteWord(fAccess, fptr + 4); memoryWriteWord(0x4E75, fptr + 6); // rts memoryWriteWord(fClose, fptr + 8); memoryWriteWord(0x4E75, fptr + 10); // rts memoryWriteWord(fRead, fptr + 12); memoryWriteWord(0x4E75, fptr + 14); // rts memoryWriteWord(fWrite, fptr + 16); memoryWriteWord(0x4E75, fptr + 18); // rts memoryWriteWord(fIOCtl, fptr + 20); memoryWriteWord(0x4E75, fptr + 22); // rts } // dev table { uint32_t size = 0x78; error = MM::Native::NewPtr(size, true, devptr); if (error) return error; memoryWriteLong(0x46535953, devptr + 0); // 'FSYS' memoryWriteLong(fptr + 4, devptr + 4); memoryWriteLong(fptr + 8, devptr + 8); memoryWriteLong(fptr + 12, devptr + 12); memoryWriteLong(fptr + 16, devptr + 16); memoryWriteLong(fptr + 20, devptr + 20); memoryWriteLong(0x45434f4e, devptr + 24); // 'ECON' -- not implemented. memoryWriteLong(0x53595354, devptr + 48); // 'SYST' -- not implemented. } // io table. { uint32_t size = 0x3c; uint32_t ptr; error = MM::Native::NewPtr(size, true, ioptr); if (error) return error; ptr = ioptr; // stdin memoryWriteWord(0x0001, ptr + 0); // open flags (read) memoryWriteWord(0x0000, ptr + 2); // os err memoryWriteLong(devptr, ptr + 4); // -> 'FSYS' memoryWriteLong(STDIN_FILENO, ptr + 8); // cookie memoryWriteLong(0, ptr + 12); // transfer count. memoryWriteLong(0, ptr + 16); // buffer ptr = ioptr + 20; // stdout memoryWriteWord(0x0002, ptr + 0); // open flags (write) memoryWriteWord(0x0000, ptr + 2); // os err memoryWriteLong(devptr, ptr + 4); // -> 'FSYS' memoryWriteLong(STDOUT_FILENO, ptr + 8); // cookie memoryWriteLong(0, ptr + 12); // transfer count. memoryWriteLong(0, ptr + 16); // buffer ptr = ioptr + 40; // stderr memoryWriteWord(0x0002, ptr + 0); // open flags (write) memoryWriteWord(0x0000, ptr + 2); // os err memoryWriteLong(devptr, ptr + 4); // -> 'FSYS' memoryWriteLong(STDERR_FILENO, ptr + 8); // cookie memoryWriteLong(0, ptr + 12); // transfer count. memoryWriteLong(0, ptr + 16); // buffer } uint32_t mpi = 0; error = MM::Native::NewPtr(8 + 0x30, true, mpi); if (error) return error; MacProgramInfo = mpi + 8; memoryWriteLong(0x4d50474d, mpi); // 'MPGM' - magic memoryWriteLong(mpi + 8, mpi + 4); memoryWriteLong(mpi, 0x0316); mpi += 8; memoryWriteWord(0x5348, mpi + 0x00); // 'SH' - more magic memoryWriteLong(argc, mpi + 0x02); memoryWriteLong(argvptr, mpi + 0x06); memoryWriteLong(envptr, mpi + 0x0a); // 0x0e = exit code // ??? default fd table size? memoryWriteWord(0x190, mpi + 0x1a); // io table - stdin/stdout/stderr memoryWriteLong(ioptr, mpi + 0x1c); // device table memoryWriteLong(devptr, mpi + 0x20); return 0; }
static void fhfileWriteProt(ULO index) { memoryWriteLong(fhfile_devs[index].readonly, cpuGetAReg(1) + 32); }
static void fhfileGetDriveType(ULO index) { memoryWriteLong(1, cpuGetAReg(1) + 32); }
uint16_t SetHandleSize(uint32_t handle, uint32_t newSize) { if (handle == 0) return SetMemError(MacOS::nilHandleErr); const auto iter = HandleMap.find(handle); if (iter == HandleMap.end()) return SetMemError(MacOS::memWZErr); auto &info = iter->second; // 0 - no change in size. if (info.size == newSize) return SetMemError(0); uint32_t mcptr = info.address; uint8_t *ptr = mcptr + Memory; // 1. - resizing to 0. if (!newSize) { if (info.locked) { //return SetMemError(MacOS::memLockedErr); // ppclink resizes locked handles. info.size = 0; return SetMemError(0); } // todo -- size 0 should have a ptr to differentiate // from purged. mplite_free(&pool, ptr); info.address = 0; info.size = 0; memoryWriteLong(info.address, handle); return SetMemError(0); } // 2. - resizing from 0. if (!mcptr) { if (info.locked) return SetMemError(MacOS::memLockedErr); ptr = (uint8_t *)mplite_malloc(&pool, newSize); if (!ptr) return SetMemError(MacOS::memFullErr); mcptr = ptr - Memory; info.address = mcptr; info.size = newSize; memoryWriteLong(info.address, handle); return SetMemError(0); } for (unsigned i = 0; i < 2; ++i) { // 3. - locked if (info.locked) { if (mplite_resize(&pool, ptr, mplite_roundup(&pool, newSize)) == MPLITE_OK) { info.size = newSize; return SetMemError(0); } } else { // 4. - resize. ptr = (uint8_t *)mplite_realloc(&pool, ptr, mplite_roundup(&pool, newSize)); if (ptr) { mcptr = ptr - Memory; info.address = mcptr; info.size = newSize; memoryWriteLong(info.address, handle); return SetMemError(0); } } fprintf(stderr, "mplite_realloc failed.\n"); Native::PrintMemoryStats(); if (i > 0) return SetMemError(MacOS::memFullErr); // purge... for (auto & kv : HandleMap) { uint32_t ph = kv.first; auto &info = kv.second; if (ph == handle) continue; if (info.size && info.purgeable && !info.locked) { mplite_free(&pool, Memory + info.address); info.size = 0; info.address = 0; // also need to update memory memoryWriteLong(0, ph); } } } return SetMemError(MacOS::memFullErr); }
static void fhfileIgnore(ULO index) { memoryWriteLong(0, cpuGetAReg(1) + 32); cpuSetDReg(0, 0); }
static void fhfileGetNumberOfTracks(ULO index) { memoryWriteLong(fhfile_devs[index].tracks, cpuGetAReg(1) + 32); }
/* MPW's open logic pseudo code: if (flags & 0x1000) { // undocumented - use old tool calls oserr = flags & O_RSRC ? PBOPENRF() : PBOPEN(); } else { oserr = flags & O_RSRC ? PBHOPENRF() : PBHOPEN(); } if (!oserr) { if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) { errno = EEXIST; return; } return; } if (oserr == file not found) { if (flags & O_CREAT) { oserr = PBCreate(); if (!oserr) { oserr = flag & O_RSRC ? PBOpenRF() : PBOpen(); } } PBGETFCBINFO(); if (file size) { if (flags & O_TRUNC) { oserr = PBSetEOF(); } if (!permission check) { errno = EPERM; PBClose(); } */ uint32_t ftrap_open(uint32_t name, uint32_t parm) { uint32_t d0; int fd; std::string sname; MPWFile f; int nativeFlags = 0; std::memset(&f, 0, sizeof(f)); f.flags = memoryReadWord(parm); nativeFlags = 0; switch (f.flags & 0x03) { case 0x01: nativeFlags = O_RDONLY; break; case 0x02: nativeFlags = O_WRONLY; break; case 0x00: // ???? case 0x03: nativeFlags = O_RDWR; break; } if (f.flags & kO_APPEND) nativeFlags |= O_APPEND; if (f.flags & kO_CREAT) nativeFlags |= O_CREAT; if (f.flags & kO_TRUNC) nativeFlags |= O_TRUNC; if (f.flags & kO_EXCL) nativeFlags |= O_EXCL; sname = ToolBox::ReadCString(name, true); std::string xname = sname; Log(" open(%s, %04x)\n", sname.c_str(), f.flags); if (f.flags & kO_RSRC) { // O_CREAT and O_EXCL apply to the file, not the fork. int flags = O_RDONLY | (nativeFlags & (O_CREAT | O_EXCL)); int parent = ::open(sname.c_str(), flags, 0666); fd = -1; if (parent >= 0) { sname.append(_PATH_RSRCFORKSPEC); nativeFlags &= ~O_EXCL; // APFS, etc - resource fork doesn't automatically exist so // need O_CREAT. if ((nativeFlags & O_ACCMODE) != O_RDONLY) nativeFlags |= O_CREAT; fd = ::open(sname.c_str(), nativeFlags, 0666); close(parent); } } else { fd = ::open(sname.c_str(), nativeFlags, 0666); } if (fd < 0) { // return an errno. d0 = 0x40000000 | mpw_errno_from_errno(); f.error = MacOS::ioErr; f.cookie = 0; } else { d0 = 0; f.error = 0; f.cookie = fd; // adjust the binary flags... // some apps are good about this but // dumpobj, makelib, linkiigs don't set O_BINARY (but should) // MPW Assembler sets O_BINARY (but shouldn't) if (OS::IsTextFile(sname)) f.flags &= ~kO_BINARY; if (OS::IsBinaryFile(sname)) f.flags |= kO_BINARY; if (f.flags & kO_RSRC) f.flags |= kO_BINARY; auto &e = OS::Internal::FDEntry::allocate(fd, std::move(xname)); e.text = !(f.flags & kO_BINARY); e.resource = f.flags & kO_RSRC; } memoryWriteWord(f.flags, parm + 0); memoryWriteWord(f.error, parm + 2); memoryWriteLong(f.cookie, parm + 8); return d0; }