Bunch More Work: more APIs, subprocesses, multithreading.

EMX's GCC compiler can now build hello.c when run from lx_loader!
This commit is contained in:
Ryan C. Gordon committed 2016-10-14 02:39:17 -04:00
1 parent b4d0e571e7
commit 0349122bd7
7 files changed
+1140 -68

No files matched your search

+2
View File
@@ -52,6 +52,8 @@ foreach(_I doscalls;msg;nls;quecalls;viocalls;kbdcalls;sesmgr)
set_target_properties(${_I} PROPERTIES LINK_FLAGS "-m32 -ggdb3")
endforeach()
target_link_libraries(doscalls "pthread")
add_executable(lx_dump lx_dump.c)
add_executable(lx_loader lx_loader.c)
+65 -23
View File
@@ -9,6 +9,7 @@
#include <sys/mman.h>
#include <assert.h>
#include <dlfcn.h>
#include <pthread.h>
// 16-bit selector kernel nonsense...
#include <sys/syscall.h>
@@ -279,8 +280,7 @@ static void *generateMissingTrampoline(const char *_module, const char *_entry)
// the EMX runtime) touch the register directly, so we have to deal with it.
// You must call this once for each thread that will go into LX land, from
// that thread, as soon as possible after starting.
// !!! FIXME: eventually, we'll have a deinit equivalent for the end of threads, too.
static void initOs2Tib(void *_topOfStack, const size_t stacklen)
static uint16 initOs2Tib(void *_topOfStack, const size_t stacklen, const uint32 tid)
{
uint8 *topOfStack = (uint8 *) _topOfStack;
const size_t tiblen = (sizeof (LxTIB) + sizeof (LxTIB2));
@@ -300,7 +300,7 @@ static void initOs2Tib(void *_topOfStack, const size_t stacklen)
tib->tib_version = 20; // !!! FIXME
tib->tib_ordinal = 79; // !!! FIXME
tib2->tib2_ultid = 1;
tib2->tib2_ultid = tid;
tib2->tib2_ulpri = 512;
tib2->tib2_version = 20;
tib2->tib2_usMCCount = 0;
@@ -325,15 +325,27 @@ static void initOs2Tib(void *_topOfStack, const size_t stacklen)
// Wine does it. I still don't know why.
const unsigned int segment = (entry.entry_number << 3) | 3;
__asm__ __volatile__ ( "movw %%ax, %%fs \n\t" : : "a" (segment) );
return (uint16) segment;
} // initOs2Tib
static __attribute__((noreturn)) void runLxModule(LxModule *lxmod, const int argc, char **argv)
static void deinitOs2Tib(const uint16 selector)
{
// !!! FIXME: right now, we don't list any environment variables, because they probably don't make sense to drop in (even PATH uses a different separator on Unix).
// !!! FIXME: eventually, the environment table looks like this (double-null to terminate list): var1=a\0var2=b\0var3=c\0\0
// The command line looks like this...
// \0argv0\0argv1 argv2 argvN\0\0
// !!! FIXME: I barely know what I'm doing here, this could all be wrong.
struct user_desc entry;
memset(&entry, '\0', sizeof (entry));
entry.entry_number = selector;
entry.read_exec_only = 1;
entry.seg_not_present = 1;
const long rc = syscall(SYS_set_thread_area, &entry);
assert(rc == 0); FIXME("this can legit fail, though!");
} // deinitOs2Tib
static __attribute__((noreturn)) void runLxModule(LxModule *lxmod, const int argc, char **argv, char **envp)
{
// Eventually, the environment table looks like this (double-null to terminate list): var1=a\0var2=b\0var3=c\0\0
// The command line looks like this: \0argv0\0argv1 argv2 argvN\0\0
size_t len = 1;
for (int i = 0; i < argc; i++) {
@@ -353,11 +365,20 @@ static __attribute__((noreturn)) void runLxModule(LxModule *lxmod, const int arg
} // if
len++; // terminator
}
} // for
const char *default_os2path = "PATH=C:\\home\\icculus\\Dropbox\\emx\\bin;C:\\home\\icculus"; // !!! FIXME: noooooope.
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, "IS_2INE=", 8) == 0) {
continue;
} // if
len += strlen(str) + 1;
} // for
const char *tmpenv = "IS_2INE=1";
const size_t envlen = strlen(tmpenv);
len += envlen;
len += 4; // null terminators.
char *env = (char *) malloc(len);
@@ -366,10 +387,21 @@ static __attribute__((noreturn)) void runLxModule(LxModule *lxmod, const int arg
exit(1);
} // if
strcpy(env, tmpenv);
char *ptr = env + envlen;
*(ptr++) = '\0';
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, "IS_2INE=", 8) == 0) {
continue;
} // if
strcpy(ptr, str);
ptr += strlen(str) + 1;
}
*(ptr++) = '\0';
char *cmd = ptr;
strcpy(ptr, argv[0]);
ptr += strlen(argv[0]);
@@ -920,7 +952,7 @@ static LxModule *loadLxModule(const char *fname, uint8 *exe, uint32 exelen, int
if (!isDLL) {
// This needs to be set up now, so it's available to any library
// init code that runs in LX land.
initOs2Tib((void *) ((size_t) retval->esp), retval->mmaps[retval->lx.esp_object - 1].size);
initOs2Tib((void *) ((size_t) retval->esp), retval->mmaps[retval->lx.esp_object - 1].size, 0);
} // if
// Set up our exports...
@@ -1137,8 +1169,10 @@ static LxModule *loadNativeModule(const char *fname, const char *modname)
// !!! FIXME: mutex this.
lib = dlopen(fname, RTLD_LOCAL | RTLD_NOW);
if (lib == NULL)
if (lib == NULL) {
fprintf(stderr, "dlopen('%s') failed: %s\n", fname, dlerror());
goto loadnative_failed;
} // if
fn = (LxNativeModuleInitEntryPoint) dlsym(lib, "lxNativeModuleInit");
if (!fn)
@@ -1206,23 +1240,31 @@ static inline LxModule *loadLxModuleByModuleName(const char *modname)
return loadLxModuleByModuleNameInternal(modname, 0);
} // loadLxModuleByModuleName
int main(int argc, char **argv)
int main(int argc, char **argv, char **envp)
{
if (argc < 2) {
fprintf(stderr, "USAGE: %s <program.exe> [...programargs...]\n", argv[0]);
return 1;
}
const char *envr = getenv("IS_2INE");
GLoaderState->subprocess = (envr != NULL);
GLoaderState->initOs2Tib = initOs2Tib;
GLoaderState->deinitOs2Tib = deinitOs2Tib;
LxModule *lxmod = loadLxModuleByPath(argv[1]);
if (lxmod) {
LxModule *lxmod = loadLxModuleByPath(envr ? envr : argv[1]);
if (!lxmod) {
return 1;
}
// standalone, drop argv[0]. As a subprocess, keep it.
if (!GLoaderState->subprocess) {
argc--;
argv++;
runLxModule(lxmod, argc, argv);
} // if
runLxModule(lxmod, argc, argv, envp);
return 0;
return 1; // you shouldn't hit this, but if you do, report failure.
} // main
// end of lx_loader.c ...
+4 -2
View File
@@ -173,7 +173,6 @@ typedef struct LxTIB2
uint16 tib2_usMCCount;
uint16 tib2_fMCForceFlag;
} LxTIB2;
#pragma pack(pop)
typedef struct LxTIB
{
@@ -184,12 +183,15 @@ typedef struct LxTIB
uint32 tib_version;
uint32 tib_ordinal;
} LxTIB;
#pragma pack(pop)
typedef struct LxLoaderState
{
LxModule *loaded_modules;
LxModule *main_module;
void (*initOs2Tib)(void *_topOfStack, const size_t stacklen);
int subprocess;
uint16 (*initOs2Tib)(void *_topOfStack, const size_t stacklen, const uint32 tid);
void (*deinitOs2Tib)(const uint16 selector);
} LxLoaderState;
typedef const LxExport *(*LxNativeModuleInitEntryPoint)(LxLoaderState *lx_state, uint32 *lx_num_exports);
+972 -41
View File
File diff suppressed because it is too large. Load diff
+85 -1
View File
@@ -51,7 +51,6 @@ typedef struct TIB2
USHORT tib2_usMCCount;
USHORT tib2_fMCForceFlag;
} TIB2, *PTIB2;
#pragma pack(pop)
typedef struct TIB
{
@@ -62,6 +61,7 @@ typedef struct TIB
ULONG tib_version;
ULONG tib_ordinal;
} TIB, *PTIB;
#pragma pack(pop)
typedef struct PIB
{
@@ -222,6 +222,74 @@ typedef struct
ULONG cbList;
} FILESTATUS4, *PFILESTATUS4;
enum
{
CREATE_READY,
CREATE_SUSPENDED
};
enum
{
STACK_SPARSE = 0,
STACK_COMMITTED = 2
};
typedef VOID APIENTRY FNTHREAD(ULONG);
typedef FNTHREAD *PFNTHREAD;
typedef struct
{
ULONG codeTerminate;
ULONG codeResult;
} RESULTCODES, *PRESULTCODES;
enum
{
EXEC_SYNC,
EXEC_ASYNC,
EXEC_ASYNCRESULT,
EXEC_TRACE,
EXEC_BACKGROUND,
EXEC_LOAD,
EXEC_ASYNCRESULTDB
};
enum
{
DC_SEM_SHARED = 1
};
enum
{
DCMW_WAIT_ANY = (1<<1),
DCMW_WAIT_ALL = (1<<2)
};
enum
{
SEM_INDEFINITE_WAIT = -1,
SEM_IMMEDIATE_RETURN = 0
};
enum
{
DCWW_WAIT,
DCWW_NOWAIT
};
enum
{
DCWA_PROCESS,
DCWA_PROCESSTREE
};
enum
{
DSPI_WRTTHRU = 0x10,
};
// !!! FIXME: these should probably get sorted alphabetically and/or grouped
// !!! FIXME: into areas of functionality, but for now, I'm just listing them
// !!! FIXME: in the order I implemented them to get things running.
@@ -255,6 +323,22 @@ APIRET OS2API DosEnterMustComplete(PULONG pulNesting);
APIRET OS2API DosExitMustComplete(PULONG pulNesting);
APIRET OS2API DosQueryPathInfo(PSZ pszPathName, ULONG ulInfoLevel, PVOID pInfoBuf, ULONG cbInfoBuf);
APIRET OS2API DosQueryFileInfo(HFILE hf, ULONG ulInfoLevel, PVOID pInfo, ULONG cbInfoBuf);
APIRET OS2API DosQueryFileInfo(HFILE hf, ULONG ulInfoLevel, PVOID pInfo, ULONG cbInfoBuf);
APIRET OS2API DosCreateThread(PTID ptid, PFNTHREAD pfn, ULONG param, ULONG flag, ULONG cbStack);
APIRET OS2API DosExecPgm(PCHAR pObjname, LONG cbObjname, ULONG execFlag, PSZ pArg, PSZ pEnv, PRESULTCODES pRes, PSZ pName);
APIRET OS2API DosResetEventSem(HEV hev, PULONG pulPostCt);
APIRET OS2API DosPostEventSem(HEV hev);
APIRET OS2API DosCloseEventSem(HEV hev);
APIRET OS2API DosWaitEventSem(HEV hev, ULONG ulTimeout);
APIRET OS2API DosQueryEventSem(HEV hev, PULONG pulPostCt);
APIRET OS2API DosFreeMem(PVOID pb);
APIRET OS2API DosWaitChild(ULONG action, ULONG option, PRESULTCODES pres, PPID ppid, PID pid);
APIRET OS2API DosWaitThread(PTID ptid, ULONG option);
APIRET OS2API DosSleep(ULONG msec);
APIRET OS2API DosSubFreeMem(PVOID pbBase, PVOID pb, ULONG cb);
APIRET OS2API DosDelete(PSZ pszFile);
APIRET OS2API DosQueryCurrentDir(ULONG disknum, PBYTE pBuf, PULONG pcbBuf);
APIRET OS2API DosSetPathInfo(PSZ pszPathName, ULONG ulInfoLevel, PVOID pInfoBuf, ULONG cbInfoBuf, ULONG flOptions);
#ifdef __cplusplus
}
+1
View File
@@ -4,6 +4,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
#include <pthread.h>
#include <errno.h>
#include "os2types.h"
+11 -1
View File
@@ -33,11 +33,21 @@ typedef uint16_t USHORT, *PUSHORT;
typedef int32_t LONG, *PLONG;
typedef uint32_t ULONG, *PULONG;
typedef uint32_t BOOL32, *PBOOL32;
typedef uint32_t HANDLE, *PHANDLE;
typedef uint8_t BYTE, *PBYTE;
// !!! FIXME: HANDLE should either be 64-bits on x86_64, or we need to
// !!! FIXME: refactor and mutex a bunch of stuff...if it has to be a 32-bit
// !!! FIXME: int, it needs to be an index into a resizable array, but at the
// !!! FIXME: native word size, these handles can just be pointers cast to ints.
typedef uint16_t SHANDLE, *PSHANDLE;
typedef uint32_t LHANDLE, *PLHANDLE;
typedef LHANDLE HANDLE, *PHANDLE;
typedef HANDLE HMODULE, *PHMODULE;
typedef HANDLE HFILE, *PHFILE;
typedef HANDLE HEV, *PHEV;
typedef HANDLE HMTX, *PHMTX;
typedef HANDLE PID, *PPID;
typedef HANDLE TID, *PTID;
typedef PCHAR PSZ;
#ifdef __cplusplus