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:
1 parent
b4d0e571e7
commit
0349122bd7
7 files changed
+1140
-68
No files matched your search
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large.
Load diff
+85
-1
@@ -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
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "os2types.h"
|
||||
|
||||
+11
-1
@@ -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
|
||||
|
||||
Reference in new issue
Block a user