16-bit support!

This gets us everything we need (I hope!) to support 16-bit code in LX
binaries and call into 16-bit OS/2 APIs. This is just enough to call
into VioGetMode() (which isn't otherwise implemented yet) as an example.

If this is ever used Winelib-style to provide an OS/2 API to native Linux
binaries, the 16-bit system APIs are 32-bit clean and C callable, as one
might expect them to be. All the tapdancing is to support existing LX
binaries in the loader and bridge between the 32-bit clean APIs and
existing 16-bit code that expects to call 16-bit APIs.

This was a staggering amount of effort, but yay!

Other fixes and improvements probably leaked into this commit, as a
lot of code got touched and a lot of research and debugging took place.
This commit is contained in:
Ryan C. Gordon committed 2016-10-27 01:44:26 -04:00
1 parent 29696db8b3
commit 26a52988a6
10 files changed
+694 -57

No files matched your search

Executable
+25
View File
@@ -0,0 +1,25 @@
#!/usr/bin/perl -w
# run this on the output from ndisasm.
use warnings;
use strict;
while (<>) {
chomp;
my ($bytes, $asm) = /\A.*?\s+(.*?)\s+(.*)\Z/;
my $first = 1;
while ($bytes ne '') {
$bytes =~ s/\A(..)//;
my $hex = $1;
if ($first and ($bytes eq '')) {
print(" *(ptr++) = 0x$hex; /* $asm */\n");
} elsif ($first) {
print(" *(ptr++) = 0x$hex; /* $asm... */\n");
} else {
print(" *(ptr++) = 0x$hex; /* ...$asm */\n");
}
$first = 0;
}
}
+318 -39
View File
@@ -23,7 +23,6 @@
static LxLoaderState _GLoaderState;
static LxLoaderState *GLoaderState = &_GLoaderState;
static uint8 GMainTibSpace[LXTIBSIZE];
// !!! FIXME: move this into an lx_common.c file.
static int sanityCheckLxModule(uint8 **_exe, uint32 *_exelen)
@@ -410,6 +409,149 @@ static void *generateMissingTrampoline(const char *_module, const char *_entry)
} // generateMissingTrampoline
// !!! FIXME: mutex this
static int allocateSelector(const uint16 selector, const uint32 addr, const unsigned int contents, const int is32bit)
{
assert(selector < (sizeof (GLoaderState->ldt) / sizeof (GLoaderState->ldt[0])));
if (GLoaderState->ldt[selector])
return 0; // already in use.
//const int expand_down = (contents == MODIFY_LDT_CONTENTS_STACK);
struct user_desc entry;
entry.entry_number = (unsigned int) selector;
entry.base_addr = (unsigned int) addr; //(expand_down ? (addr + 0x10000) : addr);
entry.limit = 16; //expand_down ? 0 : 16;
entry.seg_32bit = is32bit;
entry.contents = contents;
entry.read_exec_only = 0;
entry.limit_in_pages = 1;
entry.seg_not_present = 0;
entry.useable = 1;
if (syscall(SYS_modify_ldt, 1, &entry, sizeof (entry)) != 0)
return 0;
GLoaderState->ldt[selector] = addr;
return 1;
} // allocateSelector
// !!! FIXME: mutex this
static int findSelector(const uint32 _addr, uint16 *outselector, uint16 *outoffset)
{
uint32 addr = _addr;
if (addr < 4096)
return 0; // we won't map the NULL page.
const uint32 *ldt = GLoaderState->ldt;
int available = -1;
int preferred = -1;
// optimize for the case where we need a selector that happenes to be in tiled memory,
// since it's fast to look up.
if (addr < (1024 * 1024 * 512)) {
const uint16 idx = (uint16) (addr >> 16);
const uint32 tile = ldt[idx];
if (tile == 0) {
preferred = available = idx; // we can use this piece.
} else if ((tile <= addr) && ((tile + 0x10000) > addr)) {
*outselector = idx;
*outoffset = (uint16) (addr - tile);
//printf("SELECTOR: found tiled selector 0x%X for address %p\n", (uint) idx, (void *) addr);
return 1; // already allocated to this address.
} // if
} // if
for (int i = 0; i < (sizeof (GLoaderState->ldt) / sizeof (GLoaderState->ldt[0])); i++) {
const uint32 tile = ldt[i];
if (tile == 0)
available = i;
else if ((tile <= addr) && ((tile + 0x10000) > addr)) {
*outselector = (uint16) i;
*outoffset = (uint16) (addr - tile);
//printf("SELECTOR: found existing selector 0x%X for address %p\n", (uint) i, (void *) addr);
return 1; // already allocated to this address.
} // else if
} // for
// nothing allocated to this address so far. Try to allocate something.
if (available == -1) {
fprintf(stderr, "Uhoh, we've run out of LDT selectors! Probably about to crash...\n"); fflush(stderr);
return 0; // uh oh, out of selectors!
} // if
const uint32 diff = addr % 0x10000;
addr -= diff; // make sure we start on a 64k border.
const uint16 selector = (uint16) (preferred != -1) ? preferred : available;
if (!allocateSelector(selector, addr, MODIFY_LDT_CONTENTS_CODE, 0)) {
fprintf(stderr, "Uhoh, we've failed to allocate LDT selector %u! Probably about to crash...\n", (uint) selector); fflush(stderr);
return 0;
} // if
//printf("SELECTOR: allocated selector 0x%X for address %p\n", (uint) selector, (void *) addr);
*outselector = selector;
*outoffset = (uint16) diff;
return 1;
} // findSelector
// !!! FIXME: mutex this
static void freeSelector(const uint16 selector)
{
assert(selector < (sizeof (GLoaderState->ldt) / sizeof (GLoaderState->ldt[0])));
if (!GLoaderState->ldt[selector])
return; // already free.
struct user_desc entry;
memset(&entry, '\0', sizeof (entry));
entry.entry_number = (unsigned int) selector;
entry.read_exec_only = 1;
entry.seg_not_present = 1;
if (syscall(SYS_modify_ldt, 1, &entry, sizeof (entry)) != 0)
return; // oh well.
GLoaderState->ldt[selector] = 0;
} // freeSelector
static void *convert1616to32(const uint32 addr1616)
{
const uint16 selector = (uint16) (addr1616 >> 19); // slide segment down, and shift out control bits.
const uint16 offset = (uint16) (addr1616 % 0x10000); // all our LDT segments start at 64k boundaries (at the moment!).
assert(GLoaderState->ldt[selector] != 0);
return (void *) (size_t) (GLoaderState->ldt[selector] + offset);
} // convert1616to32
// EMX (and probably many other things) occasionally has to call a 16-bit
// system API, and assumes its stack is tiled in the LDT; it'll just shift
// the stack pointer and use it as a stack segment for the 16-bit call
// without calling DosFlatToSeg(). So we tile the main thread's stack and
// pray that covers it. If we have to tile _every_ thread's stack, we can do
// that later.
// !!! FIXME: if we do this for secondary thread stacks, we'll need to mutex this.
static void initOs2StackSegments(uint32 addr, uint32 stacklen)
{
//printf("base == %p, stacklen == %u\n", (void*)addr, (uint) stacklen);
const uint32 diff = addr % 0x10000;
addr -= diff; // make sure we start on a 64k border.
stacklen += diff; // make sure we start on a 64k border.
// We fill in LDT tiles for the entire stack (EMX, etc, assume this will work).
if (stacklen % 0x10000) // pad this out to 64k
stacklen += 0x10000 - (stacklen % 0x10000);
// !!! FIXME: do we have to allocate these backwards? (stack grows down).
while (stacklen) {
//printf("Allocating selector 0x%X for stack %p ... \n", (uint) (addr >> 16), (void *) addr);
if (!allocateSelector((uint16) (addr >> 16), addr, MODIFY_LDT_CONTENTS_DATA/*STACK*/, 0)) {
FIXME("uhoh, couldn't set up an LDT entry for a stack segment! Might crash later!");
} // if
stacklen -= 0x10000;
addr += 0x10000;
} // while
} // initOs2StackSegments
// OS/2 threads keep their Thread Information Block at FS:0x0000, so we have
// to ask the Linux kernel to screw around with 16-bit selectors on our
// behalf so we don't crash out when apps try to access it directly.
@@ -474,7 +616,6 @@ static void deinitOs2Tib(const uint16 selector)
assert(rc == 0); FIXME("this can legit fail, though!");
} // deinitOs2Tib
static __attribute__((noreturn)) void runLxModule(LxModule *lxmod, const int argc, char **argv, char **envp)
{
uint8 *stack = (uint8 *) ((size_t) lxmod->esp);
@@ -503,7 +644,7 @@ static __attribute__((noreturn)) void runLxModule(LxModule *lxmod, const int arg
"ret \n\t" // go to OS/2 land!
"1: \n\t" // ...and return here.
"andl $-16, %%esp \n\t" // align the stack for macOS.
"subl $-4, %%esp \n\t" // align the stack for macOS.
"subl $-4, %%esp \n\t" // align the stack for macOS.
"pushl %%eax \n\t" // call _exit() with whatever is in %eax.
"call _exit \n\t"
: // no outputs
@@ -628,8 +769,10 @@ static void freeLxModule(LxModule *lxmod)
free(lxmod->dependencies);
for (uint32 i = 0; i < lxmod->lx.module_num_objects; i++) {
if (lxmod->mmaps[i].alias != 0xFFFF)
freeSelector(lxmod->mmaps[i].alias);
if (lxmod->mmaps[i].addr)
munmap(lxmod->mmaps[i].addr, lxmod->mmaps[i].size);
munmap(lxmod->mmaps[i].mapped, lxmod->mmaps[i].size);
} // for
free(lxmod->mmaps);
@@ -646,16 +789,25 @@ static void freeLxModule(LxModule *lxmod)
static LxModule *loadLxModuleByModuleNameInternal(const char *modname, const int dependency_tree_depth);
static void *getModuleProcAddrByOrdinal(const LxModule *module, const uint32 ordinal)
static void *getModuleProcAddrByOrdinal(const LxModule *module, const uint32 ordinal, const LxExport **_lxexp)
{
//printf("lookup module == '%s', ordinal == %u\n", module->name, (uint) ordinal);
const LxExport *lxexp = module->exports;
for (uint32 i = 0; i < module->num_exports; i++, lxexp++) {
if (lxexp->ordinal == ordinal)
return lxexp->addr;
if (lxexp->ordinal == ordinal) {
if (_lxexp)
*_lxexp = lxexp;
void *retval = lxexp->addr;
if (lxexp->object && lxexp->object->alias != 0xFFFF) // 16-bit bridge? this is actually a void**, due to some macro salsa. :/
retval = *((void**) retval);
return retval;
} // if
} // for
if (_lxexp)
*_lxexp = NULL;
#if 1
char entry[128];
snprintf(entry, sizeof (entry), "ordinal #%u", (uint) ordinal);
@@ -665,16 +817,25 @@ static void *getModuleProcAddrByOrdinal(const LxModule *module, const uint32 ord
#endif
} // getModuleProcAddrByOrdinal
static void *getModuleProcAddrByName(const LxModule *module, const char *name)
static void *getModuleProcAddrByName(const LxModule *module, const char *name, const LxExport **_lxexp)
{
//printf("lookup module == '%s', name == '%s'\n", module->name, name);
const LxExport *lxexp = module->exports;
for (uint32 i = 0; i < module->num_exports; i++, lxexp++) {
if (strcmp(lxexp->name, name) == 0)
return lxexp->addr;
if (strcmp(lxexp->name, name) == 0) {
if (_lxexp)
*_lxexp = lxexp;
void *retval = lxexp->addr;
if (lxexp->object && lxexp->object->alias != 0xFFFF) // 16-bit bridge? this is actually a void**, due to some macro salsa. :/
retval = *((void**) retval);
return retval;
} // if
} // for
if (_lxexp)
*_lxexp = NULL;
#if 1
return generateMissingTrampoline(module->name, name);
#else
@@ -698,10 +859,10 @@ static void doFixup(uint8 *page, const sint16 offset, const uint32 finalval, con
case 2: { uint16 *dst = (uint16 *) (page + offset); *dst = (uint16) finalval; } break;
case 4: { uint32 *dst = (uint32 *) (page + offset); *dst = (uint32) finalval; } break;
case 6: {
uint16 *dst1 = (uint16 *) (page + offset);
*dst1 = (uint16) finalval2;
uint32 *dst2 = (uint32 *) (page + offset + 2);
*dst2 = (uint32) finalval;
uint32 *dst1 = (uint32 *) (page + offset);
*dst1 = (uint32) finalval;
uint16 *dst2 = (uint16 *) (page + offset + 4);
*dst2 = (uint16) finalval2;
break;
} // case
default:
@@ -719,7 +880,7 @@ static void fixupPage(const uint8 *exe, LxModule *lxmod, const LxObjectTableEntr
const uint32 fixuplen = fixuppage[1] - fixuppage[0];
const uint8 *fixup = (exe + lx->fixup_record_table_offset) + fixupoffset;
const uint8 *fixupend = fixup + fixuplen;
// int record = 0;
//int record = 0;
while (fixup < fixupend) {
//record++; printf("FIXUP obj #%u page #%u record #: %d\n", (uint) (obj - origobj), (uint) pagenum, record);
const uint8 srctype = *(fixup++);
@@ -730,25 +891,40 @@ static void fixupPage(const uint8 *exe, LxModule *lxmod, const LxObjectTableEntr
uint32 finalval = 0;
uint16 finalval2 = 0;
uint32 finalsize = 0;
int allow_fixup_to_alias = 0;
switch (srctype & 0xF) {
case 0x0: // byte fixup
finalsize = 1;
break;
case 0x2: // 16-bit selector fixup
finalsize = 2;
allow_fixup_to_alias = 1;
break;
case 0x5: // 16-bit offset fixup
finalsize = 2;
break;
case 0x3: // 16:16 pointer fixup
finalsize = 4;
allow_fixup_to_alias = 1;
break;
case 0x7: // 32-bit offset fixup
case 0x8: // 32-bit self-relative offset fixup
finalsize = 4;
break;
case 0x6: // 16:32 pointer fixup
finalval2 = GLoaderState->original_cs;
finalsize = 6;
allow_fixup_to_alias = 1;
break;
} // switch
const int fixup_to_alias = ((srctype & 0x10) != 0);
if (fixup_to_alias) { // fixup to alias flag.
if (!allow_fixup_to_alias)
fprintf(stderr, "WARNING: Bogus fixup srctype (%u) with fixup-to-alias flag!\n", (uint) (srctype & 0xF));
} // if
if (srctype & 0x20) { // contains a source list
srclist_count = *(fixup++);
} else {
@@ -766,8 +942,8 @@ static void fixupPage(const uint8 *exe, LxModule *lxmod, const LxObjectTableEntr
} // else
uint32 targetoffset = 0;
// !!! FIXME: where do we use 16-bit selectors? What does this mean in a 32-bit app?
if ((srctype & 0xF) != 0x2) { // not a 16-bit selector fixup?
if ((srctype & 0xF) != 2) { // not used for 16-bit selector fixups.
if (fixupflags & 0x10) { // 32-bit target offset
targetoffset = *((uint32 *) fixup); fixup += 4;
} else { // 16-bit target offset
@@ -775,8 +951,22 @@ static void fixupPage(const uint8 *exe, LxModule *lxmod, const LxObjectTableEntr
} // else
} // if
const uint32 base = (uint32) (size_t) lxmod->mmaps[objectid - 1].addr;
finalval = base + targetoffset;
if (!fixup_to_alias) {
const uint32 base = (uint32) (size_t) lxmod->mmaps[objectid - 1].addr;
finalval = base + targetoffset;
} else {
if (lxmod->mmaps[objectid - 1].alias == 0xFFFF) {
fprintf(stderr, "uhoh, need a 16-bit alias fixup, but object has no 16:16 alias!\n");
} else {
const uint16 selector = (lxmod->mmaps[objectid - 1].alias << 3) | 7;
switch (srctype & 0xF) {
case 0x2: finalval = selector; break; // 16-bit selector fixup?
case 0x3: finalval = (((uint32) selector) << 16) | targetoffset; break; // 16:16 pointer fixup
case 0x6: finalval = targetoffset; finalval2 = selector; break; // 16:32 pointer fixup
default: assert(!"shouldn't hit this code"); break;
} // switch
} // else
} // else
break;
} // case
@@ -797,12 +987,28 @@ static void fixupPage(const uint8 *exe, LxModule *lxmod, const LxObjectTableEntr
importid = (uint32) *((uint16 *) fixup); fixup += 2;
} // else
const LxExport *lxexp = NULL;
if (moduleid == 0) {
fprintf(stderr, "uhoh, looking for module ordinal 0, which is illegal.\n");
} else if (moduleid > lx->num_import_mod_entries) {
fprintf(stderr, "uhoh, looking for module ordinal %u, but only %u available.\n", (uint) moduleid, (uint) lx->num_import_mod_entries);
} else {
finalval = (uint32) (size_t) getModuleProcAddrByOrdinal(lxmod->dependencies[moduleid-1], importid);
//printf("import-by-ordinal fixup: module=%u import=%u\n", (uint) moduleid, (uint) importid);
finalval = (uint32) (size_t) getModuleProcAddrByOrdinal(lxmod->dependencies[moduleid-1], importid, &lxexp);
} // else
if (fixup_to_alias) {
if (!lxexp || !lxexp->object || (lxexp->object->alias == 0xFFFF)) {
fprintf(stderr, "uhoh, couldn't find a selector for a fixup-to-alias address!\n");
} else {
const uint16 selector = (lxexp->object->alias << 3) | 7;
switch (srctype & 0xF) {
case 0x2: finalval = selector; break; // 16-bit selector fixup? !!! FIXME:
case 0x3: finalval = (((uint32) selector) << 16) | (finalval - ((uint32)lxexp->object->addr)); break; // 16:16 pointer fixup
case 0x6: finalval -= ((uint32)lxexp->object->addr); finalval2 = selector; break; // 16:32 pointer fixup
default: assert(!"shouldn't hit this code"); break;
} // switch
} // else
} // else
break;
} // case
@@ -822,6 +1028,7 @@ static void fixupPage(const uint8 *exe, LxModule *lxmod, const LxObjectTableEntr
name_offset = *((uint16 *) fixup); fixup += 2;
} // else
const LxExport *lxexp = NULL;
if (moduleid == 0) {
fprintf(stderr, "uhoh, looking for module ordinal 0, which is illegal.\n");
} else if (moduleid > lx->num_import_mod_entries) {
@@ -832,14 +1039,30 @@ static void fixupPage(const uint8 *exe, LxModule *lxmod, const LxObjectTableEntr
const uint8 namelen = *(import_name++) & 0x7F; // the top bit is reserved.
memcpy(name, import_name, namelen);
name[namelen] = '\0';
finalval = (uint32) (size_t) getModuleProcAddrByName(lxmod->dependencies[moduleid-1], name);
//printf("import-by-name fixup: module=%u import='%s'\n", (uint) moduleid, name);
finalval = (uint32) (size_t) getModuleProcAddrByName(lxmod->dependencies[moduleid-1], name, &lxexp);
} // else
if (fixup_to_alias) {
if (!lxexp || !lxexp->object || (lxexp->object->alias == 0xFFFF)) {
fprintf(stderr, "uhoh, couldn't find a selector for a fixup-to-alias address!\n");
} else {
const uint16 selector = (lxexp->object->alias << 3) | 7;
switch (srctype & 0xF) {
case 0x2: finalval = selector; break; // 16-bit selector fixup? !!! FIXME:
case 0x3: finalval = (((uint32) selector) << 16) | (finalval - ((uint32)lxexp->object->addr)); break; // 16:16 pointer fixup
case 0x6: finalval -= ((uint32)lxexp->object->addr); finalval2 = selector; break; // 16:32 pointer fixup
default: assert(!"shouldn't hit this code"); break;
} // switch
} // else
} // else
break;
} // case
case 0x3: { // Internal entry table fixup record
fprintf(stderr, "FIXUP 0x3 WRITE ME\n");
exit(1);
FIXME("FIXUP 0x3 WRITE ME");
assert(!"write me");
_exit(1);
break;
} // case
} // switch
@@ -863,7 +1086,7 @@ static void fixupPage(const uint8 *exe, LxModule *lxmod, const LxObjectTableEntr
doFixup(page, offset, finalval - (((uint32)page)+offset+4), 0, finalsize);
} else {
doFixup(page, offset, finalval, finalval2, finalsize);
}
} // else
} // for
} else {
if ((srctype & 0xF) == 0x08) { // self-relative fixup?
@@ -871,7 +1094,7 @@ static void fixupPage(const uint8 *exe, LxModule *lxmod, const LxObjectTableEntr
doFixup(page, srcoffset, finalval - (((uint32)page)+srcoffset+4), 0, finalsize);
} else {
doFixup(page, srcoffset, finalval, finalval2, finalsize);
}
} // else
} // else
} // while
} // fixupPage
@@ -950,6 +1173,9 @@ static LxModule *loadLxModule(const char *fname, uint8 *exe, uint32 exelen, int
} // if
memset(retval->dependencies, '\0', sizeof (LxModule *) * lx->num_import_mod_entries);
memset(retval->mmaps, '\0', sizeof (LxMmaps) * lx->module_num_objects);
for (int i = 0; i < lx->module_num_objects; i++)
retval->mmaps[i].alias = 0xFFFF;
memcpy(&retval->lx, lx, sizeof (*lx));
if (lx->resident_name_table_offset) {
@@ -980,6 +1206,7 @@ static LxModule *loadLxModule(const char *fname, uint8 *exe, uint32 exelen, int
goto loadlx_failed;
} // if
int uses_aliases = 0;
const LxObjectTableEntry *obj = ((const LxObjectTableEntry *) (exe + lx->object_table_offset));
for (uint32 i = 0; i < lx->module_num_objects; i++, obj++) {
if (obj->object_flags & 0x8) // !!! FIXME: resource object; ignore this until resource support is written, later.
@@ -989,12 +1216,24 @@ static LxModule *loadLxModule(const char *fname, uint8 *exe, uint32 exelen, int
if ((vsize % lx->page_size) != 0)
vsize += lx->page_size - (vsize % lx->page_size);
const int mmapflags = MAP_POPULATE | MAP_ANON | MAP_PRIVATE | (isDLL ? 0 : MAP_FIXED);
const int needs_1616_alias = ((obj->object_flags & 0x1000) != 0); // Object needs a 16:16 alias.
if (needs_1616_alias) {
if (vsize > 0x10000) {
fprintf(stderr, "Module '%s' object #%u needs a 16:16 alias, but is > 64k\n", modname, (uint) (i+1));
goto loadlx_failed; // I guess this is an error...?
} // if
uses_aliases = 1;
if (isDLL) // (specifically: if !MAP_FIXED)
vsize += 0x10000; // make sure we can align to a 64k boundary.
} // if
const int mmapflags = MAP_ANON | MAP_PRIVATE | (isDLL ? 0 : MAP_FIXED);
void *base = isDLL ? NULL : (void *) ((size_t) obj->reloc_base_addr);
void *mmapaddr = mmap(base, vsize, PROT_READ|PROT_WRITE, mmapflags, -1, 0);
// we'll mprotect() these pages to the proper permissions later.
//fprintf(stderr, "mmap(%p, %u, RW-, ANON|PRIVATE%s, -1, 0) == %p\n", base, (uint) vsize, isDLL ? "" : "|FIXED", mmapaddr);
//fprintf(stderr, "%s lxobj #%u mmap(%p, %u, %c%c%c, ANON|PRIVATE%s, -1, 0) == %p\n", retval->name, (uint) i, base, (uint) vsize, (obj->object_flags & 0x1) ? 'R' : '-', (obj->object_flags & 0x2) ? 'W' : '-', (obj->object_flags & 0x4) ? 'X' : '-', isDLL ? "" : "|FIXED", mmapaddr);
if (mmapaddr == ((void *) MAP_FAILED)) {
fprintf(stderr, "mmap(%p, %u, RW-, ANON|PRIVATE%s, -1, 0) failed (%d): %s\n",
@@ -1002,9 +1241,21 @@ static LxModule *loadLxModule(const char *fname, uint8 *exe, uint32 exelen, int
goto loadlx_failed;
} // if
retval->mmaps[i].addr = mmapaddr;
retval->mmaps[i].mapped = mmapaddr;
retval->mmaps[i].size = vsize;
// force objects with a 16:16 alias to a 64k boundary.
size_t adjust = (size_t) mmapaddr;
if (needs_1616_alias && ((adjust % 0x10000) != 0)) {
assert(isDLL); // this must be fixed to a specific address, hopefully handled this...?
const size_t diff = 0x10000 - (adjust % 0x10000);
vsize -= diff;
adjust += diff;
mmapaddr = (void *) adjust;
} // if
retval->mmaps[i].addr = mmapaddr;
const LxObjectPageTableEntry *objpage = ((const LxObjectPageTableEntry *) (exe + lx->object_page_table_offset));
objpage += obj->page_table_index - 1;
@@ -1055,9 +1306,8 @@ static LxModule *loadLxModule(const char *fname, uint8 *exe, uint32 exelen, int
// any bytes at the end of this object that we didn't initialize? Zero them out.
const uint32 remain = vsize - ((uint32) (dst - ((uint8 *) mmapaddr)));
if (remain) {
if (remain)
memset(dst, '\0', remain);
} // if
} // for
// All the pages we need from the EXE are loaded into the appropriate spots in memory.
@@ -1072,17 +1322,30 @@ static LxModule *loadLxModule(const char *fname, uint8 *exe, uint32 exelen, int
// !!! FIXME: esp==0 means something special for programs (and is ignored for library init).
// !!! FIXME: "A zero value in this field indicates that the stack pointer is to be initialized to the highest address/offset in the object"
if (!isDLL) {
retval->esp = lx->esp;
if (lx->esp_object != 0) {
const uint32 base = (uint32) ((size_t)retval->mmaps[lx->esp_object - 1].addr);
retval->esp += base;
} // if
} // if
assert(lx->esp_object != 0);
const uint32 stackbase = (uint32) ((size_t)retval->mmaps[lx->esp_object - 1].addr);
retval->esp = lx->esp + stackbase;
if (!isDLL) {
// This needs to be set up now, so it's available to any library
// init code that runs in LX land.
initOs2Tib(GMainTibSpace, (void *) ((size_t) retval->esp), retval->mmaps[retval->lx.esp_object - 1].size, 0);
initOs2Tib(GLoaderState->main_tibspace, (void *) ((size_t) retval->esp), retval->mmaps[retval->lx.esp_object - 1].size, 0);
initOs2StackSegments(stackbase, retval->mmaps[retval->lx.esp_object - 1].size);
} // if
// now we have the stack tiled--and it got the specific selectors it
// needed--let's start making 16:16 aliases for the appropriate objects.
if (uses_aliases) {
obj = ((const LxObjectTableEntry *) (exe + lx->object_table_offset));
for (uint32 i = 0; i < lx->module_num_objects; i++, obj++) {
if ((obj->object_flags & 0x1000) == 0)
continue; // Object doesn't need a 16:16 alias, skip it.
uint16 offset = 0;
if (!findSelector((uint32) (size_t) retval->mmaps[i].addr, &retval->mmaps[i].alias, &offset)) {
fprintf(stderr, "Ran out of LDT entries getting a 16:16 alias for '%s' object #%u!\n", modname, (uint) (i + 1));
goto loadlx_failed;
} // if
assert(offset == 0);
} // for
} // if
// Set up our exports...
@@ -1124,6 +1387,7 @@ static LxModule *loadLxModule(const char *fname, uint8 *exe, uint32 exelen, int
entryptr++;
lxexp->ordinal = ordinal++;
lxexp->addr = ((uint8 *) retval->mmaps[objidx].addr) + *((const uint16 *) entryptr);
lxexp->object = &retval->mmaps[objidx];
lxexp++;
entryptr += 2;
} // for
@@ -1136,6 +1400,7 @@ static LxModule *loadLxModule(const char *fname, uint8 *exe, uint32 exelen, int
entryptr++;
lxexp->ordinal = ordinal++;
lxexp->addr = ((uint8 *) retval->mmaps[objidx].addr) + *((const uint32 *) entryptr);
lxexp->object = &retval->mmaps[objidx];
lxexp++;
entryptr += 4;
}
@@ -1210,7 +1475,7 @@ static LxModule *loadLxModule(const char *fname, uint8 *exe, uint32 exelen, int
((obj->object_flags & 0x2) ? PROT_WRITE : 0) |
((obj->object_flags & 0x4) ? PROT_EXEC : 0);
if (mprotect(retval->mmaps[i].addr, retval->mmaps[i].size, prot) == -1) {
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",
retval->mmaps[i].addr, (uint) retval->mmaps[i].size,
(prot&PROT_READ) ? "R" : "-",
@@ -1607,10 +1872,24 @@ int main(int argc, char **argv, char **envp)
if (!installSignalHandlers())
return 1;
if (getenv("TRACE_NATIVE"))
GLoaderState->trace_native = 1;
unsigned int segment = 0;
__asm__ __volatile__ ( "movw %%cs, %%ax \n\t" : "=a" (segment) );
GLoaderState->original_cs = segment;
__asm__ __volatile__ ( "movw %%ss, %%ax \n\t" : "=a" (segment) );
GLoaderState->original_ss = segment;
__asm__ __volatile__ ( "movw %%ds, %%ax \n\t" : "=a" (segment) );
GLoaderState->original_ds = segment;
const char *envr = getenv("IS_2INE");
GLoaderState->subprocess = (envr != NULL);
GLoaderState->initOs2Tib = initOs2Tib;
GLoaderState->deinitOs2Tib = deinitOs2Tib;
GLoaderState->findSelector = findSelector;
GLoaderState->freeSelector = freeSelector;
GLoaderState->convert1616to32 = convert1616to32;
GLoaderState->loadModule = loadLxModuleByModuleName;
GLoaderState->locatePathCaseInsensitive = locatePathCaseInsensitive;
GLoaderState->makeUnixPath = makeUnixPath;
+13
View File
@@ -129,8 +129,10 @@ typedef struct LxResourceTableEntry
typedef struct LxMmaps
{
void *mapped;
void *addr;
size_t size;
uint16 alias; // 16:16 alias, if one.
} LxMmaps;
typedef struct LxExport
@@ -138,6 +140,7 @@ typedef struct LxExport
uint32 ordinal;
const char *name; // can be NULL
void *addr;
const LxMmaps *object;
} LxExport;
struct LxModule;
@@ -149,6 +152,7 @@ struct LxModule
char name[256]; // !!! FIXME: allocate this.
LxModule **dependencies;
LxMmaps *mmaps;
const LxExport *exports;
uint32 num_exports;
void *nativelib;
@@ -202,14 +206,23 @@ typedef struct LxLoaderState
{
LxModule *loaded_modules;
LxModule *main_module;
uint8 main_tibspace[LXTIBSIZE];
LxPIB pib;
int subprocess;
int running;
int trace_native;
uint16 original_cs;
uint16 original_ss;
uint16 original_ds;
uint32 ldt[8192];
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).
uint16 (*initOs2Tib)(uint8 *tibspace, void *_topOfStack, const size_t stacklen, const uint32 tid);
void (*deinitOs2Tib)(const uint16 selector);
int (*findSelector)(const uint32 addr, uint16 *outselector, uint16 *outoffset);
void (*freeSelector)(const uint16 selector);
void *(*convert1616to32)(const uint32 addr1616);
LxModule *(*loadModule)(const char *modname);
int (*locatePathCaseInsensitive)(char *buf);
char *(*makeUnixPath)(const char *os2path, uint32 *err);
+32 -11
View File
@@ -1,12 +1,11 @@
#define _POSIX_C_SOURCE 199309
#define _BSD_SOURCE
#define _GNU_SOURCE
#include "os2native.h"
#include "doscalls.h"
#include <unistd.h>
#include <limits.h>
#include <time.h>
#include <dirent.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
@@ -14,10 +13,6 @@
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include "os2native.h"
#include "doscalls.h"
static LxLoaderState *GLoaderState = NULL;
@@ -100,6 +95,11 @@ 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;
@@ -599,11 +599,32 @@ APIRET DosSetExceptionHandler(PEXCEPTIONREGISTRATIONRECORD rec)
return NO_ERROR;
} // DosSetExceptionHandler
ULONG DosFlatToSel(PVOID ptr)
ULONG _DosFlatToSel(PVOID ptr)
{
TRACE_NATIVE("DosFlatToSel(%p)", ptr);
return ((ULONG) ((size_t)ptr)) >> 16; // !!! FIXME
} // DosFlatToSel
uint16 selector = 0;
uint16 offset = 0;
if (!GLoaderState->findSelector((uint32) ptr, &selector, &offset)) {
fprintf(stderr, "Uhoh, ran out of LDT entries?!\n");
return 0; // oh well, crash.
} // if
selector = (selector << 3) | 7;
return (((uint32)selector) << 16) | ((uint32) offset);
} // _DosFlatToSel
// DosFlatToSel() passes its argument in %eax, so a little asm to bridge that...
__asm__ (
".globl DosFlatToSel \n\t"
".type DosFlatToSel, @function \n\t"
"DosFlatToSel: \n\t"
" pushl %eax \n\t"
" call _DosFlatToSel \n\t"
" addl $4, %esp \n\t"
" ret \n\t"
".size _DosFlatToSel, .-_DosFlatToSel \n\t"
);
APIRET DosSetSignalExceptionFocus(BOOL32 flag, PULONG pulTimes)
{
+1 -1
View File
@@ -386,7 +386,7 @@ APIRET OS2API DosExitList(ULONG ordercode, PFNEXITLIST pfn);
APIRET OS2API DosCreateEventSem(PSZ pszName, PHEV phev, ULONG flAttr, BOOL32 fState);
APIRET OS2API DosCreateMutexSem(PSZ pszName, PHMTX phmtx, ULONG flAttr, BOOL32 fState);
APIRET OS2API DosSetExceptionHandler(PEXCEPTIONREGISTRATIONRECORD pERegRec);
ULONG OS2API DosFlatToSel(PVOID ptr);
ULONG OS2API DosFlatToSel(VOID);
APIRET OS2API DosSetSignalExceptionFocus(BOOL32 flag, PULONG pulTimes);
APIRET OS2API DosSetRelMaxFH(PLONG pcbReqCount, PULONG pcbCurMaxFH);
APIRET OS2API DosAllocMem(PPVOID ppb, ULONG cb, ULONG flag);
+9 -4
View File
@@ -1,11 +1,16 @@
#ifndef _INCL_NATIVE_H_
#define _INCL_NATIVE_H_
#ifndef _INCL_OS2NATIVE_H_
#define _INCL_OS2NATIVE_H_
#define _POSIX_C_SOURCE 199309
#define _BSD_SOURCE
#define _GNU_SOURCE
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <pthread.h>
#include <errno.h>
#include <sys/mman.h>
#include "os2types.h"
#include "os2errors.h"
@@ -28,7 +33,7 @@ void OS2EXPORT lxNativeModuleDeinit(void);
initcode; \
static const LxExport lx_native_exports[] = {
#define LX_NATIVE_EXPORT(fn, ord) { ord, #fn, fn }
#define LX_NATIVE_EXPORT(fn, ord) { ord, #fn, fn, NULL }
#define LX_NATIVE_MODULE_INIT_END() \
}; \
@@ -38,5 +43,5 @@ void OS2EXPORT lxNativeModuleDeinit(void);
#endif
// end of native.h ...
// end of os2native.h ...
+215
View File
@@ -0,0 +1,215 @@
#ifndef _INCL_OS2NATIVE16_H_
#define _INCL_OS2NATIVE16_H_
#include "os2native.h"
// !!! 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
// (not when linking directly to this shared library).
#define LX_NATIVE_MODULE_16BIT_API(fn) \
static void *fn##16 = NULL;
#define LX_NATIVE_MODULE_16BIT_SUPPORT_END()
#define LX_NATIVE_MODULE_DEINIT_16BIT_SUPPORT() \
if ((obj16.alias != 0xFFFF) && (GLoaderState)) { \
GLoaderState->freeSelector(obj16.alias); \
} \
if (obj16.mapped != NULL) { \
munmap(obj16.mapped, obj16.size); \
} \
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; \
\
const size_t vsize = 0x10000 * 2; \
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; \
} \
\
obj16.mapped = mmapaddr; \
obj16.size = vsize; \
\
/* force objects with a 16:16 alias to a 64k boundary. */ \
size_t adjust = (size_t) mmapaddr; \
if ((adjust % 0x10000) != 0) { \
const size_t diff = 0x10000 - (adjust % 0x10000); \
adjust += diff; \
mmapaddr = (void *) adjust; \
} \
obj16.addr = mmapaddr; \
\
uint16 offset = 0; \
if (!GLoaderState->findSelector((uint32) obj16.addr, &obj16.alias, &offset)) { \
fprintf(stderr, "couldn't find a selector for 16-bit entry points!\n"); \
munmap(obj16.mapped, vsize); \
obj16.mapped = obj16.addr = NULL; \
obj16.size = 0; \
obj16.alias = 0xFFFF; \
GLoaderState = NULL; \
return 0; \
} \
assert(offset == 0); \
\
uint8 *ptr = (uint8 *) mmapaddr;
/* This is the original assembly code, for use with NASM.
USE16 ; start in 16-bit code where our 16-bit caller lands.
MOV BX, SS ; save off ss:sp
SHL EBX, 16 ; scootch over!
MOV BX, SP ; save off ss:sp
; our stack is tiled, so we can easily find the linear address of it.
MOV AX, SS ; move the stack segment into the low word.
SHR AX, 3 ; shift out the control bits from the segment.
SHL EAX, 16 ; move the remaining selector bits to the high word of %eax
MOV AX, SP ; move the stack offset into the low word. Now %eax has the linear stack pointer.
JMP DWORD 0x7788:0x33332222 ; jmp into the 32-bit code segment (the next instruction!).
USE32
MOV CX, 0xABCD ; original linear stack segment from lx_loader's main().
MOV SS, CX
MOV ESP, EAX ; and the same stack pointer, but linear.
ADD EAX, 4 ; %eax now points to original function arguments on the stack.
PUSH EBX ; save original ss:sp to stack.
PUSH DS ; save off the caller's data segment.
MOV CX, 0x8888 ; restore our linear data segment.
MOV DS, CX
PUSH EAX ; make this the sole argument to the bridge function.
MOV EAX, 0x55555555 ; absolute address of our 32-bit bridging function in C.
CALL [EAX] ; call our 32-bit bridging function in C.
; don't touch EAX anymore, it has the return value now!
ADD ESP, 4 ; dump our function argument.
POP DS ; get back our 16-bit data segment.
; Restore 16:16 stack. !!! FIXME: can use LSS if we figure out prefix and DS politics.
POP BX ; Get our original ss back.
POP CX ; Get our original sp back.
JMP WORD 0xAAAA:0xBBBB ; back into 16-bit land (the next instruction!).
USE16
MOV SS, CX
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) \
fn##16 = ptr; \
\
/* instructions are in Intel syntax here, not AT&T. */ \
/* USE16 */ \
*(ptr++) = 0x8C; /* mov bx,ss... */ \
*(ptr++) = 0xD3; /* ...mov bx,ss */ \
*(ptr++) = 0x66; /* shl ebx,byte 0x10... */ \
*(ptr++) = 0xC1; /* ...shl ebx,byte 0x10 */ \
*(ptr++) = 0xE3; /* ...shl ebx,byte 0x10 */ \
*(ptr++) = 0x10; /* ...shl ebx,byte 0x10 */ \
*(ptr++) = 0x89; /* mov bx,sp... */ \
*(ptr++) = 0xE3; /* ...mov bx,sp */ \
*(ptr++) = 0x8C; /* mov ax,ss... */ \
*(ptr++) = 0xD0; /* ...mov ax,ss */ \
*(ptr++) = 0xC1; /* shr ax,byte 0x3... */ \
*(ptr++) = 0xE8; /* ...shr ax,byte 0x3 */ \
*(ptr++) = 0x03; /* ...shr ax,byte 0x3 */ \
*(ptr++) = 0x66; /* shl eax,byte 0x10... */ \
*(ptr++) = 0xC1; /* ...shl eax,byte 0x10 */ \
*(ptr++) = 0xE0; /* ...shl eax,byte 0x10 */ \
*(ptr++) = 0x10; /* ...shl eax,byte 0x10 */ \
*(ptr++) = 0x89; /* mov ax,sp... */ \
*(ptr++) = 0xE0; /* ...mov ax,sp */ \
*(ptr++) = 0x66; /* jmp dword 0x7788:0x33332222... */ \
*(ptr++) = 0xEA; /* ...jmp dword 0x7788:0x33332222 */ \
const uint32 jmp32addr = (uint32) (ptr + 6); \
memcpy(ptr, &jmp32addr, 4); ptr += 4; \
memcpy(ptr, &GLoaderState->original_cs, 2); ptr += 2; \
\
/* USE32 */ \
*(ptr++) = 0x66; /* mov cx,0xabcd... */ \
*(ptr++) = 0xB9; /* ...mov cx,0xabcd */ \
memcpy(ptr, &GLoaderState->original_ss, 2); ptr += 2; \
*(ptr++) = 0x8E; /* mov ss,ecx... */ \
*(ptr++) = 0xD1; /* ...mov ss,ecx */ \
*(ptr++) = 0x89; /* mov esp,eax... */ \
*(ptr++) = 0xC4; /* ...mov esp,eax */ \
*(ptr++) = 0x83; /* add eax,byte +0x4... */ \
*(ptr++) = 0xC0; /* ...add eax,byte +0x4 */ \
*(ptr++) = 0x04; /* ...add eax,byte +0x4 */ \
*(ptr++) = 0x53; /* push ebx */ \
*(ptr++) = 0x1E; /* push ds */ \
*(ptr++) = 0x66; /* mov cx,0x8888... */ \
*(ptr++) = 0xB9; /* ...mov cx,0x8888 */ \
memcpy(ptr, &GLoaderState->original_ds, 2); ptr += 2; \
*(ptr++) = 0x8E; /* mov ds,ecx... */ \
*(ptr++) = 0xD9; /* ...mov ds,ecx */ \
*(ptr++) = 0x50; /* push eax */ \
*(ptr++) = 0xB8; /* mov eax,0x55555555... */ \
const uint32 callbridgeaddr = (uint32) bridge16to32_##fn; \
memcpy(ptr, &callbridgeaddr, 4); ptr += 4; \
*(ptr++) = 0xFF; /* call dword [eax]... */ \
*(ptr++) = 0xD0; /* ...call dword [eax] */ \
*(ptr++) = 0x83; /* add esp,byte +0x4... */ \
*(ptr++) = 0xC4; /* ...add esp,byte +0x4 */ \
*(ptr++) = 0x04; /* ...add esp,byte +0x4 */ \
*(ptr++) = 0x1F; /* pop ds */ \
*(ptr++) = 0x66; /* pop bx... */ \
*(ptr++) = 0x5B; /* ...pop bx */ \
*(ptr++) = 0x66; /* pop cx... */ \
*(ptr++) = 0x59; /* ...pop cx */ \
*(ptr++) = 0x66; /* jmp word 0xaaaa:0xbbbb... */ \
*(ptr++) = 0xEA; /* ...jmp word 0xaaaa:0xbbbb */ \
const uint16 jmp16offset = (uint16) ((((uint32)ptr) - ((uint32)mmapaddr))+4); \
memcpy(ptr, &jmp16offset, 2); ptr += 2; \
const uint16 jmp16segment = (obj16.alias << 3) | 7; \
memcpy(ptr, &jmp16segment, 2); ptr += 2; \
\
/* USE16 */ \
*(ptr++) = 0x8E; /* mov ss,cx... */ \
*(ptr++) = 0xD1; /* ...mov ss,cx */ \
*(ptr++) = 0x89; /* mov sp,bx... */ \
*(ptr++) = 0xDC; /* ...mov sp,bx */ \
*(ptr++) = 0xCA; /* retf 0x22... */ \
const uint16 argbytecount = argbytes; \
memcpy(ptr, &argbytecount, 2); ptr += 2; \
#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"); \
munmap(obj16.mapped, vsize); \
GLoaderState->freeSelector(obj16.alias); \
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 }
#endif
// end of os2native16.h ...
+15
View File
@@ -19,6 +19,20 @@ extern "C" {
#define OS2API APIENTRY OS2EXPORT
#endif
// Note that we never export actual 16-bit APIs from these headers, even if
// we have them marked as OS2API16. This is just for documentation's sake at
// the moment. If you compile against these headers and link against an
// OS2API16 function, they will be exist and operate in a linear address
// space. If you call them from an LX executable, though, the system assumes
// you're calling in from 16-bit code and exports something that cleans up
// the details behind the scenes.
// For developing against this API directly on Linux, you should assume this
// works like OS/2's PowerPC port, and the same 16-bit APIs you used on x86
// were made 32-bit clean by default for the new platform.
#ifndef OS2API16
#define OS2API16 OS2API
#endif
typedef uint32_t APIRET;
typedef uint16_t APIRET16;
typedef uint32_t APIRET32;
@@ -51,6 +65,7 @@ typedef HANDLE HEV, *PHEV;
typedef HANDLE HMTX, *PHMTX;
typedef HANDLE PID, *PPID;
typedef HANDLE TID, *PTID;
typedef SHANDLE HVIO, *PHVIO;
typedef PCHAR PSZ;
typedef int (APIENTRY *PFN)(void);
+37 -2
View File
@@ -1,7 +1,42 @@
#include "os2native.h"
#include "os2native16.h"
#include "viocalls.h"
LX_NATIVE_MODULE_INIT()
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;
} // VioGetMode
static APIRET16 bridge16to32_VioGetMode(uint8 *args)
{
const HVIO hvio = *((HVIO *) args); args += 2;
PVIOMODEINFO pvmi = (PVIOMODEINFO) GLoaderState->convert1616to32(*((uint32*) args)); //args += 4;
return VioGetMode(pvmi, hvio);
} // bridge16to32_VioGetMode
static int initViocalls(LxLoaderState *lx_state)
{
LX_NATIVE_MODULE_INIT_16BIT_SUPPORT()
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_EXPORT16(VioGetMode, 21)
LX_NATIVE_MODULE_INIT_END()
// end of viocalls.c ...
+29
View File
@@ -7,6 +7,35 @@
extern "C" {
#endif
#pragma pack(push, 1)
typedef struct
{
USHORT cb;
UCHAR fbType;
UCHAR color;
USHORT col;
USHORT row;
USHORT hres;
USHORT vres;
UCHAR fmt_ID;
UCHAR attrib;
ULONG buf_addr;
ULONG buf_length;
ULONG full_length;
ULONG partial_length;
PCHAR ext_data_addr;
} VIOMODEINFO, *PVIOMODEINFO;
#pragma pack(pop)
enum
{
VGMT_OTHER = 0x1,
VGMT_GRAPHICS = 0x02,
VGMT_DISABLEBURST = 0x04
};
APIRET16 OS2API16 VioGetMode(PVIOMODEINFO pvioModeInfo, HVIO hvio);
#ifdef __cplusplus
}
#endif