Release 950216
[wine] / loader / selector.c
1 #ifndef WINELIB
2 /*
3 static char RCSId[] = "$Id: selector.c,v 1.3 1993/07/04 04:04:21 root Exp root $";
4 static char Copyright[] = "Copyright  Robert J. Amstadt, 1993";
5 */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12 #include <unistd.h>
13 #include <errno.h>
14 #ifdef __linux__
15 #include <sys/mman.h>
16 #include <linux/unistd.h>
17 #include <linux/head.h>
18 #include <linux/mman.h>
19 #include <linux/a.out.h>
20 #include <linux/ldt.h>
21 #endif
22 #if defined(__NetBSD__) || defined(__FreeBSD__)
23 #include <sys/mman.h>
24 #include <machine/segments.h>
25 #endif
26 #include "dlls.h"
27 #include "neexe.h"
28 #include "segmem.h"
29 #include "wine.h"
30 #include "if1632.h"
31 #include "windows.h"
32 #include "prototypes.h"
33 #include "stddebug.h"
34 /* #define DEBUG_SELECTORS */
35 #include "debug.h"
36
37
38 #ifdef linux
39 #define DEV_ZERO
40 #ifdef __ELF__
41 #define  UTEXTSEL 0x0f
42 #else
43 #define UTEXTSEL 0x23
44 #endif
45 #endif
46
47 #if defined(__NetBSD__) || defined(__FreeBSD__)
48 #define PAGE_SIZE getpagesize()
49 #define MODIFY_LDT_CONTENTS_DATA        0
50 #define MODIFY_LDT_CONTENTS_STACK       1
51 #define MODIFY_LDT_CONTENTS_CODE        2
52 #define UTEXTSEL 0x1f
53 #endif
54
55 static SEGDESC * EnvironmentSelector =  NULL;
56 static SEGDESC * PSP_Selector = NULL;
57 SEGDESC * MakeProcThunks = NULL;
58 unsigned short PSPSelector;
59 unsigned char ran_out = 0;
60 int LastUsedSelector = FIRST_SELECTOR - 1;
61
62 #define MAX_SELECTORS (512 * 2)
63
64 int max_selectors = 0;
65 unsigned short* SelectorMap;
66 SEGDESC* Segments;
67
68 #ifdef DEV_ZERO
69     static FILE *zfile = NULL;
70 #endif    
71
72 extern void KERNEL_Ordinal_102();
73 extern void UNIXLIB_Ordinal_0();
74 extern char WindowsPath[256];
75
76 extern char **Argv;
77 extern int Argc;
78 extern char **environ;
79
80 unsigned int 
81 GetEntryPointFromOrdinal(struct w_files * wpnt, int ordinal);
82
83 \f
84 /**********************************************************************
85  *                                      InitSelectors
86  */
87 void
88 InitSelectors(void) 
89 {
90     int i;
91     max_selectors = MAX_SELECTORS;
92     SelectorMap = malloc(max_selectors * sizeof(unsigned short));
93     Segments    = malloc(max_selectors * sizeof(SEGDESC));
94     for (i = 0; i < max_selectors; i++) {
95         if (i < FIRST_SELECTOR) {
96             SelectorMap[i] = SELECTOR_IS32BIT;
97 #ifdef __ELF__
98             /* quick hack, just reserves 4 meg for wine. */
99         } else if ((i << (16 + __AHSHIFT)) >= 0x8000000 &&
100                    (i << (16 + __AHSHIFT)) <= 0x8400000) {
101             SelectorMap[i]= SELECTOR_IS32BIT;
102 #endif
103         } else {
104             SelectorMap[i]=0;
105         }
106     }
107 #ifdef __ELF__
108     /* create an ldt. */
109     if (set_ldt_entry(1, 0x8000000, 65535, 1,0x1a ,1,0)) {
110         perror ("set_ldt_entry");
111         exit (1);
112     }
113 #endif
114     }
115 \f
116 /**********************************************************************
117  *                                      FindUnusedSelectors
118  */
119 int
120 FindUnusedSelectors(int n_selectors)
121 {
122     int i;
123     int n_found;
124
125     n_found = 0;
126     for (i = LastUsedSelector + 1; i != LastUsedSelector; i++)
127     {
128         if (i >= max_selectors)
129         {
130             int j;
131             max_selectors += MAX_SELECTORS;
132             dprintf_selectors(stddeb, "Expanding no of segments to %d.\n", 
133                               max_selectors);
134             SelectorMap =
135               realloc(SelectorMap, max_selectors * sizeof(unsigned short));
136             Segments = realloc(Segments, max_selectors * sizeof(SEGDESC));
137             if (!SelectorMap || !Segments)
138               {
139                 fprintf(stderr,
140                         "FindUnusedSelectors: Out of memory! Exiting\n");
141                 exit (-1);
142               }
143             for (j = max_selectors - MAX_SELECTORS; j < max_selectors; j++)
144               SelectorMap[j] = 0;
145         }
146
147         if (SelectorMap[i] && n_found) n_found=0;
148         
149         if (!SelectorMap[i] && ++n_found == n_selectors)
150             break;
151     }
152     
153     if (i == LastUsedSelector)
154         return 0;
155
156     LastUsedSelector = i;
157     return i - n_selectors + 1;
158 }
159 \f
160 #ifdef HAVE_IPC
161 /**********************************************************************
162  *                                      IPCCopySelector
163  *
164  * Created a shared memory copy of a segment:
165  *
166  *      - at a new selector location (if "new" is a 16-bit value)
167  *      - at an arbitrary memory location (if "new" is a 32-bit value)
168  */
169 int
170 IPCCopySelector(int i_old, unsigned long new, int swap_type)
171 {
172     SEGDESC *s_new, *s_old;
173     int i_new;
174     void *base_addr;
175
176     s_old  = &Segments[i_old];
177
178     if (new & 0xffff0000)
179     {
180         /**************************************************************
181          * Let's set the address parameter for no segment.
182          */
183         i_new = -1;
184         s_new = NULL;
185         base_addr = (void *) new;
186     }
187     else
188     {
189         /***************************************************************
190          * We need to fill in the segment descriptor for segment "new".
191          */
192         i_new = new;
193         s_new = &Segments[i_new];
194
195         SelectorMap[i_new] = i_new;
196     
197         s_new->selector  = (i_new << __AHSHIFT) | 0x0007;
198         s_new->base_addr = (void *) ((long) s_new->selector << 16);
199         s_new->length    = s_old->length;
200         s_new->flags     = s_old->flags;
201         s_new->owner     = s_old->owner;
202         if (swap_type)
203         {
204             if (s_old->type == MODIFY_LDT_CONTENTS_DATA)
205                 s_new->type = MODIFY_LDT_CONTENTS_CODE;
206             else
207                 s_new->type = MODIFY_LDT_CONTENTS_DATA;
208         }
209         else
210             s_new->type = s_old->type;
211
212         base_addr = s_new->base_addr;
213     }
214 \f
215     /******************************************************************
216      * If we don't have a shared memory key for s_old, then we need
217      * to get one.  In this case, we'll also have to copy the data
218      * to protect it.
219      */
220     if (s_old->shm_key == -1)
221     {
222         s_old->shm_key = shmget(IPC_PRIVATE, s_old->length, IPC_CREAT | 0600);
223         if (s_old->shm_key == -1)
224         {
225             if (s_new) {
226                 memset(s_new, 0, sizeof(*s_new));
227                 s_new->shm_key = -1;
228             }
229             return -1;
230         }
231         if (shmat(s_old->shm_key, base_addr, 0) == (char *) -1)
232         {
233             if (s_new) {
234                 memset(s_new, 0, sizeof(*s_new));
235                 s_new->shm_key = -1;
236             }
237             shmctl(s_old->shm_key, IPC_RMID, NULL);
238             return -1;
239         }
240         memcpy(base_addr, s_old->base_addr, s_old->length);
241         munmap(s_old->base_addr, 
242                ((s_old->length + PAGE_SIZE) & ~(PAGE_SIZE - 1)));
243         shmat(s_old->shm_key, s_old->base_addr, 0);
244     }
245     /******************************************************************
246      * If have shared memory key s_old, then just attach the new
247      * address.
248      */
249     else
250     {
251         if (shmat(s_old->shm_key, base_addr, 0) == (char *) -1)
252         {
253             if (s_new) {
254                 memset(s_new, 0, sizeof(*s_new));
255                 s_new->shm_key = -1;
256             }
257             return -1;
258         }
259     }
260
261     /******************************************************************
262      * If we are creating a new segment, then we also need to update
263      * the LDT to include the new selector.  In this return the
264      * new selector.
265      */
266     if (s_new)
267     {
268         s_new->shm_key = s_old->shm_key;
269
270         if (set_ldt_entry(i_new, (unsigned long) base_addr, 
271                           s_old->length - 1, 0, s_new->type, 0, 0) < 0)
272         {
273             return -1;
274         }
275
276         return s_new->selector;
277     }
278     /******************************************************************
279      * No new segment.  So, just return the shared memory key.
280      */
281     else
282         return s_old->shm_key;
283 }
284 #endif
285 \f
286 /**********************************************************************
287  *                                      AllocSelector
288  *
289  * This is very bad!!!  This function is implemented for Windows
290  * compatibility only.  Do not call this from the emulation library.
291  */
292 WORD AllocSelector(WORD old_selector)
293 {
294     SEGDESC *s_new;
295     int i_new, i_old;
296     int selector;
297     
298     i_new = FindUnusedSelectors(1);
299     s_new = &Segments[i_new];
300     
301     if (old_selector)
302     {
303         i_old = (old_selector >> __AHSHIFT);
304 #ifdef HAVE_IPC
305         selector = IPCCopySelector(i_old, i_new, 0);
306         if (selector < 0)
307             return 0;
308         else
309             return selector;
310 #else
311         s_old = &Segments[i_old];
312         s_new->selector = (i_new << __AHSHIFT) | 0x0007;
313         *s_new = *s_old;
314         SelectorMap[i_new] = SelectorMap[i_old];
315
316         if (set_ldt_entry(i_new, s_new->base_addr, 
317                           s_new->length - 1, 0, 
318                           s_new->type, 0, 0) < 0)
319         {
320             return 0;
321         }
322 #endif
323     }
324     else
325     {
326         memset(s_new, 0, sizeof(*s_new));
327 #ifdef HAVE_IPC
328         s_new->shm_key = -1;
329 #endif
330         SelectorMap[i_new] = i_new;
331     }
332
333     return (i_new << __AHSHIFT) | 0x0007;
334 }
335 \f
336 /**********************************************************************
337  *                                      PrestoChangoSelector
338  *
339  * This is very bad!!!  This function is implemented for Windows
340  * compatibility only.  Do not call this from the emulation library.
341  */
342 unsigned int PrestoChangoSelector(unsigned src_selector, unsigned dst_selector)
343 {
344 #ifdef HAVE_IPC
345     SEGDESC *src_s;
346     int src_idx, dst_idx;
347
348     src_idx = src_selector >> __AHSHIFT;
349     dst_idx = dst_selector >> __AHSHIFT;
350
351     if (src_idx == dst_idx)
352     {
353         src_s = &Segments[src_idx];
354         
355         if (src_s->type == MODIFY_LDT_CONTENTS_DATA)
356             src_s->type = MODIFY_LDT_CONTENTS_CODE;
357         else
358             src_s->type = MODIFY_LDT_CONTENTS_DATA;
359
360         if (set_ldt_entry(src_idx, (long) src_s->base_addr,
361                           src_s->length - 1, 0, src_s->type, 0, 0) < 0)
362         {
363             return 0;
364         }
365
366         return src_s->selector;
367     }
368     else
369     {
370         return IPCCopySelector(src_idx, dst_idx, 1);
371     }
372 #else /* HAVE_IPC */
373     SEGDESC *src_s, *dst_s;
374     char *p;
375     int src_idx, dst_idx;
376     int alias_count;
377     int i;
378
379     src_idx = (SelectorMap[src_selector >> __AHSHIFT]);
380     dst_idx = dst_selector >> __AHSHIFT;
381     src_s = &Segments[src_idx];
382     dst_s = &Segments[dst_idx];
383
384     alias_count = 0;
385     for (i = FIRST_SELECTOR; i < max_selectors; i++)
386         if (SelectorMap[i] == src_idx)
387             alias_count++;
388     
389     if (src_s->type == MODIFY_LDT_CONTENTS_DATA 
390         || alias_count > 1 || src_idx == dst_idx)
391     {
392         *dst_s = *src_s;
393         
394         if (src_s->type == MODIFY_LDT_CONTENTS_DATA)
395             dst_s->type = MODIFY_LDT_CONTENTS_CODE;
396         else
397             dst_s->type = MODIFY_LDT_CONTENTS_DATA;
398
399         SelectorMap[dst_idx] = SelectorMap[src_idx];
400         if (set_ldt_entry(dst_idx, (long) dst_s->base_addr,
401                           dst_s->length - 1, 0, dst_s->type, 0, 0) < 0)
402         {
403             return 0;
404         }
405     }
406     else
407     {
408         /*
409          * We're changing an unaliased code segment into a data
410          * segment.  The SAFEST (but ugliest) way to deal with 
411          * this is to map the new segment and copy all the contents.
412          */
413         SelectorMap[dst_idx] = dst_idx;
414         *dst_s = *src_s;
415         dst_s->selector  = (dst_idx << __AHSHIFT) | 0x0007;
416         dst_s->base_addr = (void *) ((unsigned int) dst_s->selector << 16);
417         dst_s->type      = MODIFY_LDT_CONTENTS_DATA;
418 #ifdef DEV_ZERO
419         if (zfile == NULL)
420             zfile = fopen("/dev/zero","r");
421         p = (void *) mmap((char *) dst_s->base_addr,
422                           ((dst_s->length + PAGE_SIZE-1) 
423                            & ~(PAGE_SIZE - 1)),
424                           PROT_EXEC | PROT_READ | PROT_WRITE,
425                           MAP_FIXED | MAP_PRIVATE, fileno(zfile), 0);
426 #else
427         p = (void *) mmap((char *) dst_s->base_addr,
428                           ((dst_s->length + PAGE_SIZE-1) 
429                            & ~(PAGE_SIZE - 1)),
430                           PROT_EXEC | PROT_READ | PROT_WRITE,
431                           MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0);
432 #endif
433         if (p == NULL)
434             return 0;
435         
436         memcpy((void *) dst_s->base_addr, (void *) src_s->base_addr, 
437                dst_s->length);
438         if (set_ldt_entry(src_idx, dst_s->base_addr,
439                           dst_s->length - 1, 0, dst_s->type, 0, 0) < 0)
440         {
441             return 0;
442         }
443         if (set_ldt_entry(dst_idx, dst_s->base_addr,
444                           dst_s->length - 1, 0, dst_s->type, 0, 0) < 0)
445         {
446             return 0;
447         }
448
449         munmap(src_s->base_addr,
450                (src_s->length + PAGE_SIZE) & ~(PAGE_SIZE - 1));
451         SelectorMap[src_idx] = dst_idx;
452         src_s->base_addr = dst_s->base_addr;
453     }
454
455     return dst_s->selector;
456 #endif /* HAVE_IPC */
457 }
458 \f
459 /**********************************************************************
460  *                                      AllocCStoDSAlias
461  */
462 WORD AllocDStoCSAlias(WORD ds_selector)
463 {
464     unsigned int cs_selector;
465     
466     if (ds_selector == 0)
467         return 0;
468     
469     cs_selector = AllocSelector(0);
470     return PrestoChangoSelector(ds_selector, cs_selector);
471 }
472 \f
473 /**********************************************************************
474  *                                      CleanupSelectors
475  */
476
477 void CleanupSelectors(void)
478 {
479     int sel_idx;
480
481     for (sel_idx = FIRST_SELECTOR; sel_idx < max_selectors; sel_idx++)
482         if (SelectorMap[sel_idx])
483             FreeSelector((sel_idx << __AHSHIFT) | 7);
484 }
485 \f
486 /**********************************************************************
487  *                                      FreeSelector
488  */
489 WORD FreeSelector(WORD sel)
490 {
491     SEGDESC *s;
492     int sel_idx;
493     int alias_count;
494     int i;
495
496 #ifdef HAVE_IPC
497     sel_idx = sel >> __AHSHIFT;
498
499     if (sel_idx < FIRST_SELECTOR || sel_idx >= max_selectors)
500         return 0;
501     
502     s = &Segments[sel_idx];
503     if (s->shm_key == -1)
504     {
505         munmap(s->base_addr, ((s->length + PAGE_SIZE) & ~(PAGE_SIZE - 1)));
506         memset(s, 0, sizeof(*s));
507         s->shm_key = -1;
508         SelectorMap[sel_idx] = 0;
509     }
510     else
511     {
512         shmdt(s->base_addr);
513
514         alias_count = 0;
515         for (i = FIRST_SELECTOR; i < max_selectors; i++)
516             if (SelectorMap[i] && Segments[i].shm_key == s->shm_key)
517                 alias_count++;
518         
519         if (alias_count == 1)
520             shmctl(s->shm_key, IPC_RMID, NULL);
521             
522         memset(s, 0, sizeof(*s));
523         s->shm_key = -1;
524         SelectorMap[sel_idx] = 0;
525     }
526     
527 #else /* HAVE_IPC */
528     sel_idx = SelectorMap[sel >> __AHSHIFT];
529
530     if (sel_idx < FIRST_SELECTOR || sel_idx >= max_selectors)
531         return 0;
532     
533     if (sel_idx != (sel >> __AHSHIFT))
534     {
535         SelectorMap[sel >> __AHSHIFT] = 0;
536         return 0;
537     }
538     
539     alias_count = 0;
540     for (i = FIRST_SELECTOR; i < max_selectors; i++)
541         if (SelectorMap[i] == sel_idx)
542             alias_count++;
543
544     if (alias_count == 1)
545     {
546         s = &Segments[sel_idx];
547         munmap(s->base_addr, ((s->length + PAGE_SIZE) & ~(PAGE_SIZE - 1)));
548         memset(s, 0, sizeof(*s));
549         SelectorMap[sel >> __AHSHIFT] = 0;
550     }
551 #endif /* HAVE_IPC */
552
553     return 0;
554 }
555 \f
556 /**********************************************************************
557  *                                      CreateNewSegments
558  */
559 SEGDESC *
560 CreateNewSegments(int code_flag, int read_only, int length, int n_segments)
561 {
562     SEGDESC *s, *first_segment;
563     int contents;
564     int i, last_i;
565     
566     i = FindUnusedSelectors(n_segments);
567
568     dprintf_selectors(stddeb, "Using %d segments starting at index %d.\n", 
569         n_segments, i);
570
571     /*
572      * Fill in selector info.
573      */
574     first_segment = s = &Segments[i];
575     for (last_i = i + n_segments; i < last_i; i++, s++)
576     {
577         if (code_flag)
578         {
579             contents = MODIFY_LDT_CONTENTS_CODE;
580             s->flags = 0;
581         }
582         else
583         {
584             contents = MODIFY_LDT_CONTENTS_DATA;
585             s->flags = NE_SEGFLAGS_DATA;
586         }
587         
588         s->selector = (i << __AHSHIFT) | 0x0007;
589         s->length = length;
590 #ifdef DEV_ZERO
591         if (zfile == NULL)
592             zfile = fopen("/dev/zero","r");
593         s->base_addr = (void *) mmap((char *) (s->selector << 16),
594                                      ((s->length + PAGE_SIZE - 1) & 
595                                       ~(PAGE_SIZE - 1)),
596                                      PROT_EXEC | PROT_READ | PROT_WRITE,
597                                      MAP_FIXED | MAP_PRIVATE, 
598                                      fileno(zfile), 0);
599 #else
600         s->base_addr = (void *) mmap((char *) (s->selector << 16),
601                                      ((s->length + PAGE_SIZE - 1) & 
602                                       ~(PAGE_SIZE - 1)),
603                                      PROT_EXEC | PROT_READ | PROT_WRITE,
604                                      MAP_FIXED | MAP_PRIVATE | MAP_ANON, 
605                                      -1, 0);
606 #endif
607 #ifdef HAVE_IPC
608         s->shm_key = -1;
609 #endif
610         if (set_ldt_entry(i, (unsigned long) s->base_addr, 
611                           (s->length - 1) & 0xffff, 0, 
612                           contents, read_only, 0) < 0)
613         {
614             memset(s, 0, sizeof(*s));
615 #ifdef HAVE_IPC
616             s->shm_key = -1;
617 #endif
618             return NULL;
619         }
620
621         SelectorMap[i] = (unsigned short) i;
622         s->type = contents;
623     }
624
625     return first_segment;
626 }
627 \f
628 /**********************************************************************
629  *                                      GetNextSegment
630  */
631 SEGDESC *
632 GetNextSegment(unsigned int flags, unsigned int limit)
633 {
634     return CreateNewSegments(0, 0, limit, 1);
635 }
636 \f
637 /**********************************************************************
638  *                                      GetEntryPointFromOrdinal
639  */
640 union lookup{
641     struct entry_tab_header_s *eth;
642     struct entry_tab_movable_s *etm;
643     struct entry_tab_fixed_s *etf;
644     char  * cpnt;
645 };
646
647 unsigned int GetEntryDLLName(char * dll_name, char * function, int * sel, 
648                                 int  * addr)
649 {
650         struct dll_table_entry_s *dll_table;
651         struct w_files * wpnt;
652         char * cpnt;
653         int ordinal, j, len;
654
655         dll_table = FindDLLTable(dll_name);
656
657         if(dll_table) {
658                 ordinal = FindOrdinalFromName(dll_table, function);
659                 *sel = dll_table[ordinal].selector;
660                 *addr  = (unsigned int) dll_table[ordinal].address;
661 #ifdef WINESTAT
662                 dll_table[ordinal].used++;
663 #endif
664                 return 0;
665         };
666
667         /* We need a means  of determining the ordinal for the function. */
668         /* Not a builtin symbol, look to see what the file has for us */
669         for(wpnt = wine_files; wpnt; wpnt = wpnt->next){
670                 if(strcasecmp(wpnt->name, dll_name)) continue;
671                 cpnt  = wpnt->ne->nrname_table;
672                 while(1==1){
673                         if( ((int) cpnt)  - ((int)wpnt->ne->nrname_table) >  
674                            wpnt->ne->ne_header->nrname_tab_length)  return 1;
675                         len = *cpnt++;
676                         if(strncmp(cpnt, function, len) ==  0) break;
677                         cpnt += len + 2;
678                 };
679                 ordinal =  *((unsigned short *)  (cpnt +  len));
680                 j = GetEntryPointFromOrdinal(wpnt, ordinal);            
681                 *addr  = j & 0xffff;
682                 j = j >> 16;
683                 *sel = j;
684                 return 0;
685         };
686         return 1;
687 }
688
689 unsigned int GetEntryDLLOrdinal(char * dll_name, int ordinal, int * sel, 
690                                 int  * addr)
691 {
692         struct dll_table_entry_s *dll_table;
693         struct w_files * wpnt;
694         int j;
695
696         dll_table = FindDLLTable(dll_name);
697
698         if(dll_table) {
699             *sel = dll_table[ordinal].selector;
700             *addr  = (unsigned int) dll_table[ordinal].address;
701 #ifdef WINESTAT
702                 dll_table[ordinal].used++;
703 #endif
704             return 0;
705         };
706
707         /* Not a builtin symbol, look to see what the file has for us */
708         for(wpnt = wine_files; wpnt; wpnt = wpnt->next){
709                 if(strcasecmp(wpnt->name, dll_name)) continue;
710                 j = GetEntryPointFromOrdinal(wpnt, ordinal);
711                 *addr  = j & 0xffff;
712                 j = j >> 16;
713                 *sel = j;
714                 return 0;
715         };
716         return 1;
717 }
718
719 unsigned int 
720 GetEntryPointFromOrdinal(struct w_files * wpnt, int ordinal)
721 {
722     union lookup entry_tab_pointer;
723     struct entry_tab_header_s *eth;
724     struct entry_tab_movable_s *etm;
725     struct entry_tab_fixed_s *etf;
726     int current_ordinal;
727     int i;
728     
729    entry_tab_pointer.cpnt = wpnt->ne->lookup_table;
730     /*
731      * Let's walk through the table until we get to our entry.
732      */
733     current_ordinal = 1;
734     while (1)
735     {
736         /*
737          * Read header for this bundle.
738          */
739         eth = entry_tab_pointer.eth++;
740         
741         if (eth->n_entries == 0)
742             return 0xffffffff;  /* Yikes - we went off the end of the table */
743
744         if (eth->seg_number == 0)
745         {
746             current_ordinal += eth->n_entries;
747             if(current_ordinal > ordinal) return 0;
748             continue;
749         }
750
751         /*
752          * Read each of the bundle entries.
753          */
754         for (i = 0; i < eth->n_entries; i++, current_ordinal++)
755         {
756             if (eth->seg_number >= 0xfe)
757             {
758                     etm = entry_tab_pointer.etm++;
759
760                 if (current_ordinal == ordinal)
761                 {
762                     return ((unsigned int) 
763                             (wpnt->ne->selector_table[etm->seg_number - 1].base_addr + 
764                              etm->offset));
765                 }
766             }
767             else
768             {
769                     etf = entry_tab_pointer.etf++;
770
771                 if (current_ordinal == ordinal)
772                 {
773                     return ((unsigned int) 
774                             (wpnt->ne->selector_table[eth->seg_number - 1].base_addr + 
775                              (int) etf->offset[0] + 
776                              ((int) etf->offset[1] << 8)));
777                 }
778             }
779         }
780     }
781 }
782 \f
783 /**********************************************************************
784  *                                      GetDOSEnvironment
785  */
786 LPSTR GetDOSEnvironment(void)
787 {
788     return (LPSTR) EnvironmentSelector->base_addr;
789 }
790 \f
791 /**********************************************************************
792  *                                      CreateEnvironment
793  */
794 static SEGDESC *
795 CreateEnvironment(void)
796 {
797     char **e;
798     char *p;
799     SEGDESC * s;
800
801     s = CreateNewSegments(0, 0, PAGE_SIZE, 1);
802     if (s == NULL)
803         return NULL;
804
805     /*
806      * Fill environment with Windows path, the Unix environment,
807      * and program name.
808      */
809     p = (char *) s->base_addr;
810     strcpy(p, "PATH=");
811     strcat(p, WindowsPath);
812     p += strlen(p) + 1;
813
814     for (e = environ; *e; e++)
815     {
816         if (strncasecmp(*e, "path", 4))
817         {
818             strcpy(p, *e);
819             p += strlen(p) + 1;
820         }
821     }
822
823     *p++ = '\0';
824
825     /*
826      * Display environment
827      */
828     dprintf_selectors(stddeb, "Environment at %p\n", s->base_addr);
829     for (p = s->base_addr; *p; p += strlen(p) + 1)
830         dprintf_selectors(stddeb, "    %s\n", p);
831
832     return  s;
833 }
834 \f
835 /**********************************************************************
836  */
837 WORD GetCurrentPDB()
838 {
839     return PSPSelector;
840 }
841 \f
842 /**********************************************************************
843  *                                      CreatePSP
844  */
845 static SEGDESC *
846 CreatePSP(void)
847 {
848     struct dos_psp_s *psp;
849     unsigned short *usp;
850     SEGDESC * s;
851     char *p1, *p2;
852     int i;
853
854     s = CreateNewSegments(0, 0, PAGE_SIZE, 1);
855
856     /*
857      * Fill PSP
858      */
859     PSPSelector = s->selector;
860     psp = (struct dos_psp_s *) s->base_addr;
861     psp->pspInt20 = 0x20cd;
862     psp->pspDispatcher[0] = 0x9a;
863     usp = (unsigned short *) &psp->pspDispatcher[1];
864     *usp       = (unsigned short) KERNEL_Ordinal_102;
865     *(usp + 1) = UTEXTSEL;
866     psp->pspTerminateVector[0] = (unsigned short) UNIXLIB_Ordinal_0;
867     psp->pspTerminateVector[1] = UTEXTSEL;
868     psp->pspControlCVector[0] = (unsigned short) UNIXLIB_Ordinal_0;
869     psp->pspControlCVector[1] = UTEXTSEL;
870     psp->pspCritErrorVector[0] = (unsigned short) UNIXLIB_Ordinal_0;
871     psp->pspCritErrorVector[1] = UTEXTSEL;
872     psp->pspEnvironment = EnvironmentSelector->selector;
873
874     p1 = psp->pspCommandTail;
875     for (i = 1; i < Argc; i++)
876     {
877         if ((int) ((int) p1 - (int) psp->pspCommandTail) + 
878             strlen(Argv[i]) > 124)
879             break;
880         
881         if (i != 1)
882             *p1++ = ' ';
883
884         for (p2 = Argv[i]; *p2 != '\0'; )
885             *p1++ = *p2++;
886         
887     }
888     *p1 = '\0';
889     psp->pspCommandTailCount = strlen(psp->pspCommandTail);
890
891     return s;
892 }
893 \f
894 /**********************************************************************
895  *                                      CreateSelectors
896  */
897 SEGDESC *
898 CreateSelectors(struct  w_files * wpnt)
899 {
900     int fd = wpnt->fd;
901     struct ne_segment_table_entry_s *seg_table = wpnt->ne->seg_table;
902     struct ne_header_s *ne_header = wpnt->ne->ne_header;
903     SEGDESC *selectors, *s;
904     unsigned short auto_data_sel;
905     int contents, read_only;
906     int SelectorTableLength;
907     int i;
908     int status;
909     int old_length, file_image_length = 0;
910     int saved_old_length = 0;
911
912     auto_data_sel=0;
913     /*
914      * Allocate memory for the table to keep track of all selectors.
915      */
916     SelectorTableLength = ne_header->n_segment_tab;
917     selectors = malloc(SelectorTableLength * sizeof(*selectors));
918     if (selectors == NULL)
919         return NULL;
920
921     /*
922      * Step through the segment table in the exe header.
923      */
924     s = selectors;
925     for (i = 0; i < ne_header->n_segment_tab; i++, s++)
926     {
927         /*
928          * Store the flags in our table.
929          */
930         s->flags = seg_table[i].seg_flags;
931
932         /*
933          * Is there an image for this segment in the file?
934          */
935         if (seg_table[i].seg_data_offset == 0)
936         {
937             /*
938              * No image in exe file, let's allocate some memory for it.
939              */
940             s->length = seg_table[i].min_alloc;
941         }
942         else
943         {
944             /*
945              * Image in file, let's just point to the image in memory.
946              */
947             s->length         = seg_table[i].min_alloc;
948             file_image_length = seg_table[i].seg_data_length;
949             if (file_image_length == 0) file_image_length = 0x10000;
950         }
951
952         if (s->length == 0)
953             s->length = 0x10000;
954         old_length = s->length;
955
956         /*
957          * If this is the automatic data segment, its size must be adjusted.
958          * First we need to check for local heap.  Second we nee to see if
959          * this is also the stack segment.
960          */
961         if (i + 1 == ne_header->auto_data_seg || i + 1 == ne_header->ss)
962         {
963             s->length = 0x10000;
964             ne_header->sp = s->length - 2;
965         }
966
967         /*
968          * Is this a DATA or CODE segment?
969          */
970         read_only = 0;
971         if (s->flags & NE_SEGFLAGS_DATA)
972         {
973             contents = MODIFY_LDT_CONTENTS_DATA;
974             if (s->flags & NE_SEGFLAGS_READONLY)
975                 read_only = 1;
976         }
977         else
978         {
979             contents = MODIFY_LDT_CONTENTS_CODE;
980             if (s->flags & NE_SEGFLAGS_EXECUTEONLY)
981                 read_only = 1;
982         }
983
984 #if 0
985         stmp = CreateNewSegments(!(s->flags & NE_SEGFLAGS_DATA), read_only,
986                                 s->length, 1);
987         s->base_addr = stmp->base_addr;
988         s->selector = stmp->selector;
989 #endif
990         s->selector = GlobalAlloc(GMEM_FIXED, s->length);
991         if (s->selector == 0)
992             myerror("CreateSelectors: GlobalAlloc() failed");
993
994         s->base_addr = (void *) ((LONG) s->selector << 16);
995 #ifdef HAVE_IPC
996         s->shm_key = -1;
997 #endif
998         if (!(s->flags & NE_SEGFLAGS_DATA))
999             PrestoChangoSelector(s->selector, s->selector);
1000         else
1001             memset(s->base_addr, 0, s->length);
1002         
1003         if (seg_table[i].seg_data_offset != 0)
1004         {
1005             /*
1006              * Image in file.
1007              */
1008             status = lseek(fd, seg_table[i].seg_data_offset * 
1009                            (1 << ne_header->align_shift_count), SEEK_SET);
1010             if(read(fd, s->base_addr, file_image_length) != file_image_length)
1011                 myerror("Unable to read segment from file");
1012         }
1013
1014         /*
1015          * If this is the automatic data segment, then we must initialize
1016          * the local heap.
1017          */
1018         if (i + 1 == ne_header->auto_data_seg)
1019         {
1020             auto_data_sel = s->selector;
1021             saved_old_length = old_length;
1022         }
1023     }
1024
1025     if(!auto_data_sel)dprintf_selectors(stddeb,"Warning: No auto_data_sel\n");
1026     s = selectors;
1027     for (i = 0; i < ne_header->n_segment_tab; i++, s++)
1028     {
1029         Segments[s->selector >> __AHSHIFT].owner = auto_data_sel;
1030         if (s->selector == auto_data_sel)
1031             HEAP_LocalInit(auto_data_sel, s->base_addr + saved_old_length, 
1032                            0x10000 - 2 - saved_old_length 
1033                            - ne_header->stack_length);
1034     }
1035
1036     if(!EnvironmentSelector) {
1037             EnvironmentSelector = CreateEnvironment();
1038             PSP_Selector = CreatePSP();
1039             MakeProcThunks = CreateNewSegments(1, 0, 0x10000, 1);
1040     };
1041
1042     return selectors;
1043 }
1044 /**********************************************************************
1045  */
1046 void
1047 FixupFunctionPrologs(struct w_files * wpnt)
1048 {
1049     struct ne_header_s *ne_header = wpnt->ne->ne_header;   
1050     union lookup entry_tab_pointer;
1051     struct entry_tab_header_s *eth;
1052     struct entry_tab_movable_s *etm;
1053     struct entry_tab_fixed_s *etf;
1054     unsigned char *fixup_ptr;
1055     int i;
1056
1057     if (!(ne_header->format_flags & 0x0001))
1058         return;
1059
1060     entry_tab_pointer.cpnt = wpnt->ne->lookup_table;
1061     /*
1062      * Let's walk through the table and fixup prologs as we go.
1063      */
1064     while (1)
1065     {
1066         /* Get bundle header */
1067         eth = entry_tab_pointer.eth++;
1068
1069         /* Check for end of table */
1070         if (eth->n_entries == 0)
1071             return;
1072
1073         /* Check for empty bundle */
1074         if (eth->seg_number == 0)
1075             continue;
1076
1077         /* Examine each bundle */
1078         for (i = 0; i < eth->n_entries; i++)
1079         {
1080             /* Moveable segment */
1081             if (eth->seg_number >= 0xfe)
1082             {
1083                 etm = entry_tab_pointer.etm++;
1084                 fixup_ptr = (wpnt->ne->selector_table[etm->seg_number-1].base_addr
1085                              + etm->offset);
1086             }
1087             else
1088             {
1089                 etf = entry_tab_pointer.etf++;
1090                 fixup_ptr = (wpnt->ne->selector_table[eth->seg_number-1].base_addr
1091                              + (int) etf->offset[0] 
1092                              + ((int) etf->offset[1] << 8));
1093
1094             }
1095
1096             /* Verify the signature */
1097             if (((fixup_ptr[0] == 0x1e && fixup_ptr[1] == 0x58)
1098                  || (fixup_ptr[0] == 0x8c && fixup_ptr[1] == 0xd8))
1099                 && fixup_ptr[2] == 0x90)
1100             {
1101                 fixup_ptr[0] = 0xb8;    /* MOV AX, */
1102                 fixup_ptr[1] = wpnt->hinstance;
1103                 fixup_ptr[2] = (wpnt->hinstance >> 8);
1104             }
1105         }
1106     }
1107 }
1108
1109 /***********************************************************************
1110  *      GetSelectorBase (KERNEL.186)
1111  */
1112 DWORD GetSelectorBase(WORD wSelector)
1113 {
1114         fprintf(stdnimp, "GetSelectorBase(selector %4X) stub!\n", wSelector);
1115         return 0;
1116 }
1117
1118 /***********************************************************************
1119  *      SetSelectorBase (KERNEL.187)
1120  */
1121 void SetSelectorBase(WORD wSelector, DWORD dwBase)
1122 {
1123         fprintf(stdnimp, "SetSelectorBase(selector %4X, base %8lX) stub!\n",
1124                         wSelector, dwBase);
1125 }
1126
1127 /***********************************************************************
1128  *      GetSelectorLimit (KERNEL.188)
1129  */
1130 DWORD GetSelectorLimit(WORD wSelector)
1131 {
1132         fprintf(stdnimp, "GetSelectorLimit(selector %4X) stub!\n", wSelector);
1133
1134         return 0xffff;
1135 }
1136
1137 /***********************************************************************
1138  *      SetSelectorLimit (KERNEL.189)
1139  */
1140 void SetSelectorLimit(WORD wSelector, DWORD dwLimit)
1141 {
1142         fprintf(stdnimp, "SetSelectorLimit(selector %4X, base %8lX) stub!\n", 
1143                         wSelector, dwLimit);
1144 }
1145
1146 #endif /* ifndef WINELIB */