Release 0.2.0
[wine/multimedia.git] / selector.c
blobef52ae783a00d11d6b70f8991c914974d6f9462f
1 static char RCSId[] = "$Id: selector.c,v 1.3 1993/07/04 04:04:21 root Exp root $";
2 static char Copyright[] = "Copyright Robert J. Amstadt, 1993";
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <fcntl.h>
9 #include <unistd.h>
10 #include <linux/unistd.h>
11 #include <linux/head.h>
12 #include <linux/mman.h>
13 #include <linux/a.out.h>
14 #include <linux/ldt.h>
15 #include <errno.h>
16 #include "neexe.h"
17 #include "segmem.h"
18 #include "prototypes.h"
19 #include "wine.h"
21 #define MAX_SELECTORS 512
23 static struct segment_descriptor_s * EnvironmentSelector = NULL;
24 static struct segment_descriptor_s * PSP_Selector = NULL;
25 struct segment_descriptor_s * MakeProcThunks = NULL;
26 unsigned short PSPSelector;
27 unsigned char ran_out = 0;
28 unsigned short SelectorOwners[MAX_SELECTORS];
30 static int next_unused_selector = 0;
31 extern void KERNEL_Ordinal_102();
32 extern void UNIXLIB_Ordinal_0();
34 /**********************************************************************
35 * GetNextSegment
37 struct segment_descriptor_s *
38 GetNextSegment(unsigned int flags, unsigned int limit)
40 struct segment_descriptor_s *selectors, *s;
41 int sel_idx;
42 FILE *zfile;
44 sel_idx = next_unused_selector++;
47 * Fill in selector info.
49 zfile = fopen("/dev/zero","r");
51 s = malloc(sizeof(*s));
52 s->flags = NE_SEGFLAGS_DATA;
53 s->selector = (sel_idx << 3) | 0x0007;
54 s->length = limit;
55 s->base_addr = (void *) mmap((char *) (s->selector << 16),
56 ((s->length + PAGE_SIZE - 1) &
57 ~(PAGE_SIZE - 1)),
58 PROT_EXEC | PROT_READ | PROT_WRITE,
59 MAP_FIXED | MAP_PRIVATE, fileno(zfile), 0);
61 fclose(zfile);
63 if (set_ldt_entry(sel_idx, (unsigned long) s->base_addr,
64 (s->length - 1) & 0xffff, 0,
65 MODIFY_LDT_CONTENTS_DATA, 0, 0) < 0)
67 next_unused_selector--;
68 free(s);
69 return NULL;
72 return s;
75 /**********************************************************************
76 * GetEntryPointFromOrdinal
78 union lookup{
79 struct entry_tab_header_s *eth;
80 struct entry_tab_movable_s *etm;
81 struct entry_tab_fixed_s *etf;
82 char * cpnt;
85 unsigned int GetEntryDLLName(char * dll_name, char * function, int * sel,
86 int * addr)
88 struct dll_table_entry_s *dll_table;
89 struct w_files * wpnt;
90 char * cpnt;
91 int ordinal, j, len;
93 dll_table = FindDLLTable(dll_name);
95 if(dll_table) {
96 ordinal = FindOrdinalFromName(dll_table, function);
97 *sel = dll_table[ordinal].selector;
98 *addr = (unsigned int) dll_table[ordinal].address;
99 return 0;
102 /* We need a means of determining the ordinal for the function. */
103 /* Not a builtin symbol, look to see what the file has for us */
104 for(wpnt = wine_files; wpnt; wpnt = wpnt->next){
105 if(strcmp(wpnt->name, dll_name)) continue;
106 cpnt = wpnt->nrname_table;
107 while(1==1){
108 if( ((int) cpnt) - ((int)wpnt->nrname_table) >
109 wpnt->ne_header->nrname_tab_length) return 1;
110 len = *cpnt++;
111 if(strncmp(cpnt, function, len) == 0) break;
112 cpnt += len + 2;
114 ordinal = *((unsigned short *) (cpnt + len));
115 j = GetEntryPointFromOrdinal(wpnt, ordinal);
116 *addr = j & 0xffff;
117 j = j >> 16;
118 *sel = wpnt->selector_table[j].selector;
119 return 0;
121 return 1;
124 unsigned int GetEntryDLLOrdinal(char * dll_name, int ordinal, int * sel,
125 int * addr)
127 struct dll_table_entry_s *dll_table;
128 struct w_files * wpnt;
129 int j;
131 dll_table = FindDLLTable(dll_name);
133 if(dll_table) {
134 *sel = dll_table[ordinal].selector;
135 *addr = (unsigned int) dll_table[ordinal].address;
136 return 0;
139 /* Not a builtin symbol, look to see what the file has for us */
140 for(wpnt = wine_files; wpnt; wpnt = wpnt->next){
141 if(strcmp(wpnt->name, dll_name)) continue;
142 j = GetEntryPointFromOrdinal(wpnt, ordinal);
143 *addr = j & 0xffff;
144 j = j >> 16;
145 *sel = wpnt->selector_table[j].selector;
146 return 0;
148 return 1;
151 unsigned int
152 GetEntryPointFromOrdinal(struct w_files * wpnt, int ordinal)
154 int fd = wpnt->fd;
155 struct mz_header_s *mz_header = wpnt->mz_header;
156 struct ne_header_s *ne_header = wpnt->ne_header;
159 union lookup entry_tab_pointer;
160 struct entry_tab_header_s *eth;
161 struct entry_tab_movable_s *etm;
162 struct entry_tab_fixed_s *etf;
163 int current_ordinal;
164 int i;
167 entry_tab_pointer.cpnt = wpnt->lookup_table;
169 * Let's walk through the table until we get to our entry.
171 current_ordinal = 1;
172 while (1)
175 * Read header for this bundle.
177 eth = entry_tab_pointer.eth++;
179 if (eth->n_entries == 0)
180 return 0xffffffff; /* Yikes - we went off the end of the table */
182 if (eth->seg_number == 0)
184 current_ordinal += eth->n_entries;
185 if(current_ordinal > ordinal) return 0;
186 continue;
190 * Read each of the bundle entries.
192 for (i = 0; i < eth->n_entries; i++, current_ordinal++)
194 if (eth->seg_number >= 0xfe)
196 etm = entry_tab_pointer.etm++;
198 if (current_ordinal == ordinal)
200 return ((unsigned int)
201 (wpnt->selector_table[etm->seg_number - 1].base_addr +
202 etm->offset));
205 else
207 etf = entry_tab_pointer.etf++;
209 if (current_ordinal == ordinal)
211 return ((unsigned int)
212 (wpnt->selector_table[eth->seg_number - 1].base_addr +
213 (int) etf->offset[0] +
214 ((int) etf->offset[1] << 8)));
221 /**********************************************************************
222 * GetDOSEnvironment
224 void *
225 GetDOSEnvironment()
227 return EnvironmentSelector->base_addr;
230 /**********************************************************************
231 * CreateEnvironment
233 static struct segment_descriptor_s *
234 CreateEnvironment(FILE *zfile)
236 char *p;
237 int sel_idx;
238 struct segment_descriptor_s * s;
240 s = (struct segment_descriptor_s *)
241 malloc(sizeof(struct segment_descriptor_s));
243 sel_idx = next_unused_selector;
245 * Create memory to hold environment.
247 s->flags = NE_SEGFLAGS_DATA;
248 s->selector = (next_unused_selector++ << 3) | 0x0007;
249 s->length = PAGE_SIZE;
250 s->base_addr = (void *) mmap((char *) (s->selector << 16),
251 PAGE_SIZE,
252 PROT_EXEC | PROT_READ | PROT_WRITE,
253 MAP_FIXED | MAP_PRIVATE, fileno(zfile), 0);
256 * Fill environment with meaningless babble.
258 p = (char *) s->base_addr;
259 strcpy(p, "PATH=C:\\WINDOWS");
260 p += strlen(p) + 1;
261 *p++ = '\0';
262 *p++ = 11;
263 *p++ = 0;
264 strcpy(p, "C:\\TEST.EXE");
267 * Create entry in LDT for this segment.
269 if (set_ldt_entry(sel_idx, (unsigned long) s->base_addr,
270 (s->length - 1) & 0xffff, 0,
271 MODIFY_LDT_CONTENTS_DATA, 0, 0) < 0)
273 myerror("Could not create LDT entry for environment");
275 return s;
278 /**********************************************************************
279 * CreateThunks
281 static struct segment_descriptor_s *
282 CreateThunks(FILE *zfile)
284 int sel_idx;
285 struct segment_descriptor_s * s;
287 s = (struct segment_descriptor_s *)
288 malloc(sizeof(struct segment_descriptor_s));
290 sel_idx = next_unused_selector;
292 * Create memory to hold environment.
294 s->flags = 0;
295 s->selector = (next_unused_selector++ << 3) | 0x0007;
296 s->length = 0x10000;
297 s->base_addr = (void *) mmap((char *) (s->selector << 16),
298 s->length,
299 PROT_EXEC | PROT_READ | PROT_WRITE,
300 MAP_FIXED | MAP_PRIVATE, fileno(zfile), 0);
304 * Create entry in LDT for this segment.
306 if (set_ldt_entry(sel_idx, (unsigned long) s->base_addr,
307 (s->length - 1) & 0xffff, 0,
308 MODIFY_LDT_CONTENTS_CODE, 0, 0) < 0)
310 myerror("Could not create LDT entry for thunks");
312 return s;
315 /**********************************************************************
316 * CreatePSP
318 static struct segment_descriptor_s *
319 CreatePSP(FILE *zfile)
321 struct dos_psp_s *psp;
322 unsigned short *usp;
323 int sel_idx;
324 struct segment_descriptor_s * s;
326 s = (struct segment_descriptor_s *)
327 malloc(sizeof(struct segment_descriptor_s));
329 sel_idx = next_unused_selector;
331 * Create memory to hold PSP.
333 s->flags = NE_SEGFLAGS_DATA;
334 s->selector = (next_unused_selector++ << 3) | 0x0007;
335 s->length = PAGE_SIZE;
336 s->base_addr = (void *) mmap((char *) (s->selector << 16),
337 PAGE_SIZE,
338 PROT_EXEC | PROT_READ | PROT_WRITE,
339 MAP_FIXED | MAP_PRIVATE, fileno(zfile), 0);
342 * Fill PSP
344 PSPSelector = s->selector;
345 psp = (struct dos_psp_s *) s->base_addr;
346 psp->pspInt20 = 0x20cd;
347 psp->pspDispatcher[0] = 0x9a;
348 usp = (unsigned short *) &psp->pspDispatcher[1];
349 *usp = (unsigned short) KERNEL_Ordinal_102;
350 *(usp + 1) = 0x23;
351 psp->pspTerminateVector[0] = (unsigned short) UNIXLIB_Ordinal_0;
352 psp->pspTerminateVector[1] = 0x0023;
353 psp->pspControlCVector[0] = (unsigned short) UNIXLIB_Ordinal_0;
354 psp->pspControlCVector[1] = 0x0023;
355 psp->pspCritErrorVector[0] = (unsigned short) UNIXLIB_Ordinal_0;
356 psp->pspCritErrorVector[1] = 0x0023;
357 psp->pspEnvironment = EnvironmentSelector->selector;
358 psp->pspCommandTailCount = 1;
359 strcpy(psp->pspCommandTail, "\r");
363 * Create entry in LDT for this segment.
365 if (set_ldt_entry(sel_idx, (unsigned long) s->base_addr,
366 (s->length - 1) & 0xffff, 0,
367 MODIFY_LDT_CONTENTS_DATA, 0, 0) < 0)
369 myerror("Could not create LDT entry for PSP");
371 return s;
374 /**********************************************************************
375 * CreateSelectors
377 struct segment_descriptor_s *
378 CreateSelectors(struct w_files * wpnt)
380 int fd = wpnt->fd;
381 struct ne_segment_table_entry_s *seg_table = wpnt->seg_table;
382 struct ne_header_s *ne_header = wpnt->ne_header;
383 struct segment_descriptor_s *selectors, *s;
384 unsigned short *sp;
385 int contents, read_only;
386 int SelectorTableLength;
387 int i;
388 int status;
389 FILE * zfile;
390 int old_length;
393 * Allocate memory for the table to keep track of all selectors.
395 SelectorTableLength = ne_header->n_segment_tab;
396 selectors = malloc(SelectorTableLength * sizeof(*selectors));
397 if (selectors == NULL)
398 return NULL;
401 * Step through the segment table in the exe header.
403 s = selectors;
404 zfile = fopen("/dev/zero","r");
405 for (i = 0; i < ne_header->n_segment_tab; i++, s++)
407 #ifdef DEBUG_SEGMENT
408 printf(" %2d: OFFSET %04.4x, LENGTH %04.4x, ",
409 i + 1, seg_table[i].seg_data_offset,
410 seg_table[i].seg_data_length);
411 printf("FLAGS %04.4x, MIN ALLOC %04.4x\n",
412 seg_table[i].seg_flags, seg_table[i].min_alloc);
413 #endif
416 * Store the flags in our table.
418 s->flags = seg_table[i].seg_flags;
419 s->selector = ((next_unused_selector + i) << 3) | 0x0007;
422 * Is there an image for this segment in the file?
424 if (seg_table[i].seg_data_offset == 0)
427 * No image in exe file, let's allocate some memory for it.
429 s->length = seg_table[i].min_alloc;
431 else
434 * Image in file, let's just point to the image in memory.
436 s->length = seg_table[i].seg_data_length;
439 if (s->length == 0)
440 s->length = 0x10000;
441 old_length = s->length;
444 * If this is the automatic data segment, its size must be adjusted.
445 * First we need to check for local heap. Second we nee to see if
446 * this is also the stack segment.
448 if (i + 1 == ne_header->auto_data_seg)
450 s->length += ne_header->local_heap_length;
452 if (i + 1 == ne_header->ss)
454 s->length += ne_header->stack_length;
455 ne_header->sp = s->length;
460 * Is this a DATA or CODE segment?
462 read_only = 0;
463 if (s->flags & NE_SEGFLAGS_DATA)
465 contents = MODIFY_LDT_CONTENTS_DATA;
466 if (s->flags & NE_SEGFLAGS_READONLY)
467 read_only = 1;
469 else
471 contents = MODIFY_LDT_CONTENTS_CODE;
472 if (s->flags & NE_SEGFLAGS_EXECUTEONLY)
473 read_only = 1;
475 s->base_addr =
476 (void *) mmap((char *) (s->selector << 16),
477 (s->length + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1),
478 PROT_EXEC | PROT_READ | PROT_WRITE,
479 MAP_FIXED | MAP_PRIVATE, fileno(zfile), 0);
480 if (seg_table[i].seg_data_offset != 0)
483 * Image in file.
485 status = lseek(fd, seg_table[i].seg_data_offset *
486 (1 << ne_header->align_shift_count), SEEK_SET);
487 if(read(fd, s->base_addr, old_length) != old_length)
488 myerror("Unable to read segment from file");
491 * Create entry in LDT for this segment.
493 if (set_ldt_entry(i, (unsigned long) s->base_addr,
494 (s->length - 1) & 0xffff, 0,
495 contents, read_only, 0) < 0)
497 free(selectors);
498 fprintf(stderr,"Ran out of ldt entries.\n");
499 ran_out++;
500 return NULL;
503 * If this is the automatic data segment, then we must initialize
504 * the local heap.
506 if (i + 1 == ne_header->auto_data_seg)
508 HEAP_LocalInit(s->base_addr + old_length,
509 ne_header->local_heap_length);
513 sp = &SelectorOwners[next_unused_selector];
514 for (i = 0; i < ne_header->n_segment_tab; i++)
515 *sp++ = (((next_unused_selector + ne_header->auto_data_seg - 1) << 3)
516 | 0x0007);
518 next_unused_selector += ne_header->n_segment_tab;
520 if(!EnvironmentSelector) {
521 EnvironmentSelector = CreateEnvironment(zfile);
522 PSP_Selector = CreatePSP(zfile);
523 MakeProcThunks = CreateThunks(zfile);
526 fclose(zfile);
528 return selectors;