Added YUV routines needed for v4l driver, and in the future possibly
[wine/gsoc-2012-control.git] / dlls / kernel / ne_segment.c
blob8756d127e272013da3d65d971a94c34d3f9da1fd
1 /*
2 * NE segment loading
4 * Copyright 1993 Robert J. Amstadt
5 * Copyright 1995 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "config.h"
23 #include "wine/port.h"
25 #include <assert.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <sys/types.h>
29 #include <fcntl.h>
30 #ifdef HAVE_UNISTD_H
31 # include <unistd.h>
32 #endif
33 #include <ctype.h>
34 #include <string.h>
36 #include "wine/winbase16.h"
37 #include "wownt32.h"
38 #include "wine/library.h"
39 #include "kernel_private.h"
40 #include "kernel16_private.h"
41 #include "toolhelp.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(fixup);
45 WINE_DECLARE_DEBUG_CHANNEL(dll);
46 WINE_DECLARE_DEBUG_CHANNEL(module);
49 * Relocation table entry
51 struct relocation_entry_s
53 BYTE address_type; /* Relocation address type */
54 BYTE relocation_type; /* Relocation type */
55 WORD offset; /* Offset in segment to fixup */
56 WORD target1; /* Target specification */
57 WORD target2; /* Target specification */
61 * Relocation address types
63 #define NE_RADDR_LOWBYTE 0
64 #define NE_RADDR_SELECTOR 2
65 #define NE_RADDR_POINTER32 3
66 #define NE_RADDR_OFFSET16 5
67 #define NE_RADDR_POINTER48 11
68 #define NE_RADDR_OFFSET32 13
71 * Relocation types
73 #define NE_RELTYPE_INTERNAL 0
74 #define NE_RELTYPE_ORDINAL 1
75 #define NE_RELTYPE_NAME 2
76 #define NE_RELTYPE_OSFIXUP 3
77 #define NE_RELFLAG_ADDITIVE 4
79 /* Self-loading modules contain this structure in their first segment */
80 typedef struct
82 WORD version; /* Must be "A0" (0x3041) */
83 WORD reserved;
84 FARPROC16 BootApp; /* startup procedure */
85 FARPROC16 LoadAppSeg; /* procedure to load a segment */
86 FARPROC16 reserved2;
87 FARPROC16 MyAlloc; /* memory allocation procedure,
88 * wine must write this field */
89 FARPROC16 EntryAddrProc;
90 FARPROC16 ExitProc; /* exit procedure */
91 WORD reserved3[4];
92 FARPROC16 SetOwner; /* Set Owner procedure, exported by wine */
93 } SELFLOADHEADER;
95 #define SEL(x) ((x)|1)
97 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum);
100 /***********************************************************************
101 * NE_GetRelocAddrName
103 static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
105 switch(addr_type & 0x7f)
107 case NE_RADDR_LOWBYTE: return additive ? "BYTE add" : "BYTE";
108 case NE_RADDR_OFFSET16: return additive ? "OFFSET16 add" : "OFFSET16";
109 case NE_RADDR_POINTER32: return additive ? "POINTER32 add" : "POINTER32";
110 case NE_RADDR_SELECTOR: return additive ? "SELECTOR add" : "SELECTOR";
111 case NE_RADDR_POINTER48: return additive ? "POINTER48 add" : "POINTER48";
112 case NE_RADDR_OFFSET32: return additive ? "OFFSET32 add" : "OFFSET32";
114 return "???";
118 /***********************************************************************
119 * NE_OpenFile
121 static HFILE16 NE_OpenFile( NE_MODULE *pModule )
123 char *name = NE_MODULE_NAME( pModule );
124 HANDLE handle = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ,
125 NULL, OPEN_EXISTING, 0, 0 );
127 if (handle == INVALID_HANDLE_VALUE)
129 ERR( "Can't open file '%s' for module %04x\n", name, pModule->self );
130 return HFILE_ERROR;
132 return Win32HandleToDosFileHandle( handle );
136 /***********************************************************************
137 * apply_relocations
139 * Apply relocations to a segment. Helper for NE_LoadSegment.
141 static inline BOOL apply_relocations( NE_MODULE *pModule, const struct relocation_entry_s *rep,
142 int count, int segnum )
144 BYTE *func_name;
145 char buffer[256];
146 int i, ordinal;
147 WORD offset, *sp;
148 HMODULE16 module;
149 FARPROC16 address = 0;
150 HMODULE16 *pModuleTable = (HMODULE16 *)((char *)pModule + pModule->ne_modtab);
151 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
152 SEGTABLEENTRY *pSeg = pSegTable + segnum - 1;
155 * Go through the relocation table one entry at a time.
157 for (i = 0; i < count; i++, rep++)
160 * Get the target address corresponding to this entry.
163 /* If additive, there is no target chain list. Instead, add source
164 and target */
165 int additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
166 switch (rep->relocation_type & 3)
168 case NE_RELTYPE_ORDINAL:
169 module = pModuleTable[rep->target1-1];
170 ordinal = rep->target2;
171 address = NE_GetEntryPoint( module, ordinal );
172 if (!address)
174 NE_MODULE *pTarget = NE_GetPtr( module );
175 if (!pTarget)
176 WARN_(module)("Module not found: %04x, reference %d of module %*.*s\n",
177 module, rep->target1,
178 *((BYTE *)pModule + pModule->ne_restab),
179 *((BYTE *)pModule + pModule->ne_restab),
180 (char *)pModule + pModule->ne_restab + 1 );
181 else
183 ERR("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
184 *((BYTE *)pTarget + pTarget->ne_restab),
185 (char *)pTarget + pTarget->ne_restab + 1,
186 ordinal );
187 address = (FARPROC16)0xdeadbeef;
190 if (TRACE_ON(fixup))
192 NE_MODULE *pTarget = NE_GetPtr( module );
193 TRACE("%d: %.*s.%d=%04x:%04x %s\n", i + 1,
194 *((BYTE *)pTarget + pTarget->ne_restab),
195 (char *)pTarget + pTarget->ne_restab + 1,
196 ordinal, HIWORD(address), LOWORD(address),
197 NE_GetRelocAddrName( rep->address_type, additive ) );
199 break;
201 case NE_RELTYPE_NAME:
202 module = pModuleTable[rep->target1-1];
203 func_name = (char *)pModule + pModule->ne_imptab + rep->target2;
204 memcpy( buffer, func_name+1, *func_name );
205 buffer[*func_name] = '\0';
206 func_name = buffer;
207 ordinal = NE_GetOrdinal( module, func_name );
208 address = NE_GetEntryPoint( module, ordinal );
210 if (ERR_ON(fixup) && !address)
212 NE_MODULE *pTarget = NE_GetPtr( module );
213 ERR("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
214 *((BYTE *)pTarget + pTarget->ne_restab),
215 (char *)pTarget + pTarget->ne_restab + 1, func_name );
217 if (!address) address = (FARPROC16) 0xdeadbeef;
218 if (TRACE_ON(fixup))
220 NE_MODULE *pTarget = NE_GetPtr( module );
221 TRACE("%d: %.*s.%s=%04x:%04x %s\n", i + 1,
222 *((BYTE *)pTarget + pTarget->ne_restab),
223 (char *)pTarget + pTarget->ne_restab + 1,
224 func_name, HIWORD(address), LOWORD(address),
225 NE_GetRelocAddrName( rep->address_type, additive ) );
227 break;
229 case NE_RELTYPE_INTERNAL:
230 if ((rep->target1 & 0xff) == 0xff)
232 address = NE_GetEntryPoint( pModule->self, rep->target2 );
234 else
236 address = (FARPROC16)MAKESEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
239 TRACE("%d: %04x:%04x %s\n",
240 i + 1, HIWORD(address), LOWORD(address),
241 NE_GetRelocAddrName( rep->address_type, additive ) );
242 break;
244 case NE_RELTYPE_OSFIXUP:
245 /* Relocation type 7:
247 * These appear to be used as fixups for the Windows
248 * floating point emulator. Let's just ignore them and
249 * try to use the hardware floating point. Linux should
250 * successfully emulate the coprocessor if it doesn't
251 * exist.
253 TRACE("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
254 i + 1, rep->relocation_type, rep->offset,
255 rep->target1, rep->target2,
256 NE_GetRelocAddrName( rep->address_type, additive ) );
257 continue;
260 offset = rep->offset;
262 /* Apparently, high bit of address_type is sometimes set; */
263 /* we ignore it for now */
264 if (rep->address_type > NE_RADDR_OFFSET32)
266 char module[10];
267 GetModuleName16( pModule->self, module, sizeof(module) );
268 ERR("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
269 module, rep->address_type );
272 if (additive)
274 sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
275 TRACE(" %04x:%04x\n", offset, *sp );
276 switch (rep->address_type & 0x7f)
278 case NE_RADDR_LOWBYTE:
279 *(BYTE *)sp += LOBYTE((int)address);
280 break;
281 case NE_RADDR_OFFSET16:
282 *sp += LOWORD(address);
283 break;
284 case NE_RADDR_POINTER32:
285 *sp += LOWORD(address);
286 *(sp+1) = HIWORD(address);
287 break;
288 case NE_RADDR_SELECTOR:
289 /* Borland creates additive records with offset zero. Strange, but OK */
290 if (*sp)
291 ERR("Additive selector to %04x.Please report\n",*sp);
292 else
293 *sp = HIWORD(address);
294 break;
295 default:
296 goto unknown;
299 else /* non-additive fixup */
303 WORD next_offset;
305 sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
306 next_offset = *sp;
307 TRACE(" %04x:%04x\n", offset, *sp );
308 switch (rep->address_type & 0x7f)
310 case NE_RADDR_LOWBYTE:
311 *(BYTE *)sp = LOBYTE((int)address);
312 break;
313 case NE_RADDR_OFFSET16:
314 *sp = LOWORD(address);
315 break;
316 case NE_RADDR_POINTER32:
317 *(FARPROC16 *)sp = address;
318 break;
319 case NE_RADDR_SELECTOR:
320 *sp = SELECTOROF(address);
321 break;
322 default:
323 goto unknown;
325 if (next_offset == offset) break; /* avoid infinite loop */
326 if (next_offset >= GlobalSize16(pSeg->hSeg)) break;
327 offset = next_offset;
328 } while (offset != 0xffff);
331 return TRUE;
333 unknown:
334 WARN("WARNING: %d: unknown ADDR TYPE %d, "
335 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
336 i + 1, rep->address_type, rep->relocation_type,
337 rep->offset, rep->target1, rep->target2);
338 return FALSE;
342 /***********************************************************************
343 * NE_LoadSegment
345 BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
347 WORD count;
348 DWORD pos;
349 const struct relocation_entry_s *rep;
350 int size;
351 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
352 SEGTABLEENTRY *pSeg = pSegTable + segnum - 1;
354 if (pSeg->flags & NE_SEGFLAGS_LOADED)
356 /* self-loader ? -> already loaded it */
357 if (pModule->ne_flags & NE_FFLAGS_SELFLOAD)
358 return TRUE;
360 /* leave, except for DGROUP, as this may be the second instance */
361 if (segnum != pModule->ne_autodata)
362 return TRUE;
365 if (!pSeg->filepos) return TRUE; /* No file image, just return */
367 TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
368 segnum, pSeg->hSeg, pSeg->flags );
369 pos = pSeg->filepos << pModule->ne_align;
370 if (pSeg->size) size = pSeg->size;
371 else size = pSeg->minsize ? pSeg->minsize : 0x10000;
373 if (pModule->ne_flags & NE_FFLAGS_SELFLOAD && segnum > 1)
375 /* Implement self-loading segments */
376 SELFLOADHEADER *selfloadheader;
377 void *oldstack;
378 HFILE16 hFile16;
379 WORD args[3];
380 DWORD ret;
382 selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg),0) );
383 oldstack = NtCurrentTeb()->WOW32Reserved;
384 NtCurrentTeb()->WOW32Reserved = (void *)MAKESEGPTR(pModule->self_loading_sel,
385 0xff00 - sizeof(STACK16FRAME));
387 hFile16 = NE_OpenFile( pModule );
388 TRACE_(dll)("CallLoadAppSegProc(hmodule=0x%04x,hf=%x,segnum=%d\n",
389 pModule->self,hFile16,segnum );
390 args[2] = pModule->self;
391 args[1] = hFile16;
392 args[0] = segnum;
393 WOWCallback16Ex( (DWORD)selfloadheader->LoadAppSeg, WCB16_PASCAL, sizeof(args), args, &ret );
394 pSeg->hSeg = LOWORD(ret);
395 TRACE_(dll)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n", pSeg->hSeg);
396 _lclose16( hFile16 );
397 NtCurrentTeb()->WOW32Reserved = oldstack;
399 else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
401 void *mem = GlobalLock16(pSeg->hSeg);
402 if (!NE_READ_DATA( pModule, mem, pos, size ))
403 return FALSE;
404 pos += size;
406 else
409 The following bit of code for "iterated segments" was written without
410 any documentation on the format of these segments. It seems to work,
411 but may be missing something.
413 const char *buff = NE_GET_DATA( pModule, pos, size );
414 const char* curr = buff;
415 char *mem = GlobalLock16(pSeg->hSeg);
417 pos += size;
418 if (buff == NULL) return FALSE;
420 while(curr < buff + size) {
421 unsigned int rept = ((short*)curr)[0];
422 unsigned int len = ((short*)curr)[1];
424 curr += 2*sizeof(short);
425 while (rept--)
427 memcpy( mem, curr, len );
428 mem += len;
430 curr += len;
434 pSeg->flags |= NE_SEGFLAGS_LOADED;
436 /* Perform exported function prolog fixups */
437 NE_FixupSegmentPrologs( pModule, segnum );
439 if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
440 return TRUE; /* No relocation data, we are done */
442 if (!NE_READ_DATA( pModule, &count, pos, sizeof(count) ) || !count) return TRUE;
443 pos += sizeof(count);
445 TRACE("Fixups for %.*s, segment %d, hSeg %04x\n",
446 *((BYTE *)pModule + pModule->ne_restab),
447 (char *)pModule + pModule->ne_restab + 1,
448 segnum, pSeg->hSeg );
450 if (!(rep = NE_GET_DATA( pModule, pos, count * sizeof(struct relocation_entry_s) )))
451 return FALSE;
453 return apply_relocations( pModule, rep, count, segnum );
457 /***********************************************************************
458 * NE_LoadAllSegments
460 BOOL NE_LoadAllSegments( NE_MODULE *pModule )
462 int i;
463 SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
465 if (pModule->ne_flags & NE_FFLAGS_SELFLOAD)
467 HFILE16 hFile16;
468 HGLOBAL16 sel;
469 /* Handle self-loading modules */
470 SELFLOADHEADER *selfloadheader;
471 HMODULE16 mod = GetModuleHandle16("KERNEL");
472 void *oldstack;
473 WORD args[2];
475 TRACE_(module)("%.*s is a self-loading module!\n",
476 *((BYTE*)pModule + pModule->ne_restab),
477 (char *)pModule + pModule->ne_restab + 1);
478 if (!NE_LoadSegment( pModule, 1 )) return FALSE;
479 selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg), 0) );
480 selfloadheader->EntryAddrProc = GetProcAddress16(mod,"EntryAddrProc");
481 selfloadheader->MyAlloc = GetProcAddress16(mod,"MyAlloc");
482 selfloadheader->SetOwner = GetProcAddress16(mod,"FarSetOwner");
483 sel = GlobalAlloc16( GMEM_ZEROINIT, 0xFF00 );
484 pModule->self_loading_sel = SEL(sel);
485 FarSetOwner16( sel, pModule->self );
486 oldstack = NtCurrentTeb()->WOW32Reserved;
487 NtCurrentTeb()->WOW32Reserved = (void *)MAKESEGPTR(pModule->self_loading_sel,
488 0xff00 - sizeof(STACK16FRAME) );
490 hFile16 = NE_OpenFile(pModule);
491 TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
492 pModule->self,hFile16);
493 args[1] = pModule->self;
494 args[0] = hFile16;
495 WOWCallback16Ex( (DWORD)selfloadheader->BootApp, WCB16_PASCAL, sizeof(args), args, NULL );
496 TRACE_(dll)("Return from CallBootAppProc\n");
497 _lclose16(hFile16);
498 NtCurrentTeb()->WOW32Reserved = oldstack;
500 for (i = 2; i <= pModule->ne_cseg; i++)
501 if (!NE_LoadSegment( pModule, i )) return FALSE;
503 else
505 for (i = 1; i <= pModule->ne_cseg; i++)
506 if (!NE_LoadSegment( pModule, i )) return FALSE;
508 return TRUE;
512 /***********************************************************************
513 * NE_FixupSegmentPrologs
515 * Fixup exported functions prologs of one segment
517 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum)
519 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
520 ET_BUNDLE *bundle;
521 ET_ENTRY *entry;
522 WORD dgroup, num_entries, sel = SEL(pSegTable[segnum-1].hSeg);
523 BYTE *pSeg, *pFunc;
525 TRACE("(%d);\n", segnum);
527 if (pSegTable[segnum-1].flags & NE_SEGFLAGS_DATA)
529 pSegTable[segnum-1].flags |= NE_SEGFLAGS_LOADED;
530 return;
533 if (!pModule->ne_autodata) return;
535 if (!(dgroup = SEL(pSegTable[pModule->ne_autodata-1].hSeg))) return;
537 pSeg = MapSL( MAKESEGPTR(sel, 0) );
539 bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->ne_enttab);
541 do {
542 TRACE("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle->last - bundle->first, bundle, bundle->next, pSeg);
543 if (!(num_entries = bundle->last - bundle->first))
544 return;
545 entry = (ET_ENTRY *)((BYTE *)bundle+6);
546 while (num_entries--)
548 /*TRACE("entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/
549 if (entry->segnum == segnum)
551 pFunc = ((BYTE *)pSeg+entry->offs);
552 TRACE("pFunc: %p, *(DWORD *)pFunc: %08lx, num_entries: %d\n", pFunc, *(DWORD *)pFunc, num_entries);
553 if (*(pFunc+2) == 0x90)
555 if (*(WORD *)pFunc == 0x581e) /* push ds, pop ax */
557 TRACE("patch %04x:%04x -> mov ax, ds\n", sel, entry->offs);
558 *(WORD *)pFunc = 0xd88c; /* mov ax, ds */
561 if (*(WORD *)pFunc == 0xd88c)
563 if ((entry->flags & 2)) /* public data ? */
565 TRACE("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel, entry->offs, dgroup);
566 *pFunc = 0xb8; /* mov ax, */
567 *(WORD *)(pFunc+1) = dgroup;
569 else
570 if ((pModule->ne_flags & NE_FFLAGS_MULTIPLEDATA)
571 && (entry->flags & 1)) /* exported ? */
573 TRACE("patch %04x:%04x -> nop, nop\n", sel, entry->offs);
574 *(WORD *)pFunc = 0x9090; /* nop, nop */
579 entry++;
581 } while ( (bundle->next)
582 && (bundle = ((ET_BUNDLE *)((BYTE *)pModule + bundle->next))) );
586 /***********************************************************************
587 * PatchCodeHandle (KERNEL.110)
589 * Needed for self-loading modules.
591 DWORD WINAPI PatchCodeHandle16(HANDLE16 hSeg)
593 WORD segnum;
594 WORD sel = SEL(hSeg);
595 NE_MODULE *pModule = NE_GetPtr(FarGetOwner16(sel));
596 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE(pModule);
598 TRACE_(module)("(%04x);\n", hSeg);
600 /* find the segment number of the module that belongs to hSeg */
601 for (segnum = 1; segnum <= pModule->ne_cseg; segnum++)
603 if (SEL(pSegTable[segnum-1].hSeg) == sel)
605 NE_FixupSegmentPrologs(pModule, segnum);
606 break;
610 return MAKELONG(hSeg, sel);
614 /***********************************************************************
615 * NE_GetDLLInitParams
617 static VOID NE_GetDLLInitParams( NE_MODULE *pModule,
618 WORD *hInst, WORD *ds, WORD *heap )
620 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
622 if (!(pModule->ne_flags & NE_FFLAGS_SINGLEDATA))
624 if (pModule->ne_flags & NE_FFLAGS_MULTIPLEDATA || pModule->ne_autodata)
626 /* Not SINGLEDATA */
627 ERR_(dll)("Library is not marked SINGLEDATA\n");
628 exit(1);
630 else /* DATA NONE DLL */
632 *ds = 0;
633 *heap = 0;
636 else /* DATA SINGLE DLL */
638 if (pModule->ne_autodata) {
639 *ds = SEL(pSegTable[pModule->ne_autodata-1].hSeg);
640 *heap = pModule->ne_heap;
642 else /* hmm, DLL has no dgroup,
643 but why has it NE_FFLAGS_SINGLEDATA set ?
644 Buggy DLL compiler ? */
646 *ds = 0;
647 *heap = 0;
651 *hInst = *ds ? GlobalHandle16(*ds) : pModule->self;
655 /***********************************************************************
656 * NE_InitDLL
658 * Call the DLL initialization code
660 static BOOL NE_InitDLL( NE_MODULE *pModule )
662 SEGTABLEENTRY *pSegTable;
663 WORD hInst, ds, heap;
664 CONTEXT86 context;
666 pSegTable = NE_SEG_TABLE( pModule );
668 if (!(pModule->ne_flags & NE_FFLAGS_LIBMODULE) ||
669 (pModule->ne_flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
671 /* Call USER signal handler for Win3.1 compatibility. */
672 NE_CallUserSignalProc( pModule->self, USIG16_DLL_LOAD );
674 if (!SELECTOROF(pModule->ne_csip)) return TRUE; /* no initialization code */
677 /* Registers at initialization must be:
678 * cx heap size
679 * di library instance
680 * ds data segment if any
681 * es:si command line (always 0)
684 memset( &context, 0, sizeof(context) );
686 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
688 context.Ecx = heap;
689 context.Edi = hInst;
690 context.SegDs = ds;
691 context.SegEs = ds; /* who knows ... */
692 context.SegFs = wine_get_fs();
693 context.SegGs = wine_get_gs();
694 context.SegCs = SEL(pSegTable[SELECTOROF(pModule->ne_csip)-1].hSeg);
695 context.Eip = OFFSETOF(pModule->ne_csip);
696 context.Ebp = OFFSETOF(NtCurrentTeb()->WOW32Reserved) + (WORD)&((STACK16FRAME*)0)->bp;
698 pModule->ne_csip = 0; /* Don't initialize it twice */
699 TRACE_(dll)("Calling LibMain for %.*s, cs:ip=%04lx:%04lx ds=%04lx di=%04x cx=%04x\n",
700 *((BYTE*)pModule + pModule->ne_restab),
701 (char *)pModule + pModule->ne_restab + 1,
702 context.SegCs, context.Eip, context.SegDs,
703 LOWORD(context.Edi), LOWORD(context.Ecx) );
704 WOWCallback16Ex( 0, WCB16_REGS, 0, NULL, (DWORD *)&context );
705 return TRUE;
708 /***********************************************************************
709 * NE_InitializeDLLs
711 * Recursively initialize all DLLs (according to the order in which
712 * they where loaded).
714 void NE_InitializeDLLs( HMODULE16 hModule )
716 NE_MODULE *pModule;
717 HMODULE16 *pDLL;
719 if (!(pModule = NE_GetPtr( hModule ))) return;
720 assert( !(pModule->ne_flags & NE_FFLAGS_WIN32) );
722 if (pModule->dlls_to_init)
724 HGLOBAL16 to_init = pModule->dlls_to_init;
725 pModule->dlls_to_init = 0;
726 for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
728 NE_InitializeDLLs( *pDLL );
730 GlobalFree16( to_init );
732 NE_InitDLL( pModule );
736 /**********************************************************************
737 * NE_CallUserSignalProc
739 * According to "Undocumented Windows", the task signal proc is
740 * bypassed for module load/unload notifications, and the USER signal
741 * proc is called directly instead. This is what this function does.
743 typedef DWORD (WINAPI *pSignalProc)( HANDLE16 module, UINT16 code, UINT16 exit,
744 HINSTANCE16 inst, HQUEUE16 queue );
746 void NE_CallUserSignalProc( HMODULE16 hModule, UINT16 code )
748 FARPROC16 proc;
749 HMODULE16 user = GetModuleHandle16("user.exe");
751 if (!user) return;
752 if ((proc = GetProcAddress16( user, "SignalProc" )))
754 /* USER is always a builtin dll */
755 pSignalProc sigproc = (pSignalProc)((ENTRYPOINT16 *)MapSL( (SEGPTR)proc ))->target;
756 sigproc( hModule, code, 0, 0, 0 );
761 /***********************************************************************
762 * NE_CallDllEntryPoint
764 * Call the DllEntryPoint of DLLs with subsystem >= 4.0
766 typedef DWORD (WINAPI *WinNEEntryProc)(DWORD,WORD,WORD,WORD,DWORD,WORD);
768 static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
770 WORD hInst, ds, heap;
771 FARPROC16 entryPoint;
773 if (!(pModule->ne_flags & NE_FFLAGS_LIBMODULE)) return;
774 if (!(pModule->ne_flags & NE_FFLAGS_BUILTIN) && pModule->ne_expver < 0x0400) return;
775 if (!(entryPoint = GetProcAddress16( pModule->self, "DllEntryPoint" ))) return;
777 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
779 TRACE_(dll)( "Calling %s DllEntryPoint, cs:ip=%04x:%04x\n",
780 NE_MODULE_NAME( pModule ),
781 SELECTOROF(entryPoint), OFFSETOF(entryPoint) );
783 if ( pModule->ne_flags & NE_FFLAGS_BUILTIN )
785 WinNEEntryProc entryProc = (WinNEEntryProc)((ENTRYPOINT16 *)MapSL( (SEGPTR)entryPoint ))->target;
787 entryProc( dwReason, hInst, ds, heap, 0, 0 );
789 else
791 CONTEXT86 context;
792 WORD args[8];
794 memset( &context, 0, sizeof(context) );
795 context.SegDs = ds;
796 context.SegEs = ds; /* who knows ... */
797 context.SegFs = wine_get_fs();
798 context.SegGs = wine_get_gs();
799 context.SegCs = HIWORD(entryPoint);
800 context.Eip = LOWORD(entryPoint);
801 context.Ebp = OFFSETOF(NtCurrentTeb()->WOW32Reserved) + (WORD)&((STACK16FRAME*)0)->bp;
803 args[7] = HIWORD(dwReason);
804 args[6] = LOWORD(dwReason);
805 args[5] = hInst;
806 args[4] = ds;
807 args[3] = heap;
808 args[2] = 0; /* HIWORD(dwReserved1) */
809 args[1] = 0; /* LOWORD(dwReserved1) */
810 args[0] = 0; /* wReserved2 */
811 WOWCallback16Ex( 0, WCB16_REGS, sizeof(args), args, (DWORD *)&context );
815 /***********************************************************************
816 * NE_DllProcessAttach
818 * Call the DllEntryPoint of all modules this one (recursively)
819 * depends on, according to the order in which they were loaded.
821 * Note that --as opposed to the PE module case-- there is no notion
822 * of 'module loaded into a process' for NE modules, and hence we
823 * have no place to store the fact that the DllEntryPoint of a
824 * given module was already called on behalf of this process (e.g.
825 * due to some earlier LoadLibrary16 call).
827 * Thus, we just call the DllEntryPoint twice in that case. Win9x
828 * appears to behave this way as well ...
830 * This routine must only be called with the Win16Lock held.
832 * FIXME: We should actually abort loading in case the DllEntryPoint
833 * returns FALSE ...
837 struct ne_init_list
839 int count;
840 int size;
841 NE_MODULE **module;
844 static void add_to_init_list( struct ne_init_list *list, NE_MODULE *hModule )
846 NE_MODULE **newModule = NULL;
847 if ( list->count == list->size )
849 int newSize = list->size + 128;
851 if (list->module)
852 newModule = HeapReAlloc( GetProcessHeap(), 0,
853 list->module, newSize*sizeof(NE_MODULE *) );
854 else
855 newModule = HeapAlloc( GetProcessHeap(), 0,
856 newSize*sizeof(NE_MODULE *) );
857 if ( !newModule )
859 FIXME_(dll)("Out of memory!\n");
860 return;
863 list->module = newModule;
864 list->size = newSize;
867 list->module[list->count++] = hModule;
870 static void free_init_list( struct ne_init_list *list )
872 if ( list->module )
874 HeapFree( GetProcessHeap(), 0, list->module );
875 memset( list, 0, sizeof(*list) );
879 static void fill_init_list( struct ne_init_list *list, HMODULE16 hModule )
881 NE_MODULE *pModule;
882 HMODULE16 *pModRef;
883 int i;
885 if (!(pModule = NE_GetPtr( hModule ))) return;
886 assert( !(pModule->ne_flags & NE_FFLAGS_WIN32) );
888 /* Never add a module twice */
889 for ( i = 0; i < list->count; i++ )
890 if ( list->module[i] == pModule )
891 return;
893 /* Check for recursive call */
894 if ( pModule->ne_flagsothers & 0x80 ) return;
896 TRACE_(dll)("(%s) - START\n", NE_MODULE_NAME(pModule) );
898 /* Tag current module to prevent recursive loop */
899 pModule->ne_flagsothers |= 0x80;
901 /* Recursively attach all DLLs this one depends on */
902 pModRef = (HMODULE16 *)((char *)pModule + pModule->ne_modtab);
903 for ( i = 0; i < pModule->ne_cmod; i++ )
904 if ( pModRef[i] ) fill_init_list( list, pModRef[i] );
906 /* Add current module */
907 add_to_init_list( list, pModule );
909 /* Remove recursion flag */
910 pModule->ne_flagsothers &= ~0x80;
912 TRACE_(dll)("(%s) - END\n", NE_MODULE_NAME(pModule) );
915 static void call_init_list( struct ne_init_list *list )
917 int i;
918 for ( i = 0; i < list->count; i++ )
919 NE_CallDllEntryPoint( list->module[i], DLL_PROCESS_ATTACH );
922 void NE_DllProcessAttach( HMODULE16 hModule )
924 struct ne_init_list list;
925 memset( &list, 0, sizeof(list) );
927 fill_init_list( &list, hModule );
928 call_init_list( &list );
929 free_init_list( &list );
933 /***********************************************************************
934 * NE_Ne2MemFlags
936 * This function translates NE segment flags to GlobalAlloc flags
938 static WORD NE_Ne2MemFlags(WORD flags)
940 WORD memflags = 0;
941 #if 1
942 if (flags & NE_SEGFLAGS_DISCARDABLE)
943 memflags |= GMEM_DISCARDABLE;
944 if (flags & NE_SEGFLAGS_MOVEABLE ||
945 ( ! (flags & NE_SEGFLAGS_DATA) &&
946 ! (flags & NE_SEGFLAGS_LOADED) &&
947 ! (flags & NE_SEGFLAGS_ALLOCATED)
950 memflags |= GMEM_MOVEABLE;
951 memflags |= GMEM_ZEROINIT;
952 #else
953 memflags = GMEM_ZEROINIT | GMEM_FIXED;
954 #endif
955 return memflags;
958 /***********************************************************************
959 * MyAlloc (KERNEL.668) Wine-specific export
961 * MyAlloc() function for self-loading apps.
963 DWORD WINAPI MyAlloc16( WORD wFlags, WORD wSize, WORD wElem )
965 WORD size = wSize << wElem;
966 HANDLE16 hMem = 0;
968 if (wSize || (wFlags & NE_SEGFLAGS_MOVEABLE))
969 hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
971 if ( ((wFlags & 0x7) != 0x1) && /* DATA */
972 ((wFlags & 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
974 WORD hSel = SEL(hMem);
975 WORD access = SelectorAccessRights16(hSel,0,0);
977 access |= 2<<2; /* SEGMENT_CODE */
978 SelectorAccessRights16(hSel,1,access);
980 if (size)
981 return MAKELONG( hMem, SEL(hMem) );
982 else
983 return MAKELONG( 0, hMem );
986 /***********************************************************************
987 * NE_GetInstance
989 HINSTANCE16 NE_GetInstance( NE_MODULE *pModule )
991 if ( !pModule->ne_autodata )
992 return pModule->self;
993 else
995 SEGTABLEENTRY *pSeg;
996 pSeg = NE_SEG_TABLE( pModule ) + pModule->ne_autodata - 1;
997 return pSeg->hSeg;
1001 /***********************************************************************
1002 * NE_CreateSegment
1004 BOOL NE_CreateSegment( NE_MODULE *pModule, int segnum )
1006 SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule ) + segnum - 1;
1007 int minsize;
1008 unsigned char selflags;
1010 assert( !(pModule->ne_flags & NE_FFLAGS_WIN32) );
1012 if ( segnum < 1 || segnum > pModule->ne_cseg )
1013 return FALSE;
1015 if ( (pModule->ne_flags & NE_FFLAGS_SELFLOAD) && segnum != 1 )
1016 return TRUE; /* selfloader allocates segment itself */
1018 if ( (pSeg->flags & NE_SEGFLAGS_ALLOCATED) && segnum != pModule->ne_autodata )
1019 return TRUE; /* all but DGROUP only allocated once */
1021 minsize = pSeg->minsize ? pSeg->minsize : 0x10000;
1022 if ( segnum == SELECTOROF(pModule->ne_sssp) ) minsize += pModule->ne_stack;
1023 if ( segnum == pModule->ne_autodata ) minsize += pModule->ne_heap;
1025 selflags = (pSeg->flags & NE_SEGFLAGS_DATA) ? WINE_LDT_FLAGS_DATA : WINE_LDT_FLAGS_CODE;
1026 if (pSeg->flags & NE_SEGFLAGS_32BIT) selflags |= WINE_LDT_FLAGS_32BIT;
1027 pSeg->hSeg = GLOBAL_Alloc( NE_Ne2MemFlags(pSeg->flags), minsize, pModule->self, selflags );
1028 if (!pSeg->hSeg) return FALSE;
1030 pSeg->flags |= NE_SEGFLAGS_ALLOCATED;
1031 return TRUE;
1034 /***********************************************************************
1035 * NE_CreateAllSegments
1037 BOOL NE_CreateAllSegments( NE_MODULE *pModule )
1039 int i;
1040 for ( i = 1; i <= pModule->ne_cseg; i++ )
1041 if ( !NE_CreateSegment( pModule, i ) )
1042 return FALSE;
1044 pModule->dgroup_entry = pModule->ne_autodata ? pModule->ne_segtab +
1045 (pModule->ne_autodata - 1) * sizeof(SEGTABLEENTRY) : 0;
1046 return TRUE;
1050 /**********************************************************************
1051 * IsSharedSelector (KERNEL.345)
1053 BOOL16 WINAPI IsSharedSelector16( HANDLE16 selector )
1055 /* Check whether the selector belongs to a DLL */
1056 NE_MODULE *pModule = NE_GetPtr( selector );
1057 if (!pModule) return FALSE;
1058 return (pModule->ne_flags & NE_FFLAGS_LIBMODULE) != 0;