Skip to content

Commit

Permalink
Fixes for LDT manipulation.
Browse files Browse the repository at this point in the history
- Let allocateSelector() specify number of pages to allocate.
- Let findSelector() specify if this is a code or data segment.
- Let findSelector() choose if this is a code or data segment
  if the caller doesn't know (DosFlatToSel(), etc).
  • Loading branch information
icculus committed Jan 4, 2018
1 parent 44565f5 commit b302f0f
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 12 deletions.
43 changes: 33 additions & 10 deletions lx_loader.c
Expand Up @@ -342,7 +342,7 @@ static int decompressIterated(uint8 *dst, uint32 dstlen, const uint8 *src, uint3
} // decompressIterated

// !!! FIXME: mutex this
static int allocateSelector(const uint16 selector, const uint32 addr, const unsigned int contents, const int is32bit)
static int allocateSelector(const uint16 selector, const int pages, const uint32 addr, const unsigned int contents, const int is32bit)
{
assert(selector < (sizeof (GLoaderState->ldt) / sizeof (GLoaderState->ldt[0])));

Expand All @@ -354,7 +354,7 @@ static int allocateSelector(const uint16 selector, const uint32 addr, const unsi
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.limit = pages; //expand_down ? 0 : 16;
entry.seg_32bit = is32bit;
entry.contents = contents;
entry.read_exec_only = 0;
Expand All @@ -369,7 +369,7 @@ static int allocateSelector(const uint16 selector, const uint32 addr, const unsi
} // allocateSelector

// !!! FIXME: mutex this
static int findSelector(const uint32 _addr, uint16 *outselector, uint16 *outoffset)
static int findSelector(const uint32 _addr, uint16 *outselector, uint16 *outoffset, int iscode)
{
uint32 addr = _addr;
if (addr < 4096)
Expand All @@ -380,7 +380,7 @@ static int findSelector(const uint32 _addr, uint16 *outselector, uint16 *outoffs
int available = -1;
int preferred = -1;

// optimize for the case where we need a selector that happenes to be in tiled memory,
// optimize for the case where we need a selector that happens to be in tiled memory,
// since it's fast to look up.
if (addr < (1024 * 1024 * 512)) {
const uint16 idx = (uint16) (addr >> 16);
Expand Down Expand Up @@ -413,11 +413,31 @@ static int findSelector(const uint32 _addr, uint16 *outselector, uint16 *outoffs
return 0; // uh oh, out of selectors!
} // if

// decide if there is code or data mapped here. If there's an OS/2 API to
// change page permissions, we'll need to update the mapping and our state.
for (LxModule *lxmod = GLoaderState->loaded_modules; (iscode == -1) && lxmod; lxmod = lxmod->next) {
LxMmaps *mmaps = lxmod->mmaps;
for (uint32 i = 0; i < lxmod->lx.module_num_objects; i++, mmaps++) {
const size_t lo = (size_t) mmaps->addr;
const size_t hi = lo + mmaps->size;
if ((addr >= lo) && (addr <= hi)) {
iscode = ((mmaps->prot & PROT_EXEC) != 0);
break;
} // if
} // for
} // for

if (iscode == -1) {
iscode = 0;
}

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)) {
//printf("setting up LDT mapping for %s at selector %u\n", iscode ? "code" : "data", (unsigned int) selector);

if (!allocateSelector(selector, 16, addr, iscode ? MODIFY_LDT_CONTENTS_CODE : MODIFY_LDT_CONTENTS_DATA, 0)) {
fprintf(stderr, "Uhoh, we've failed to allocate LDT selector %u! Probably about to crash...\n", (uint) selector); fflush(stderr);
return 0;
} // if
Expand Down Expand Up @@ -466,7 +486,7 @@ static uint32 convert32to1616(void *addr32)

uint16 selector = 0;
uint16 offset = 0;
if (!findSelector((uint32) addr32, &selector, &offset)) {
if (!findSelector((uint32) addr32, &selector, &offset, -1)) {
fprintf(stderr, "Uhoh, ran out of LDT entries?!\n");
return 0; // oh well, crash, probably.
} // if
Expand All @@ -481,7 +501,7 @@ static uint32 convert32to1616(void *addr32)
// 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
// without calling DosFlatToSel(). 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.
Expand All @@ -502,7 +522,7 @@ static void initOs2StackSegments(uint32 addr, uint32 stacklen, const int deinit)
if (deinit) {
freeSelector((uint16) (addr >> 16));
} else {
if (!allocateSelector((uint16) (addr >> 16), addr, MODIFY_LDT_CONTENTS_DATA/*STACK*/, 0)) {
if (!allocateSelector((uint16) (addr >> 16), 16, addr, MODIFY_LDT_CONTENTS_DATA, 0)) {
FIXME("uhoh, couldn't set up an LDT entry for a stack segment! Might crash later!");
} // if
} // else
Expand Down Expand Up @@ -691,7 +711,7 @@ static void *generateMissingTrampoline16(const char *_module, const char *_entry
pageused = 0;
uint16 offset = 0xFFFF;
selector = 0xFFFF;
findSelector((uint32) page, &selector, &offset);
findSelector((uint32) page, &selector, &offset, 1);
assert(selector != 0xFFFF);
assert(offset == 0);
} // if
Expand Down Expand Up @@ -1505,7 +1525,8 @@ static LxModule *loadLxModule(const char *fname, uint8 *exe, uint32 exelen, int
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)) {
const int iscode = (obj->object_flags & 0x4) ? 1 : 0;
if (!findSelector((uint32) (size_t) retval->mmaps[i].addr, &retval->mmaps[i].alias, &offset, iscode)) {
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
Expand Down Expand Up @@ -1648,6 +1669,8 @@ static LxModule *loadLxModule(const char *fname, uint8 *exe, uint32 exelen, int
((object_flags & 0x2) ? PROT_WRITE : 0) |
((object_flags & 0x4) ? PROT_EXEC : 0);

retval->mmaps[i].prot = prot;

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,
Expand Down
3 changes: 2 additions & 1 deletion lx_loader.h
Expand Up @@ -134,6 +134,7 @@ typedef struct LxMmaps
void *mapped;
void *addr;
size_t size;
int prot;
uint16 alias; // 16:16 alias, if one.
} LxMmaps;

Expand Down Expand Up @@ -226,7 +227,7 @@ typedef struct LxLoaderState
void (*dosExit)(uint32 action, uint32 result);
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);
int (*findSelector)(const uint32 addr, uint16 *outselector, uint16 *outoffset, int iscode);
void (*freeSelector)(const uint16 selector);
void *(*convert1616to32)(const uint32 addr1616);
uint32 (*convert32to1616)(void *addr32);
Expand Down
2 changes: 1 addition & 1 deletion native/os2native16.h
Expand Up @@ -51,7 +51,7 @@
obj16.addr = mmapaddr; \
\
uint16 offset = 0; \
if (!GLoaderState->findSelector((uint32) obj16.addr, &obj16.alias, &offset)) { \
if (!GLoaderState->findSelector((uint32) obj16.addr, &obj16.alias, &offset, 1)) { \
fprintf(stderr, "couldn't find a selector for 16-bit entry points!\n"); \
munmap(obj16.mapped, vsize); \
obj16.mapped = obj16.addr = NULL; \
Expand Down

0 comments on commit b302f0f

Please sign in to comment.