Sun Jan 2 12:38:53 1994 David Metcalfe <david@prism.demon.co.uk> * [windows/class.c] Implemented GetClassName and GetClassInfo. * [windows/caret.c] Various improvements to text caret code. Fri Dec 31 15:22:22 1993 John Brezak <brezak@apollo.hp.com> * [misc/comm.c] Patches to work with NetBSD. Thu Dec 30 12:11:55 1993 John Richardson <jrichard@cs.uml.edu> * [objects/bitblt.c] Added StretchBlt(). Tue Jan 4 05:22:07 1994 julliard@di.epfl.ch (Alexandre Julliard) * [misc/user.c] Added creation of system message queue. * [objects/bitmap.c] [objects/dcvalues.c] [windows/dc.c] Added DC size fields into DC structure. * [objects/clipping.c] Bug fix in CLIPPING_IntersectRect(). * [windows/class.c] Allocate a DCE instead of a DC for CS_CLASSDC classes. * [windows/clipping.c] Fixed GetUpdateRect() and GetUpdateRgn() to clip to the client area. * [windows/dce.c] Implemented GetDCEx() and GetWindowDC(). * [windows/defwnd.c] Implemented WM_WINDOWPOSCHANGED handling. * [windows/event.c] Preliminary support for Xlib event handling instead of Xt callbacks. Changed MSG_AddMsg() calls to hardware_event() or PostMessage(). * [windows/message.c] Preliminary support for multiple message queues. Implemented hardware_event() to store messages into the system queue. Implemented Get/SetTaskQueue(). Better WM_PAINT and WM_TIMER handling. Changes to use Xlib instead of Xt for events. * [windows/painting.c] Use GetDCEx() to retrieve the DC, to get a correct visible region. * [windows/timer.c] Moved the timer procedure callback into DispatchMessage(). Changed implementation to get rid of Xt timeouts. Timer checking is now done inside GetMessage(). * [windows/win.c] Allocate a DCE instead of a DC for CS_OWNDC windows. Replaced Xt calls with Xlib calls. Moved window positioning functions into windows/winpos.c * [windows/winpos.c] (New file) Rewritten most of the window positioning functions. Implemented SetWindowPos() and MapWindowPoints(). Jan 3, 94 martin2@trgcorp.solucorp.qc.ca (Martin Ayotte) * [if1632/user.spec] Bad arguments description for function SetDlgItemText. * [objects/text.c] Function DrawText now handle DT_CALCRECT request. * [misc/message.c] Message boxes now use DrawText with DT_CALCRECT. * [windows/graphics.c] Bug fix in function FrameRect, (it was using PEN instead of BRUSH). * [windows/win.c] Bug fix for flags in function ShowWindow. More accurate WM_SIZE generated by function ShowWindow. * [controls/listbox.c] More code for LBS_MULTIPLESEL. More code for LBS_MULTICOLUMN. * [include/windows.h] Bad define for MF_SEPARATOR. * [controls/menu.c] New functions: PopMenuWndProc() with 'glues', CreatePopupMenu(), AppendMenu(), InsertMenu(), RemoveMenu(), DeleteMenu(), ModifyMenu(), TrackPopupMenu(). Code in stubs: CreateMenu(), DestroyMenu(). Sat Jan 1 10:22:43 1994 Bob Amstadt (bob@pooh) * loader/wine.c: Added support for relocation types 5 and 6. Mon Dec 27 11:06:03 1993 Erik Bos (erik@trashcan.hacktic.nl) * [misc/comm.c] new functions: BuildCommDCB(), OpenComm(), CloseComm(), SetCommBreak(), ClearCommBreak(), EscapeCommFunction(), FlushComm(), GetCommError(), SetCommEventMask(), GetCommEventMask(), SetCommState(), GetCommState(), TransmitCommChar(), ReadComm(), WriteComm(). Wed Dec 22 13:00:15 1993 David Metcalfe <david@prism.demon.co.uk> * [windows/caret.c] Implemented text caret functions. Tue Dec 21 06:13:58 1993 julliard@di.epfl.ch (Alexandre Julliard) * [loader/wine.c] Bug fix in LoadImage(). * [objects/bitblt.c] [objects/clipping.c] [objects/text.c] [windows/dc.c] [windows/dce.c] [windows/graphics.c] Modified graphics calls to take into account the DC origin. * [windows/defwnd.c] Added preliminary WM_NCCALCSIZE handling. * [windows/event.c] Send WM_NCCALCSIZE message on resize event. * [windows/win.c] Send WM_NCCALCSIZE message in CreateWindow(). Realize widgets at creation time (should prevent problems with unrealized widgets). Dec 19, 93 martin2@trgcorp.solucorp.qc.ca (Martin Ayotte) * [controls/static.c] Send mouse & keyboard message received to its parent. * [controls/scroll.c] Send keyboard message received to its parent. * [controls/listbox.c] Add Navigation keys . ListBox now use VSCROLL & HSCROLL instead of children. Alpha version of LBS_MULTIPLESEL. Alpha version of LBS_MULTICOLUMN. * [controls/combo.c] Add Navigation keys on closed ComboBox. Remove useless 'COMBOBOX_CreateComboBox' function. Mon Dec 19 20:39:34 1993 Erik Bos (erik@trashcan.hacktic.nl) * [loader/wine. LoadImage() modified to use FindFile(). * [misc/file.c] SetErrorMode added * [misc/dos_fs.c] bug fixes. Dec 13, 93 martin2@trgcorp.solucorp.qc.ca (Martin Ayotte) * [memory/global.c] bug fix in GlobalGetFreeSegment : good ptr in 'g_prev'. * [sysres.dll] preliminary version of a 'glass of wine' bitmap * [windows/event.c] New function 'GetCapture'. * [controls/scroll.c] Remove useless 'SCROLLBAR_CreateScrollBar' function. * [controls/listbox.c] Remove useless 'LISTBOX_CreateListBox' function. Mon Dec 13 13:51:00 1993 David Metcalfe <david@prism.demon.co.uk> * [objects/font.c] Corrected bugs in GetCharWidth(). * [windows/event.c] Modified EVENT_key to send Windows virtual key codes for WM_KEYDOWN and WM_KEYUP messages, and a WM_CHAR message for printable characters. Wed Dec 08 19:20:00 1993 Karl Guenter Wuensch (hn324wu@unidui.uni-duisburg.de) * [windows/graphics.c] Added Polyline and Polygon Mon Dec 13 14:51:54 1993 Erik Bos (erik@trashcan.hacktic.nl) * [controls/listbox.c] ListBoxDirectory() modified to use dos_fs.c's functions to access files&|drives. Sat Dec 04 17:04:23 1993 Erik Bos (erik@trashcan.hacktic.nl) * [misc/dos_fs.c] Added FindFile() to search a file in a dos/unix style path. * [misc/file.c] New Win31 functions: OpenFile, _lcreate, _llseek, GetTempDrive, GetTempFileName, GetWindowsDirectory, GetSystemDirectory, GetDriveType. * [misc/int21.c] Modified. Wed Dec 1 16:20:45 1993 Miguel de Icaza (miguel@roxanne.nuclecu.unam.mx) * [misc/profile.c] The Profile functions now return the correct values. They now implement all the features described in the SDK. Tue Nov 30 13:55:27 1993 Bob Amstadt (bob at amscons) * [loader/selector.c] Rewrote selector aliasing routines to use System V IPC routine to alias memory segments. Nov 28, 93 martin2@trgcorp.solucorp.qc.ca (Martin Ayotte) * [controls/listbox.c] More consistency in functions using wIndexes * [controls/scroll.c] New function : ShowScrollBar(). * [loader/cursor.c] ... New file Move cursor functions from [loader/resource.c]. New function : ClipCursor(). New function : GetClipCursor(). New function : CreateCursor(). SetCursor() now working using gloabal variable 'winHasCursor'. *[object/palette.c] New stub only : SelectPalette(). New stub only : RealizePalette(). *[win/event.c] New function : EVENT_enter_notify(), update 'winHasCursor' and send WM_SETCURSOR. *[win/defwnd.c] Add processing of WM_SETCURSOR message. *[win/win.c] New members in WND structure : hCursor, hWndVScroll & hWndHScroll. CreateWindowEx() now create children for WM_HSCROLL & WM_VSCROLL. New function ClientToScreen(). New function ScreenToClient(). Mon Nov 25 18:25:40 1993 Erik Bos (erik@trashcan.hacktic.nl) * [files.h / regfunc.h / misc/dos.c] Removed. * [misc/dos_fs.c] Added support for loading dosdrive cfg from wine.ini. * [misc/int21.c] Modified. Wed Nov 24 11:37:33 1993 julliard@disuns2.epfl.ch (Alexandre Julliard) * [include/atom.h] [memory/atom.c] Implemented atoms. * [windows/class.c] Modified RegisterClass() to use atoms. Implemented CS_GLOBALCLASS style. * [windows/message.c] Implemented RegisterWindowMessage(). * [loader/resource.c] Bug fix in LoadResource(). * [windows/dialog.c] Modified CreateDialogParam() to use Find/LoadResource().
847 lines
19 KiB
C
847 lines
19 KiB
C
static char RCSId[] = "$Id: selector.c,v 1.3 1993/07/04 04:04:21 root Exp root $";
|
||
static char Copyright[] = "Copyright Robert J. Amstadt, 1993";
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <sys/types.h>
|
||
#include <sys/stat.h>
|
||
#include <fcntl.h>
|
||
#include <unistd.h>
|
||
#ifdef __linux__
|
||
#include <linux/unistd.h>
|
||
#include <linux/head.h>
|
||
#include <linux/mman.h>
|
||
#include <linux/a.out.h>
|
||
#include <linux/ldt.h>
|
||
#endif
|
||
#ifdef __NetBSD__
|
||
#include <sys/mman.h>
|
||
#endif
|
||
#include <errno.h>
|
||
#include "neexe.h"
|
||
#include "segmem.h"
|
||
#include "prototypes.h"
|
||
#include "wine.h"
|
||
|
||
|
||
#ifdef linux
|
||
#define DEV_ZERO
|
||
#define UTEXTSEL 0x23
|
||
#endif
|
||
|
||
#ifdef __NetBSD__
|
||
#include <machine/segments.h>
|
||
#define PAGE_SIZE getpagesize()
|
||
#define MODIFY_LDT_CONTENTS_DATA 0
|
||
#define MODIFY_LDT_CONTENTS_STACK 1
|
||
#define MODIFY_LDT_CONTENTS_CODE 2
|
||
#define UTEXTSEL 0x1f
|
||
#endif
|
||
|
||
static SEGDESC * EnvironmentSelector = NULL;
|
||
static SEGDESC * PSP_Selector = NULL;
|
||
SEGDESC * MakeProcThunks = NULL;
|
||
unsigned short PSPSelector;
|
||
unsigned char ran_out = 0;
|
||
int LastUsedSelector = FIRST_SELECTOR - 1;
|
||
|
||
unsigned short SelectorMap[MAX_SELECTORS];
|
||
SEGDESC Segments[MAX_SELECTORS];
|
||
|
||
#ifdef DEV_ZERO
|
||
static FILE *zfile = NULL;
|
||
#endif
|
||
|
||
extern void KERNEL_Ordinal_102();
|
||
extern void UNIXLIB_Ordinal_0();
|
||
|
||
extern char **Argv;
|
||
extern int Argc;
|
||
|
||
/**********************************************************************
|
||
* FindUnusedSelector
|
||
*/
|
||
int
|
||
FindUnusedSelector(void)
|
||
{
|
||
int i;
|
||
|
||
for (i = LastUsedSelector + 1; i != LastUsedSelector; i++)
|
||
{
|
||
if (i >= MAX_SELECTORS)
|
||
i = FIRST_SELECTOR;
|
||
|
||
if (!SelectorMap[i])
|
||
break;
|
||
}
|
||
|
||
if (i == LastUsedSelector)
|
||
return 0;
|
||
|
||
LastUsedSelector = i;
|
||
return i;
|
||
}
|
||
|
||
#ifdef HAVE_IPC
|
||
/**********************************************************************
|
||
* IPCCopySelector
|
||
*/
|
||
int
|
||
IPCCopySelector(int i_old, int i_new, int swap_type)
|
||
{
|
||
SEGDESC *s_new, *s_old;
|
||
|
||
s_old = &Segments[i_old];
|
||
s_new = &Segments[i_new];
|
||
|
||
SelectorMap[i_new] = i_new;
|
||
|
||
s_new->selector = (i_new << 3) | 0x0007;
|
||
s_new->base_addr = (void *) ((long) s_new->selector << 16);
|
||
s_new->length = s_old->length;
|
||
s_new->flags = s_old->flags;
|
||
s_new->owner = s_old->owner;
|
||
if (swap_type)
|
||
{
|
||
if (s_old->type == MODIFY_LDT_CONTENTS_DATA)
|
||
s_new->type = MODIFY_LDT_CONTENTS_CODE;
|
||
else
|
||
s_new->type = MODIFY_LDT_CONTENTS_DATA;
|
||
}
|
||
else
|
||
s_new->type = s_old->type;
|
||
|
||
if (s_old->shm_key == 0)
|
||
{
|
||
s_old->shm_key = shmget(IPC_PRIVATE, s_old->length, 0600);
|
||
if (s_old->shm_key == 0)
|
||
{
|
||
memset(s_new, 0, sizeof(*s_new));
|
||
return 0;
|
||
}
|
||
if (shmat(s_old->shm_key, s_new->base_addr, 0) == NULL)
|
||
{
|
||
memset(s_new, 0, sizeof(*s_new));
|
||
shmctl(s_old->shm_key, IPC_RMID, NULL);
|
||
return 0;
|
||
}
|
||
memcpy(s_new->base_addr, s_old->base_addr, s_new->length);
|
||
munmap(s_old->base_addr,
|
||
((s_old->length + PAGE_SIZE) & ~(PAGE_SIZE - 1)));
|
||
shmat(s_old->shm_key, s_old->base_addr, 0);
|
||
}
|
||
else
|
||
{
|
||
if (shmat(s_old->shm_key, s_new->base_addr, 0) == NULL)
|
||
{
|
||
memset(s_new, 0, sizeof(*s_new));
|
||
return 0;
|
||
}
|
||
}
|
||
s_new->shm_key = s_old->shm_key;
|
||
|
||
if (set_ldt_entry(i_new, (unsigned long) s_new->base_addr,
|
||
s_new->length - 1, 0, s_new->type, 0, 0) < 0)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
return s_new->selector;
|
||
}
|
||
#endif
|
||
|
||
/**********************************************************************
|
||
* AllocSelector
|
||
*
|
||
* This is very bad!!! This function is implemented for Windows
|
||
* compatibility only. Do not call this from the emulation library.
|
||
*/
|
||
unsigned int
|
||
AllocSelector(unsigned int old_selector)
|
||
{
|
||
SEGDESC *s_new, *s_old;
|
||
int i_new, i_old;
|
||
|
||
i_new = FindUnusedSelector();
|
||
s_new = &Segments[i_new];
|
||
|
||
if (old_selector)
|
||
{
|
||
i_old = (old_selector >> 3);
|
||
#ifdef HAVE_IPC
|
||
return IPCCopySelector(i_old, i_new, 0);
|
||
#else
|
||
s_old = &Segments[i_old];
|
||
s_new->selector = (i_new << 3) | 0x0007;
|
||
*s_new = *s_old;
|
||
SelectorMap[i_new] = SelectorMap[i_old];
|
||
|
||
if (set_ldt_entry(i_new, s_new->base_addr,
|
||
s_new->length - 1, 0,
|
||
s_new->type, 0, 0) < 0)
|
||
{
|
||
return 0;
|
||
}
|
||
#endif
|
||
}
|
||
else
|
||
{
|
||
memset(s_new, 0, sizeof(*s_new));
|
||
SelectorMap[i_new] = i_new;
|
||
}
|
||
|
||
return (i_new << 3) | 0x0007;
|
||
}
|
||
|
||
/**********************************************************************
|
||
* PrestoChangoSelector
|
||
*
|
||
* This is very bad!!! This function is implemented for Windows
|
||
* compatibility only. Do not call this from the emulation library.
|
||
*/
|
||
unsigned int PrestoChangoSelector(unsigned src_selector, unsigned dst_selector)
|
||
{
|
||
#ifdef HAVE_IPC
|
||
SEGDESC *src_s;
|
||
int src_idx, dst_idx;
|
||
|
||
src_idx = src_selector >> 3;
|
||
dst_idx = dst_selector >> 3;
|
||
|
||
if (src_idx == dst_idx)
|
||
{
|
||
src_s = &Segments[src_idx];
|
||
|
||
if (src_s->type == MODIFY_LDT_CONTENTS_DATA)
|
||
src_s->type = MODIFY_LDT_CONTENTS_CODE;
|
||
else
|
||
src_s->type = MODIFY_LDT_CONTENTS_DATA;
|
||
|
||
if (set_ldt_entry(src_idx, (long) src_s->base_addr,
|
||
src_s->length - 1, 0, src_s->type, 0, 0) < 0)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
return src_s->selector;
|
||
}
|
||
else
|
||
{
|
||
return IPCCopySelector(src_idx, dst_idx, 1);
|
||
}
|
||
#else /* HAVE_IPC */
|
||
SEGDESC *src_s, *dst_s;
|
||
char *p;
|
||
int src_idx, dst_idx;
|
||
int alias_count;
|
||
int i;
|
||
|
||
src_idx = (SelectorMap[src_selector >> 3]);
|
||
dst_idx = dst_selector >> 3;
|
||
src_s = &Segments[src_idx];
|
||
dst_s = &Segments[dst_idx];
|
||
|
||
alias_count = 0;
|
||
for (i = FIRST_SELECTOR; i < MAX_SELECTORS; i++)
|
||
if (SelectorMap[i] == src_idx)
|
||
alias_count++;
|
||
|
||
if (src_s->type == MODIFY_LDT_CONTENTS_DATA
|
||
|| alias_count > 1 || src_idx == dst_idx)
|
||
{
|
||
*dst_s = *src_s;
|
||
|
||
if (src_s->type == MODIFY_LDT_CONTENTS_DATA)
|
||
dst_s->type = MODIFY_LDT_CONTENTS_CODE;
|
||
else
|
||
dst_s->type = MODIFY_LDT_CONTENTS_DATA;
|
||
|
||
SelectorMap[dst_idx] = SelectorMap[src_idx];
|
||
if (set_ldt_entry(dst_idx, (long) dst_s->base_addr,
|
||
dst_s->length - 1, 0, dst_s->type, 0, 0) < 0)
|
||
{
|
||
return 0;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/*
|
||
* We're changing an unaliased code segment into a data
|
||
* segment. The SAFEST (but ugliest) way to deal with
|
||
* this is to map the new segment and copy all the contents.
|
||
*/
|
||
SelectorMap[dst_idx] = dst_idx;
|
||
*dst_s = *src_s;
|
||
dst_s->selector = (dst_idx << 3) | 0x0007;
|
||
dst_s->base_addr = (void *) ((unsigned int) dst_s->selector << 16);
|
||
dst_s->type = MODIFY_LDT_CONTENTS_DATA;
|
||
#ifdef DEV_ZERO
|
||
if (zfile == NULL)
|
||
zfile = fopen("/dev/zero","r");
|
||
p = (void *) mmap((char *) dst_s->base_addr,
|
||
((dst_s->length + PAGE_SIZE)
|
||
& ~(PAGE_SIZE - 1)),
|
||
PROT_EXEC | PROT_READ | PROT_WRITE,
|
||
MAP_FIXED | MAP_PRIVATE, fileno(zfile), 0);
|
||
#else
|
||
p = (void *) mmap((char *) dst_s->base_addr,
|
||
((dst_s->length + PAGE_SIZE)
|
||
& ~(PAGE_SIZE - 1)),
|
||
PROT_EXEC | PROT_READ | PROT_WRITE,
|
||
MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0);
|
||
#endif
|
||
if (p == NULL)
|
||
return 0;
|
||
|
||
memcpy((void *) dst_s->base_addr, (void *) src_s->base_addr,
|
||
dst_s->length);
|
||
if (set_ldt_entry(src_idx, dst_s->base_addr,
|
||
dst_s->length - 1, 0, dst_s->type, 0, 0) < 0)
|
||
{
|
||
return 0;
|
||
}
|
||
if (set_ldt_entry(dst_idx, dst_s->base_addr,
|
||
dst_s->length - 1, 0, dst_s->type, 0, 0) < 0)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
munmap(src_s->base_addr,
|
||
(src_s->length + PAGE_SIZE) & ~(PAGE_SIZE - 1));
|
||
SelectorMap[src_idx] = dst_idx;
|
||
src_s->base_addr = dst_s->base_addr;
|
||
}
|
||
|
||
return dst_s->selector;
|
||
#endif /* HAVE_IPC */
|
||
}
|
||
|
||
/**********************************************************************
|
||
* AllocCStoDSAlias
|
||
*/
|
||
AllocDStoCSAlias(unsigned int ds_selector)
|
||
{
|
||
unsigned int cs_selector;
|
||
|
||
if (ds_selector == 0)
|
||
return 0;
|
||
|
||
cs_selector = AllocSelector(0);
|
||
return PrestoChangoSelector(ds_selector, cs_selector);
|
||
}
|
||
|
||
/**********************************************************************
|
||
* FreeSelector
|
||
*/
|
||
unsigned int FreeSelector(unsigned int sel)
|
||
{
|
||
SEGDESC *s;
|
||
int sel_idx;
|
||
int alias_count;
|
||
int i;
|
||
|
||
#ifdef HAVE_IPC
|
||
sel_idx = sel >> 3;
|
||
|
||
if (sel_idx < FIRST_SELECTOR || sel_idx >= MAX_SELECTORS)
|
||
return 0;
|
||
|
||
s = &Segments[sel_idx];
|
||
if (s->shm_key == 0)
|
||
{
|
||
munmap(s->base_addr, ((s->length + PAGE_SIZE) & ~(PAGE_SIZE - 1)));
|
||
memcpy(s, 0, sizeof(*s));
|
||
SelectorMap[sel_idx] = 0;
|
||
}
|
||
else
|
||
{
|
||
shmdt(s->base_addr);
|
||
|
||
alias_count = 0;
|
||
for (i = FIRST_SELECTOR; i < MAX_SELECTORS; i++)
|
||
if (SelectorMap[i] && Segments[i].shm_key == s->shm_key)
|
||
alias_count++;
|
||
|
||
if (alias_count == 1)
|
||
shmctl(s->shm_key, IPC_RMID, NULL);
|
||
|
||
memcpy(s, 0, sizeof(*s));
|
||
SelectorMap[sel_idx] = 0;
|
||
}
|
||
|
||
#else /* HAVE_IPC */
|
||
sel_idx = SelectorMap[sel >> 3];
|
||
|
||
if (sel_idx < FIRST_SELECTOR || sel_idx >= MAX_SELECTORS)
|
||
return 0;
|
||
|
||
if (sel_idx != (sel >> 3))
|
||
{
|
||
SelectorMap[sel >> 3] = 0;
|
||
return 0;
|
||
}
|
||
|
||
alias_count = 0;
|
||
for (i = FIRST_SELECTOR; i < MAX_SELECTORS; i++)
|
||
if (SelectorMap[i] == sel_idx)
|
||
alias_count++;
|
||
|
||
if (alias_count == 1)
|
||
{
|
||
s = &Segments[sel_idx];
|
||
munmap(s->base_addr, ((s->length + PAGE_SIZE) & ~(PAGE_SIZE - 1)));
|
||
memcpy(s, 0, sizeof(*s));
|
||
SelectorMap[sel >> 3] = 0;
|
||
}
|
||
#endif /* HAVE_IPC */
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**********************************************************************
|
||
* CreateNewSegment
|
||
*/
|
||
SEGDESC *
|
||
CreateNewSegment(int code_flag, int read_only, int length)
|
||
{
|
||
SEGDESC *s;
|
||
int contents;
|
||
int i;
|
||
|
||
i = FindUnusedSelector();
|
||
|
||
/*
|
||
* Fill in selector info.
|
||
*/
|
||
s = &Segments[i];
|
||
if (code_flag)
|
||
{
|
||
contents = MODIFY_LDT_CONTENTS_CODE;
|
||
s->flags = 0;
|
||
}
|
||
else
|
||
{
|
||
contents = MODIFY_LDT_CONTENTS_DATA;
|
||
s->flags = NE_SEGFLAGS_DATA;
|
||
}
|
||
|
||
s->selector = (i << 3) | 0x0007;
|
||
s->length = length;
|
||
#ifdef DEV_ZERO
|
||
if (zfile == NULL)
|
||
zfile = fopen("/dev/zero","r");
|
||
s->base_addr = (void *) mmap((char *) (s->selector << 16),
|
||
((s->length + PAGE_SIZE - 1) &
|
||
~(PAGE_SIZE - 1)),
|
||
PROT_EXEC | PROT_READ | PROT_WRITE,
|
||
MAP_FIXED | MAP_PRIVATE, fileno(zfile), 0);
|
||
|
||
#else
|
||
s->base_addr = (void *) mmap((char *) (s->selector << 16),
|
||
((s->length + PAGE_SIZE - 1) &
|
||
~(PAGE_SIZE - 1)),
|
||
PROT_EXEC | PROT_READ | PROT_WRITE,
|
||
MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0);
|
||
|
||
#endif
|
||
|
||
if (set_ldt_entry(i, (unsigned long) s->base_addr,
|
||
(s->length - 1) & 0xffff, 0,
|
||
contents, read_only, 0) < 0)
|
||
{
|
||
memset(s, 0, sizeof(*s));
|
||
return NULL;
|
||
}
|
||
|
||
SelectorMap[i] = (unsigned short) i;
|
||
s->type = contents;
|
||
|
||
return s;
|
||
}
|
||
|
||
/**********************************************************************
|
||
* GetNextSegment
|
||
*/
|
||
SEGDESC *
|
||
GetNextSegment(unsigned int flags, unsigned int limit)
|
||
{
|
||
return CreateNewSegment(0, 0, limit);
|
||
}
|
||
|
||
/**********************************************************************
|
||
* GetEntryPointFromOrdinal
|
||
*/
|
||
union lookup{
|
||
struct entry_tab_header_s *eth;
|
||
struct entry_tab_movable_s *etm;
|
||
struct entry_tab_fixed_s *etf;
|
||
char * cpnt;
|
||
};
|
||
|
||
unsigned int GetEntryDLLName(char * dll_name, char * function, int * sel,
|
||
int * addr)
|
||
{
|
||
struct dll_table_entry_s *dll_table;
|
||
struct w_files * wpnt;
|
||
char * cpnt;
|
||
int ordinal, j, len;
|
||
|
||
dll_table = FindDLLTable(dll_name);
|
||
|
||
if(dll_table) {
|
||
ordinal = FindOrdinalFromName(dll_table, function);
|
||
*sel = dll_table[ordinal].selector;
|
||
*addr = (unsigned int) dll_table[ordinal].address;
|
||
#ifdef WINESTAT
|
||
dll_table[ordinal].used++;
|
||
#endif
|
||
return 0;
|
||
};
|
||
|
||
/* We need a means of determining the ordinal for the function. */
|
||
/* Not a builtin symbol, look to see what the file has for us */
|
||
for(wpnt = wine_files; wpnt; wpnt = wpnt->next){
|
||
if(strcmp(wpnt->name, dll_name)) continue;
|
||
cpnt = wpnt->nrname_table;
|
||
while(1==1){
|
||
if( ((int) cpnt) - ((int)wpnt->nrname_table) >
|
||
wpnt->ne_header->nrname_tab_length) return 1;
|
||
len = *cpnt++;
|
||
if(strncmp(cpnt, function, len) == 0) break;
|
||
cpnt += len + 2;
|
||
};
|
||
ordinal = *((unsigned short *) (cpnt + len));
|
||
j = GetEntryPointFromOrdinal(wpnt, ordinal);
|
||
*addr = j & 0xffff;
|
||
j = j >> 16;
|
||
*sel = wpnt->selector_table[j].selector;
|
||
return 0;
|
||
};
|
||
return 1;
|
||
}
|
||
|
||
unsigned int GetEntryDLLOrdinal(char * dll_name, int ordinal, int * sel,
|
||
int * addr)
|
||
{
|
||
struct dll_table_entry_s *dll_table;
|
||
struct w_files * wpnt;
|
||
int j;
|
||
|
||
dll_table = FindDLLTable(dll_name);
|
||
|
||
if(dll_table) {
|
||
*sel = dll_table[ordinal].selector;
|
||
*addr = (unsigned int) dll_table[ordinal].address;
|
||
#ifdef WINESTAT
|
||
dll_table[ordinal].used++;
|
||
#endif
|
||
return 0;
|
||
};
|
||
|
||
/* Not a builtin symbol, look to see what the file has for us */
|
||
for(wpnt = wine_files; wpnt; wpnt = wpnt->next){
|
||
if(strcmp(wpnt->name, dll_name)) continue;
|
||
j = GetEntryPointFromOrdinal(wpnt, ordinal);
|
||
*addr = j & 0xffff;
|
||
j = j >> 16;
|
||
#if 0
|
||
/* This seems like it would never work */
|
||
*sel = wpnt->selector_table[j].selector;
|
||
#else
|
||
*sel = j; /* Is there any reason this will ever fail?? */
|
||
#endif
|
||
return 0;
|
||
};
|
||
return 1;
|
||
}
|
||
|
||
unsigned int
|
||
GetEntryPointFromOrdinal(struct w_files * wpnt, int ordinal)
|
||
{
|
||
int fd = wpnt->fd;
|
||
struct mz_header_s *mz_header = wpnt->mz_header;
|
||
struct ne_header_s *ne_header = wpnt->ne_header;
|
||
|
||
|
||
union lookup entry_tab_pointer;
|
||
struct entry_tab_header_s *eth;
|
||
struct entry_tab_movable_s *etm;
|
||
struct entry_tab_fixed_s *etf;
|
||
int current_ordinal;
|
||
int i;
|
||
|
||
|
||
entry_tab_pointer.cpnt = wpnt->lookup_table;
|
||
/*
|
||
* Let's walk through the table until we get to our entry.
|
||
*/
|
||
current_ordinal = 1;
|
||
while (1)
|
||
{
|
||
/*
|
||
* Read header for this bundle.
|
||
*/
|
||
eth = entry_tab_pointer.eth++;
|
||
|
||
if (eth->n_entries == 0)
|
||
return 0xffffffff; /* Yikes - we went off the end of the table */
|
||
|
||
if (eth->seg_number == 0)
|
||
{
|
||
current_ordinal += eth->n_entries;
|
||
if(current_ordinal > ordinal) return 0;
|
||
continue;
|
||
}
|
||
|
||
/*
|
||
* Read each of the bundle entries.
|
||
*/
|
||
for (i = 0; i < eth->n_entries; i++, current_ordinal++)
|
||
{
|
||
if (eth->seg_number >= 0xfe)
|
||
{
|
||
etm = entry_tab_pointer.etm++;
|
||
|
||
if (current_ordinal == ordinal)
|
||
{
|
||
return ((unsigned int)
|
||
(wpnt->selector_table[etm->seg_number - 1].base_addr +
|
||
etm->offset));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
etf = entry_tab_pointer.etf++;
|
||
|
||
if (current_ordinal == ordinal)
|
||
{
|
||
return ((unsigned int)
|
||
(wpnt->selector_table[eth->seg_number - 1].base_addr +
|
||
(int) etf->offset[0] +
|
||
((int) etf->offset[1] << 8)));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/**********************************************************************
|
||
* GetDOSEnvironment
|
||
*/
|
||
void *
|
||
GetDOSEnvironment()
|
||
{
|
||
return EnvironmentSelector->base_addr;
|
||
}
|
||
|
||
/**********************************************************************
|
||
* CreateEnvironment
|
||
*/
|
||
static SEGDESC *
|
||
CreateEnvironment(void)
|
||
{
|
||
char *p;
|
||
SEGDESC * s;
|
||
|
||
s = CreateNewSegment(0, 0, PAGE_SIZE);
|
||
if (s == NULL)
|
||
return NULL;
|
||
|
||
/*
|
||
* Fill environment with meaningless babble.
|
||
*/
|
||
p = (char *) s->base_addr;
|
||
strcpy(p, "PATH=C:\\WINDOWS");
|
||
p += strlen(p) + 1;
|
||
*p++ = '\0';
|
||
*p++ = 11;
|
||
*p++ = 0;
|
||
strcpy(p, "C:\\TEST.EXE");
|
||
|
||
return s;
|
||
}
|
||
|
||
/**********************************************************************
|
||
* CreatePSP
|
||
*/
|
||
static SEGDESC *
|
||
CreatePSP(void)
|
||
{
|
||
struct dos_psp_s *psp;
|
||
unsigned short *usp;
|
||
SEGDESC * s;
|
||
char *p1, *p2;
|
||
int i;
|
||
|
||
s = CreateNewSegment(0, 0, PAGE_SIZE);
|
||
|
||
/*
|
||
* Fill PSP
|
||
*/
|
||
PSPSelector = s->selector;
|
||
psp = (struct dos_psp_s *) s->base_addr;
|
||
psp->pspInt20 = 0x20cd;
|
||
psp->pspDispatcher[0] = 0x9a;
|
||
usp = (unsigned short *) &psp->pspDispatcher[1];
|
||
*usp = (unsigned short) KERNEL_Ordinal_102;
|
||
*(usp + 1) = UTEXTSEL;
|
||
psp->pspTerminateVector[0] = (unsigned short) UNIXLIB_Ordinal_0;
|
||
psp->pspTerminateVector[1] = UTEXTSEL;
|
||
psp->pspControlCVector[0] = (unsigned short) UNIXLIB_Ordinal_0;
|
||
psp->pspControlCVector[1] = UTEXTSEL;
|
||
psp->pspCritErrorVector[0] = (unsigned short) UNIXLIB_Ordinal_0;
|
||
psp->pspCritErrorVector[1] = UTEXTSEL;
|
||
psp->pspEnvironment = EnvironmentSelector->selector;
|
||
|
||
p1 = psp->pspCommandTail;
|
||
for (i = 1; i < Argc; i++)
|
||
{
|
||
if ((int) ((int) p1 - (int) psp->pspCommandTail) +
|
||
strlen(Argv[i]) > 124)
|
||
break;
|
||
|
||
for (p2 = Argv[i]; *p2 != '\0'; )
|
||
*p1++ = *p2++;
|
||
|
||
*p1++ = ' ';
|
||
}
|
||
*p1++ = '\r';
|
||
*p1 = '\0';
|
||
psp->pspCommandTailCount = strlen(psp->pspCommandTail);
|
||
|
||
return s;
|
||
}
|
||
|
||
/**********************************************************************
|
||
* CreateSelectors
|
||
*/
|
||
SEGDESC *
|
||
CreateSelectors(struct w_files * wpnt)
|
||
{
|
||
int fd = wpnt->fd;
|
||
struct ne_segment_table_entry_s *seg_table = wpnt->seg_table;
|
||
struct ne_header_s *ne_header = wpnt->ne_header;
|
||
SEGDESC *selectors, *s, *stmp;
|
||
unsigned short auto_data_sel;
|
||
int contents, read_only;
|
||
int SelectorTableLength;
|
||
int i;
|
||
int status;
|
||
int old_length, file_image_length;
|
||
|
||
/*
|
||
* Allocate memory for the table to keep track of all selectors.
|
||
*/
|
||
SelectorTableLength = ne_header->n_segment_tab;
|
||
selectors = malloc(SelectorTableLength * sizeof(*selectors));
|
||
if (selectors == NULL)
|
||
return NULL;
|
||
|
||
/*
|
||
* Step through the segment table in the exe header.
|
||
*/
|
||
s = selectors;
|
||
for (i = 0; i < ne_header->n_segment_tab; i++, s++)
|
||
{
|
||
/*
|
||
* Store the flags in our table.
|
||
*/
|
||
s->flags = seg_table[i].seg_flags;
|
||
|
||
/*
|
||
* Is there an image for this segment in the file?
|
||
*/
|
||
if (seg_table[i].seg_data_offset == 0)
|
||
{
|
||
/*
|
||
* No image in exe file, let's allocate some memory for it.
|
||
*/
|
||
s->length = seg_table[i].min_alloc;
|
||
}
|
||
else
|
||
{
|
||
/*
|
||
* Image in file, let's just point to the image in memory.
|
||
*/
|
||
s->length = seg_table[i].min_alloc;
|
||
file_image_length = seg_table[i].seg_data_length;
|
||
if (file_image_length == 0) file_image_length = 0x10000;
|
||
}
|
||
|
||
if (s->length == 0)
|
||
s->length = 0x10000;
|
||
old_length = s->length;
|
||
|
||
/*
|
||
* If this is the automatic data segment, its size must be adjusted.
|
||
* First we need to check for local heap. Second we nee to see if
|
||
* this is also the stack segment.
|
||
*/
|
||
if (i + 1 == ne_header->auto_data_seg)
|
||
{
|
||
s->length += ne_header->local_heap_length;
|
||
|
||
if (i + 1 == ne_header->ss)
|
||
{
|
||
s->length += ne_header->stack_length;
|
||
ne_header->sp = s->length;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Is this a DATA or CODE segment?
|
||
*/
|
||
read_only = 0;
|
||
if (s->flags & NE_SEGFLAGS_DATA)
|
||
{
|
||
contents = MODIFY_LDT_CONTENTS_DATA;
|
||
if (s->flags & NE_SEGFLAGS_READONLY)
|
||
read_only = 1;
|
||
}
|
||
else
|
||
{
|
||
contents = MODIFY_LDT_CONTENTS_CODE;
|
||
if (s->flags & NE_SEGFLAGS_EXECUTEONLY)
|
||
read_only = 1;
|
||
}
|
||
|
||
stmp = CreateNewSegment(!(s->flags & NE_SEGFLAGS_DATA), read_only,
|
||
s->length);
|
||
s->base_addr = stmp->base_addr;
|
||
s->selector = stmp->selector;
|
||
|
||
if (seg_table[i].seg_data_offset != 0)
|
||
{
|
||
/*
|
||
* Image in file.
|
||
*/
|
||
status = lseek(fd, seg_table[i].seg_data_offset *
|
||
(1 << ne_header->align_shift_count), SEEK_SET);
|
||
if(read(fd, s->base_addr, file_image_length) != file_image_length)
|
||
myerror("Unable to read segment from file");
|
||
}
|
||
|
||
/*
|
||
* If this is the automatic data segment, then we must initialize
|
||
* the local heap.
|
||
*/
|
||
if (i + 1 == ne_header->auto_data_seg)
|
||
{
|
||
auto_data_sel = s->selector;
|
||
HEAP_LocalInit(s->base_addr + old_length,
|
||
ne_header->local_heap_length);
|
||
}
|
||
}
|
||
|
||
s = selectors;
|
||
for (i = 0; i < ne_header->n_segment_tab; i++, s++)
|
||
Segments[s->selector >> 3].owner = auto_data_sel;
|
||
|
||
if(!EnvironmentSelector) {
|
||
EnvironmentSelector = CreateEnvironment();
|
||
PSP_Selector = CreatePSP();
|
||
MakeProcThunks = CreateNewSegment(1, 0, 0x10000);
|
||
};
|
||
|
||
return selectors;
|
||
}
|