From 2481f59a28cd10afb2f22630e1538b53a75f1954 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Thu, 27 Oct 2016 03:20:02 -0400 Subject: [PATCH] Bunch of work on getting java.exe to start up. Not there yet. Lots of fixes, improvements, and a few more APIs implemented. --- lx_loader.c | 58 +++++++++++--- lx_loader.h | 2 + native/doscalls.c | 180 +++++++++++++++++++++++++++++++++++++++---- native/doscalls.h | 11 +++ native/os2native.h | 13 +++- native/os2native16.h | 14 +--- native/viocalls.c | 82 ++++++++++++++++---- native/viocalls.h | 1 + 8 files changed, 306 insertions(+), 55 deletions(-) diff --git a/lx_loader.c b/lx_loader.c index 07975d1..fa667b5 100644 --- a/lx_loader.c +++ b/lx_loader.c @@ -1470,10 +1470,18 @@ static LxModule *loadLxModule(const char *fname, uint8 *exe, uint32 exelen, int *(ptr++) = 0x90; // nop } // if + // !!! FIXME: hack for Java that fails to mark a code page as executable + // !!! FIXME: (on 386 machines, read implies execute, so this error could go unnoticed). + uint32 object_flags = obj->object_flags; + if ((i == 4) && (strcasecmp(modname, "HPI") == 0)) { + fprintf(stderr, "fixed page permissions to workaround bug in Java DLL\n"); + object_flags |= 0x4; + } // if + // Now set all the pages of this object to the proper final permissions... - const int prot = ((obj->object_flags & 0x1) ? PROT_READ : 0) | - ((obj->object_flags & 0x2) ? PROT_WRITE : 0) | - ((obj->object_flags & 0x4) ? PROT_EXEC : 0); + const int prot = ((object_flags & 0x1) ? PROT_READ : 0) | + ((object_flags & 0x2) ? PROT_WRITE : 0) | + ((object_flags & 0x4) ? PROT_EXEC : 0); if (mprotect(retval->mmaps[i].mapped, retval->mmaps[i].size, prot) == -1) { fprintf(stderr, "mprotect(%p, %u, %s%s%s, ANON|PRIVATE|FIXED, -1, 0) failed (%d): %s\n", @@ -1692,12 +1700,15 @@ static void initPib(LxPIB *pib, const int argc, char **argv, char **envp) exit(1); } // if + const char *libpath = NULL; char *ptr = env; for (int i = 0; envp[i]; i++) { const char *str = envp[i]; if (strncmp(str, "PATH=", 5) == 0) { if (!GLoaderState->subprocess) str = default_os2path; + } else if (strncmp(str, "LIBPATH=", 8) == 0) { + libpath = str + 8; } else if (strncmp(str, "IS_2INE=", 8) == 0) { continue; } // if @@ -1707,6 +1718,15 @@ static void initPib(LxPIB *pib, const int argc, char **argv, char **envp) } *(ptr++) = '\0'; + // we keep a copy of LIBPATH for undocumented API + // DosQueryHandleInfo(..., QHINF_LIBPATH, ...). I guess in case the app + // has changed the environment var after start? Java uses this. + if (libpath == NULL) + libpath = ""; + + GLoaderState->libpath = strdup(libpath); + GLoaderState->libpathlen = strlen(libpath) + 1; + // put the exe name between the environment and the command line. strcpy(ptr, argv[0]); ptr += strlen(argv[0]) + 1; @@ -1758,6 +1778,23 @@ static LxModule *loadLxModuleByModuleName(const char *modname) return loadLxModuleByModuleNameInternal(modname, 0); } // loadLxModuleByModuleName +static LxModule *loadLxModuleByPathOrModuleName(const char *modname) +{ + LxModule *retval = NULL; + // !!! FIXME: can a module name be specified as "NAME.DLL" and not be considered a filename? + if (strrchr(modname, '.') == NULL) { + retval = loadLxModuleByModuleName(modname); + } else { + uint32 err = 0; + char *path = makeUnixPath(modname, &err); + if (!path) + return NULL; + retval = loadLxModuleByPath(path); + free(path); + } // else + return retval; +} // loadLxModuleByPathOrModuleName + static __attribute__((noreturn)) void handleThreadLocalStorageAccess(const int slot, ucontext_t *uctx) { greg_t *gregs = uctx->uc_mcontext.gregs; @@ -1775,7 +1812,7 @@ static __attribute__((noreturn)) void handleThreadLocalStorageAccess(const int s uint32 *tls = (uint32 *) (ptib2 + 1); // The thread's TLS data is stored right after its TIB2 struct. tls += slot; - printf("We wanted to access thread %p TLS slot %d (currently holds %u)\n", tls - slot, slot, (uint) *tls); + //printf("We wanted to access thread %p TLS slot %d (currently holds %u)\n", tls - slot, slot, (uint) *tls); static const int x86RegisterToUContextEnum[] = { REG_EAX, REG_ECX, REG_EDX, REG_EBX, REG_ESP, REG_EBP, REG_ESI, REG_EDI @@ -1786,19 +1823,19 @@ static __attribute__((noreturn)) void handleThreadLocalStorageAccess(const int s uint8 *eip = (void *) (size_t) gregs[REG_EIP]; // program counter at point of segfault. switch (eip[0]) { case 0xC7: // mov imm16/32 -> r/m - printf("setting TLS slot %d to imm %u.\n", slot, (uint) *((uint32 *) (eip + 2))); + //printf("setting TLS slot %d to imm %u.\n", slot, (uint) *((uint32 *) (eip + 2))); *tls = *((uint32 *) (eip + 2)); // !!! FIXME: verify it's a imm32, not 16 gregs[REG_EIP] += 6; break; case 0x89: // mov r -> r/m - printf("setting TLS slot %d to reg %d (%u).\n", slot, x86RegisterToUContextEnum[eip[1] >> 3], (uint) gregs[x86RegisterToUContextEnum[eip[1] >> 3]]); + //printf("setting TLS slot %d to reg %d (%u).\n", slot, x86RegisterToUContextEnum[eip[1] >> 3], (uint) gregs[x86RegisterToUContextEnum[eip[1] >> 3]]); *tls = (uint32) gregs[x86RegisterToUContextEnum[eip[1] >> 3]]; gregs[REG_EIP] += 2; break; case 0x8B: // mov r/m -> r - printf("setting to reg %d to TLS slot %d (%u).\n", (uint) x86RegisterToUContextEnum[eip[1] >> 3], slot, *tls); + //printf("setting reg %d to TLS slot %d (%u).\n", (uint) x86RegisterToUContextEnum[eip[1] >> 3], slot, *tls); gregs[x86RegisterToUContextEnum[eip[1] >> 3]] = (greg_t) *tls; gregs[REG_EIP] += 2; break; @@ -1813,7 +1850,7 @@ static __attribute__((noreturn)) void handleThreadLocalStorageAccess(const int s } else { // drop out of signal handler to (hopefully) next instruction in the app, // as if it accessed the TLS slot normally and none of this ever happened. - printf("TLS access handler jumping back into app at %p...\n", (void *) gregs[REG_EIP]); fflush(stdout); + //printf("TLS access handler jumping back into app at %p...\n", (void *) gregs[REG_EIP]); fflush(stdout); setcontext(uctx); fprintf(stderr, "panic: setcontext() failed in the TLS access handler! Aborting! (%s)\n", strerror(errno)); } // else @@ -1841,6 +1878,7 @@ static void segfault_catcher(int sig, siginfo_t *info, void *ctx) // !!! FIXME: case #1 should be a much more detailed crash dump. case 1: fprintf(stderr, "SIGSEGV at addr=%p (eip=%p)\n", addr, (void *) ((ucontext_t *) ctx)->uc_mcontext.gregs[REG_EIP]); break; case 2: write(2, "SIGSEGV, aborting.\n", 19); break; + default: break; } // switch abort(); // cash out. @@ -1855,7 +1893,7 @@ static int installSignalHandlers(void) action.sa_flags = SA_NODEFER | SA_SIGINFO; if (sigaction(SIGSEGV, &action, NULL) == -1) { - fprintf(stderr, "Couldn't install signal handler! (%s)\n", strerror(errno)); + fprintf(stderr, "Couldn't install SIGSEGV handler! (%s)\n", strerror(errno)); return 0; } // if @@ -1890,7 +1928,7 @@ int main(int argc, char **argv, char **envp) GLoaderState->findSelector = findSelector; GLoaderState->freeSelector = freeSelector; GLoaderState->convert1616to32 = convert1616to32; - GLoaderState->loadModule = loadLxModuleByModuleName; + GLoaderState->loadModule = loadLxModuleByPathOrModuleName; GLoaderState->locatePathCaseInsensitive = locatePathCaseInsensitive; GLoaderState->makeUnixPath = makeUnixPath; GLoaderState->makeOS2Path = makeOS2Path; diff --git a/lx_loader.h b/lx_loader.h index d6b3026..7459a6d 100644 --- a/lx_loader.h +++ b/lx_loader.h @@ -215,6 +215,8 @@ typedef struct LxLoaderState uint16 original_ss; uint16 original_ds; uint32 ldt[8192]; + char *libpath; + uint32 libpathlen; uint32 *tlspage; uint32 tlsmask; // one bit for each TLS slot in use. uint8 tlsallocs[32]; // number of TLS slots allocated in one block, indexed by starting block (zero if not the starting block). diff --git a/native/doscalls.c b/native/doscalls.c index 7ca85eb..1119517 100644 --- a/native/doscalls.c +++ b/native/doscalls.c @@ -14,7 +14,28 @@ #include #include -static LxLoaderState *GLoaderState = NULL; +// DosQueryHeaderInfo() is an undocumented OS/2 API that is exported from DOSCALLS. Java uses it. +// This isn't mentioned in the docs or the SDK (beyond the ordinal being listed). I got the basic details +// from Odin32, which lists it in their os2newapi.h header. +enum +{ + QHINF_EXEINFO = 1, + QHINF_READRSRCTBL, + QHINF_READFILE, + QHINF_LIBPATHLENGTH, + QHINF_LIBPATH, + QHINF_FIXENTRY, + QHINF_STE, + QHINF_MAPSEL +}; +APIRET OS2API DosQueryHeaderInfo(HMODULE hmod, ULONG ulIndex, PVOID pvBuffer, ULONG cbBuffer, ULONG ulSubFunction); + +// This is also undocumented (thanks, EDM/2!). Of course, Java uses it. +APIRET OS2API DosQuerySysState(ULONG func, ULONG arg1, ULONG pid, ULONG _res_, PVOID buf, ULONG bufsz); + +// This is also undocumented (no idea about this at all, including function params). Of course, Java uses it. +APIRET DosR3ExitAddr(void); + static pthread_mutex_t GMutexDosCalls; @@ -54,9 +75,10 @@ enum { typedef struct HFileInfo { - int fd; - ULONG type; - ULONG attr; + int fd; // unix file descriptor. + ULONG type; // file, pipe, device, etc. + ULONG attr; // for character devices, DAW_* + ULONG flags; // OPEN_FLAGS_* } HFileInfo; static HFileInfo *HFiles = NULL; @@ -95,11 +117,6 @@ typedef struct static DirFinder GHDir1; -// !!! FIXME: -#undef TRACE_NATIVE -#define TRACE_NATIVE(...) do { if (GLoaderState->trace_native) { fprintf(stderr, "2INE TRACE [%lu]: ", (unsigned long) pthread_self()); fprintf(stderr, __VA_ARGS__); fprintf(stderr, ";\n"); } } while (0) - - LX_NATIVE_MODULE_DEINIT({ ExitListItem *next = GExitList; GExitList = NULL; @@ -118,14 +135,10 @@ LX_NATIVE_MODULE_DEINIT({ MaxHFiles = 0; pthread_mutex_destroy(&GMutexDosCalls); - - GLoaderState = NULL; }) -static int initDoscalls(LxLoaderState *lx_state) +static int initDoscalls(void) { - GLoaderState = lx_state; - if (pthread_mutex_init(&GMutexDosCalls, NULL) == -1) { fprintf(stderr, "pthread_mutex_init failed!\n"); return 0; @@ -143,6 +156,7 @@ static int initDoscalls(LxLoaderState *lx_state) info->fd = -1; info->type = 0; info->attr = 0; + info->flags = 0; } // for // launching a Hello World program from CMD.EXE seems to inherit several @@ -164,7 +178,8 @@ static int initDoscalls(LxLoaderState *lx_state) return 1; } // initDoscalls -LX_NATIVE_MODULE_INIT({ if (!initDoscalls(lx_state)) return NULL; }) +LX_NATIVE_MODULE_INIT({ if (!initDoscalls()) return NULL; }) + LX_NATIVE_EXPORT(DosSetMaxFH, 209), LX_NATIVE_EXPORT(DosSetPathInfo, 219), LX_NATIVE_EXPORT(DosQueryPathInfo, 223), LX_NATIVE_EXPORT(DosQueryHType, 224), @@ -183,6 +198,7 @@ LX_NATIVE_MODULE_INIT({ if (!initDoscalls(lx_state)) return NULL; }) LX_NATIVE_EXPORT(DosOpen, 273), LX_NATIVE_EXPORT(DosQueryCurrentDir, 274), LX_NATIVE_EXPORT(DosQueryCurrentDisk, 275), + LX_NATIVE_EXPORT(DosQueryFHState, 276), LX_NATIVE_EXPORT(DosQueryFileInfo, 279), LX_NATIVE_EXPORT(DosWaitChild, 280), LX_NATIVE_EXPORT(DosRead, 281), @@ -214,6 +230,7 @@ LX_NATIVE_MODULE_INIT({ if (!initDoscalls(lx_state)) return NULL; }) LX_NATIVE_EXPORT(DosSubFreeMem, 346), LX_NATIVE_EXPORT(DosQuerySysInfo, 348), LX_NATIVE_EXPORT(DosSetExceptionHandler, 354), + LX_NATIVE_EXPORT(DosQuerySysState, 368), LX_NATIVE_EXPORT(DosSetSignalExceptionFocus, 378), LX_NATIVE_EXPORT(DosEnterMustComplete, 380), LX_NATIVE_EXPORT(DosExitMustComplete, 381), @@ -221,6 +238,10 @@ LX_NATIVE_MODULE_INIT({ if (!initDoscalls(lx_state)) return NULL; }) LX_NATIVE_EXPORT(DosFlatToSel, 425), LX_NATIVE_EXPORT(DosAllocThreadLocalMemory, 454), LX_NATIVE_EXPORT(DosFreeThreadLocalMemory, 455), + LX_NATIVE_EXPORT(DosR3ExitAddr, 553), + LX_NATIVE_EXPORT(DosQueryHeaderInfo, 582), + LX_NATIVE_EXPORT(DosQueryExtLIBPATH, 874), + LX_NATIVE_EXPORT(DosQueryThreadContext, 877), LX_NATIVE_EXPORT(DosOpenL, 981) LX_NATIVE_MODULE_INIT_END() @@ -364,7 +385,7 @@ APIRET DosQueryModuleName(HMODULE hmod, ULONG buflen, PCHAR buf) const LxModule *lxmod = (LxModule *) hmod; // !!! FIXME: error 6 ERROR_INVALID_HANDLE - if (strlen(lxmod->os2path) <= buflen) + if (strlen(lxmod->os2path) >= buflen) return ERROR_BAD_LENGTH; strcpy(buf, lxmod->os2path); return NO_ERROR; @@ -683,6 +704,7 @@ APIRET DosSetRelMaxFH(PLONG pincr, PULONG pcurrent) info->fd = -1; info->type = 0; info->attr = 0; + info->flags = 0; } // for MaxHFiles += incr; } // if @@ -955,6 +977,8 @@ static APIRET doDosOpen(PSZ pszFileName, PHFILE pHf, PULONG pulAction, LONGLONG __builtin_unreachable(); } // if + info->flags = fsOpenFlags; + if (isReplacing) *pulAction = FILE_TRUNCATED; else if (existed) @@ -1244,6 +1268,12 @@ static APIRET queryPathInfo(PSZ unixPath, ULONG ulInfoLevel, PVOID pInfoBuf, ULO case FIL_STANDARD: return queryPathInfoStandard(unixPath, pInfoBuf, cbInfoBuf); case FIL_QUERYEASIZE: return queryPathInfoEaSize(unixPath, pInfoBuf, cbInfoBuf); case FIL_QUERYEASFROMLIST: return queryPathInfoEasFromList(unixPath, pInfoBuf, cbInfoBuf); + + // OS/2 has an undocumented info level, 7, that appears to return a case-corrected version + // of the path. (FIL_QUERYFULLNAME doesn't correct the case of what the app queries on + // OS/2). Since we have to case-correct for a Unix filesystem anyhow, we just use the + // usual FIL_QUERYFULLNAME to handle the undocumented level. Java uses this level. + case 7: case FIL_QUERYFULLNAME: return queryPathInfoFullName(unixPath, pInfoBuf, cbInfoBuf); default: break; } // switch @@ -2707,5 +2737,123 @@ APIRET DosFreeThreadLocalMemory(ULONG *p) return retval; } // DosFreeThreadLocalMemory +APIRET DosQueryFHState(HFILE hFile, PULONG pMode) +{ + TRACE_NATIVE("DosQueryFHState(%u, %p)", (uint) hFile, pMode); + + APIRET retval = NO_ERROR; + ULONG tmp = 0; + if (!pMode) + pMode = &tmp; + + grabLock(&GMutexDosCalls); + if ((hFile < MaxHFiles) && (HFiles[hFile].fd != -1)) + *pMode = HFiles[hFile].flags; + else + retval = ERROR_INVALID_HANDLE; + ungrabLock(&GMutexDosCalls); + + return retval; +} // DosQueryFHState + +APIRET DosQueryHeaderInfo(HMODULE hmod, ULONG ulIndex, PVOID pvBuffer, ULONG cbBuffer, ULONG ulSubFunction) +{ + TRACE_NATIVE("DosQueryHeaderInfo(%u, %u, %p, %u, %u)", (uint) hmod, (uint) ulIndex, pvBuffer, (uint) cbBuffer, (uint) ulSubFunction); + + switch (ulSubFunction) { + //case QHINF_EXEINFO: + //case QHINF_READRSRCTBL: + //case QHINF_READFILE: + + case QHINF_LIBPATHLENGTH: + if (cbBuffer < sizeof (ULONG)) + return ERROR_BUFFER_OVERFLOW; + *((ULONG *) pvBuffer) = GLoaderState->libpathlen; + return NO_ERROR; + + case QHINF_LIBPATH: + if (cbBuffer < GLoaderState->libpathlen) + return ERROR_BUFFER_OVERFLOW; + strcpy((char *) pvBuffer, GLoaderState->libpath); + return NO_ERROR; + + //case QHINF_FIXENTRY: + //case QHINF_STE: + //case QHINF_MAPSEL: + + default: FIXME("I don't know what this query wants"); break; + } // switch + + return ERROR_INVALID_PARAMETER; +} // DosQueryHeaderInfo + +APIRET OS2API DosQueryExtLIBPATH(PSZ pszExtLIBPATH, ULONG flags) +{ + TRACE_NATIVE("DosQueryExtLIBPATH('%s', %u)", pszExtLIBPATH, (uint) flags); + + // !!! FIXME: this is mostly a stub for now. + + if ((flags != BEGIN_LIBPATH) && (flags != END_LIBPATH)) + return ERROR_INVALID_PARAMETER; + + if (pszExtLIBPATH) + *pszExtLIBPATH = '\0'; + + return NO_ERROR; +} // DosQueryExtLIBPATH + +APIRET DosSetMaxFH(ULONG cFH) +{ + grabLock(&GMutexDosCalls); + + if (cFH < MaxHFiles) { + ungrabLock(&GMutexDosCalls); + return ERROR_INVALID_PARAMETER; // strictly speaking, we could shrink, but I'm not doing it. + } // if + + if (cFH == MaxHFiles) { + ungrabLock(&GMutexDosCalls); + return NO_ERROR; + } // if + + HFileInfo *info = (HFileInfo *) realloc(HFiles, sizeof (HFileInfo) * (cFH)); + if (info != NULL) { + HFiles = info; + info += MaxHFiles; + for (ULONG i = MaxHFiles; i < cFH; i++, info++) { + info->fd = -1; + info->type = 0; + info->attr = 0; + info->flags = 0; + } // for + MaxHFiles = cFH; + } // if + + ungrabLock(&GMutexDosCalls); + + return NO_ERROR; +} // DosSetMaxFH + +APIRET DosQuerySysState(ULONG func, ULONG arg1, ULONG pid, ULONG _res_, PVOID buf, ULONG bufsz) +{ + TRACE_NATIVE("DosQuerySysState(%u, %u, %u, %u, %p, %u)", (uint) func, (uint) arg1, (uint) pid, (uint) _res_, buf, (uint) bufsz); + FIXME("implement me"); + return ERROR_INVALID_PARAMETER; +} // DosQuerySysState + +APIRET DosR3ExitAddr(void) +{ + TRACE_NATIVE("DosR3ExitAddr()"); + FIXME("I have no idea what this is"); // but...JAVA USES IT. + return ERROR_INVALID_PARAMETER; +} // DosR3ExitAddr + +APIRET DosQueryThreadContext(TID tid, ULONG level, PCONTEXTRECORD pcxt) +{ + TRACE_NATIVE("DosQueryThreadContext(%u, %u, %p)", (uint) tid, (uint) level, pcxt); + FIXME("Need to be able to suspend threads first"); + return ERROR_INVALID_PARAMETER; +} // DosQueryThreadContext + // end of doscalls.c ... diff --git a/native/doscalls.h b/native/doscalls.h index ca6339e..c9df72a 100644 --- a/native/doscalls.h +++ b/native/doscalls.h @@ -371,6 +371,13 @@ enum FAPPTYP_32BIT = 0x4000 }; +enum +{ + BEGIN_LIBPATH = 1, + END_LIBPATH = 2 +}; + +typedef void *PCONTEXTRECORD; // !!! FIXME // !!! FIXME: these should probably get sorted alphabetically and/or grouped // !!! FIXME: into areas of functionality, but for now, I'm just listing them @@ -434,6 +441,10 @@ APIRET OS2API DosResetBuffer(HFILE hFile); APIRET OS2API DosQueryAppType(PSZ pszName, PULONG pFlags); APIRET OS2API DosAllocThreadLocalMemory(ULONG cb, PULONG *p); APIRET OS2API DosFreeThreadLocalMemory(ULONG *p); +APIRET OS2API DosQueryFHState(HFILE hFile, PULONG pMode); +APIRET OS2API DosQueryExtLIBPATH(PSZ pszExtLIBPATH, ULONG flags); +APIRET OS2API DosSetMaxFH(ULONG cFH); +APIRET OS2API DosQueryThreadContext(TID tid, ULONG level, PCONTEXTRECORD pcxt); #ifdef __cplusplus } diff --git a/native/os2native.h b/native/os2native.h index ff5591b..518ffdc 100644 --- a/native/os2native.h +++ b/native/os2native.h @@ -16,8 +16,11 @@ #include "os2errors.h" #include "../lx_loader.h" -#if 0 -#define TRACE_NATIVE(...) do { fprintf(stderr, "2INE TRACE [%lu]: ", (unsigned long) pthread_self()); fprintf(stderr, __VA_ARGS__); fprintf(stderr, ";\n"); } while (0) +// note that this is defined in _every_ module that includes this file! +static LxLoaderState *GLoaderState = NULL; + +#if 1 +#define TRACE_NATIVE(...) do { if (GLoaderState->trace_native) { fprintf(stderr, "2INE TRACE [%lu]: ", (unsigned long) pthread_self()); fprintf(stderr, __VA_ARGS__); fprintf(stderr, ";\n"); } } while (0) #else #define TRACE_NATIVE(...) do {} while (0) #endif @@ -26,10 +29,14 @@ OS2EXPORT const LxExport * lxNativeModuleInit(LxLoaderState *lx_state, uint32 *l void OS2EXPORT lxNativeModuleDeinit(void); #define LX_NATIVE_MODULE_DEINIT(deinitcode) \ - void lxNativeModuleDeinit(void) { deinitcode; } + void lxNativeModuleDeinit(void) { \ + deinitcode; \ + GLoaderState = NULL; \ + } #define LX_NATIVE_MODULE_INIT(initcode) \ const LxExport *lxNativeModuleInit(LxLoaderState *lx_state, uint32 *lx_num_exports) { \ + GLoaderState = lx_state; \ initcode; \ static const LxExport lx_native_exports[] = { diff --git a/native/os2native16.h b/native/os2native16.h index 3dfbe56..1dfed8e 100644 --- a/native/os2native16.h +++ b/native/os2native16.h @@ -6,7 +6,6 @@ // !!! FIXME: _lots_ of macro salsa in here. #define LX_NATIVE_MODULE_16BIT_SUPPORT() \ - static LxLoaderState *GLoaderState = NULL; \ static LxMmaps obj16; // These are the 16-bit entry points, which are exported to the LX loader @@ -26,11 +25,8 @@ obj16.mapped = obj16.addr = NULL; \ obj16.size = 0; \ obj16.alias = 0xFFFF; \ - GLoaderState = NULL; #define LX_NATIVE_MODULE_INIT_16BIT_SUPPORT() \ - GLoaderState = lx_state; \ - \ obj16.mapped = obj16.addr = NULL; \ obj16.size = 0; \ obj16.alias = 0xFFFF; \ @@ -39,7 +35,6 @@ void *mmapaddr = mmap(NULL, vsize, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); \ if (mmapaddr == ((void *) MAP_FAILED)) { \ fprintf(stderr, "mmap(NULL, 0x20000, RW-, ANON|PRIVATE, -1, 0) failed (%d): %s\n", errno, strerror(errno)); \ - GLoaderState = NULL; \ return 0; \ } \ \ @@ -62,7 +57,6 @@ obj16.mapped = obj16.addr = NULL; \ obj16.size = 0; \ obj16.alias = 0xFFFF; \ - GLoaderState = NULL; \ return 0; \ } \ assert(offset == 0); \ @@ -115,7 +109,7 @@ MOV SP, BX RETF 0x22 ; ...and back to the (far) caller, clearing the args (Pascal calling convention!) with retval in AX. */ -#define LX_NATIVE_INIT_16BIT_BRIDGE(fn, argbytes) \ +#define LX_NATIVE_INIT_16BIT_BRIDGE(fn, argbytes) { \ fn##16 = ptr; \ \ /* instructions are in Intel syntax here, not AT&T. */ \ @@ -192,9 +186,9 @@ RETF 0x22 ; ...and back to the (far) caller, clearing the args (Pascal calling *(ptr++) = 0xCA; /* retf 0x22... */ \ const uint16 argbytecount = argbytes; \ memcpy(ptr, &argbytecount, 2); ptr += 2; \ +} - -#define LX_NATIVE_MODULE_INIT_16BIT_SUPPORT_END() \ +#define LX_NATIVE_MODULE_INIT_16BIT_SUPPORT_END() { \ assert((((uint32)ptr) - ((uint32)mmapaddr)) < 0x10000); /* don't be more than 64k. */ \ if (mprotect(obj16.mapped, vsize, PROT_READ | PROT_EXEC) == -1) { \ fprintf(stderr, "mprotect() failed for 16-bit bridge code!\n"); \ @@ -203,9 +197,9 @@ RETF 0x22 ; ...and back to the (far) caller, clearing the args (Pascal calling obj16.mapped = obj16.addr = NULL; \ obj16.size = 0; \ obj16.alias = 0xFFFF; \ - GLoaderState = NULL; \ return 0; \ } \ +} #define LX_NATIVE_EXPORT16(fn, ord) { ord, #fn, &fn##16, &obj16 } diff --git a/native/viocalls.c b/native/viocalls.c index 8ab3012..1c8cc85 100644 --- a/native/viocalls.c +++ b/native/viocalls.c @@ -1,23 +1,35 @@ #include "os2native16.h" #include "viocalls.h" -LX_NATIVE_MODULE_16BIT_SUPPORT() - LX_NATIVE_MODULE_16BIT_API(VioGetMode) -LX_NATIVE_MODULE_16BIT_SUPPORT_END() - -// !!! FIXME: -#undef TRACE_NATIVE -#define TRACE_NATIVE(...) do { if (GLoaderState->trace_native) { fprintf(stderr, "2INE TRACE [%lu]: ", (unsigned long) pthread_self()); fprintf(stderr, __VA_ARGS__); fprintf(stderr, ";\n"); } } while (0) - -LX_NATIVE_MODULE_DEINIT({ - LX_NATIVE_MODULE_DEINIT_16BIT_SUPPORT(); -}) - APIRET16 VioGetMode(PVIOMODEINFO pvioModeInfo, HVIO hvio) { TRACE_NATIVE("VioGetMode(%p, %u)", pvioModeInfo, (uint) hvio); - FIXME("write me"); - return ERROR_INVALID_PARAMETER; + + if (hvio != 0) + return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented. + else if (pvioModeInfo == NULL) + return ERROR_VIO_INVALID_PARMS; + else if (pvioModeInfo->cb != sizeof (*pvioModeInfo)) + return ERROR_VIO_INVALID_LENGTH; + + memset(pvioModeInfo, '\0', sizeof (*pvioModeInfo)); + pvioModeInfo->cb = sizeof (*pvioModeInfo); + pvioModeInfo->fbType = VGMT_OTHER; + pvioModeInfo->color = 8; // bits? + pvioModeInfo->col = 80; + pvioModeInfo->row = 25; + FIXME("I don't know what most of these fields do"); + //pvioModeInfo->hres = 640; + //pvioModeInfo->vres = 480; + //UCHAR fmt_ID; + //UCHAR attrib; + //ULONG buf_addr; + //ULONG buf_length; + //ULONG full_length; + //ULONG partial_length; + //PCHAR ext_data_addr; + + return NO_ERROR; } // VioGetMode static APIRET16 bridge16to32_VioGetMode(uint8 *args) @@ -27,15 +39,53 @@ static APIRET16 bridge16to32_VioGetMode(uint8 *args) return VioGetMode(pvmi, hvio); } // bridge16to32_VioGetMode -static int initViocalls(LxLoaderState *lx_state) + +APIRET16 VioGetCurPos(PUSHORT pusRow, PUSHORT pusColumn, HVIO hvio) +{ + TRACE_NATIVE("VioGetCurPos(%p, %p, %u)", pusRow, pusColumn, (uint) hvio); + + if (hvio != 0) + return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented. + + FIXME("write me"); + if (pusRow) + *pusRow = 0; + if (pusColumn) + *pusColumn = 0; + + return NO_ERROR; +} // VioGetCurPos + +static APIRET16 bridge16to32_VioGetCurPos(uint8 *args) +{ + const HVIO hvio = *((HVIO *) args); args += 2; + PUSHORT pusRow = GLoaderState->convert1616to32(*((uint32*) args)); args += 4; + PUSHORT pusColumn = GLoaderState->convert1616to32(*((uint32*) args)); args += 4; + return VioGetCurPos(pusRow, pusColumn, hvio); +} // bridge16to32_VioGetCurPos + + + +LX_NATIVE_MODULE_16BIT_SUPPORT() + LX_NATIVE_MODULE_16BIT_API(VioGetCurPos) + LX_NATIVE_MODULE_16BIT_API(VioGetMode) +LX_NATIVE_MODULE_16BIT_SUPPORT_END() + +LX_NATIVE_MODULE_DEINIT({ + LX_NATIVE_MODULE_DEINIT_16BIT_SUPPORT(); +}) + +static int initViocalls(void) { LX_NATIVE_MODULE_INIT_16BIT_SUPPORT() + LX_NATIVE_INIT_16BIT_BRIDGE(VioGetCurPos, 6) LX_NATIVE_INIT_16BIT_BRIDGE(VioGetMode, 6) LX_NATIVE_MODULE_INIT_16BIT_SUPPORT_END() return 1; } // initViocalls -LX_NATIVE_MODULE_INIT({ if (!initViocalls(lx_state)) return NULL; }) +LX_NATIVE_MODULE_INIT({ if (!initViocalls()) return NULL; }) + LX_NATIVE_EXPORT16(VioGetCurPos, 9), LX_NATIVE_EXPORT16(VioGetMode, 21) LX_NATIVE_MODULE_INIT_END() diff --git a/native/viocalls.h b/native/viocalls.h index 9b72aaa..7749e05 100644 --- a/native/viocalls.h +++ b/native/viocalls.h @@ -35,6 +35,7 @@ enum }; APIRET16 OS2API16 VioGetMode(PVIOMODEINFO pvioModeInfo, HVIO hvio); +APIRET16 OS2API16 VioGetCurPos(PUSHORT pusRow, PUSHORT pusColumn, HVIO hvio); #ifdef __cplusplus }