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";
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>
18 #include "prototypes.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 /**********************************************************************
37 struct segment_descriptor_s
*
38 GetNextSegment(unsigned int flags
, unsigned int limit
)
40 struct segment_descriptor_s
*selectors
, *s
;
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;
55 s
->base_addr
= (void *) mmap((char *) (s
->selector
<< 16),
56 ((s
->length
+ PAGE_SIZE
- 1) &
58 PROT_EXEC
| PROT_READ
| PROT_WRITE
,
59 MAP_FIXED
| MAP_PRIVATE
, fileno(zfile
), 0);
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
--;
75 /**********************************************************************
76 * GetEntryPointFromOrdinal
79 struct entry_tab_header_s
*eth
;
80 struct entry_tab_movable_s
*etm
;
81 struct entry_tab_fixed_s
*etf
;
85 unsigned int GetEntryDLLName(char * dll_name
, char * function
, int * sel
,
88 struct dll_table_entry_s
*dll_table
;
89 struct w_files
* wpnt
;
93 dll_table
= FindDLLTable(dll_name
);
96 ordinal
= FindOrdinalFromName(dll_table
, function
);
97 *sel
= dll_table
[ordinal
].selector
;
98 *addr
= (unsigned int) dll_table
[ordinal
].address
;
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
;
108 if( ((int) cpnt
) - ((int)wpnt
->nrname_table
) >
109 wpnt
->ne_header
->nrname_tab_length
) return 1;
111 if(strncmp(cpnt
, function
, len
) == 0) break;
114 ordinal
= *((unsigned short *) (cpnt
+ len
));
115 j
= GetEntryPointFromOrdinal(wpnt
, ordinal
);
118 *sel
= wpnt
->selector_table
[j
].selector
;
124 unsigned int GetEntryDLLOrdinal(char * dll_name
, int ordinal
, int * sel
,
127 struct dll_table_entry_s
*dll_table
;
128 struct w_files
* wpnt
;
131 dll_table
= FindDLLTable(dll_name
);
134 *sel
= dll_table
[ordinal
].selector
;
135 *addr
= (unsigned int) dll_table
[ordinal
].address
;
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
);
145 *sel
= wpnt
->selector_table
[j
].selector
;
152 GetEntryPointFromOrdinal(struct w_files
* wpnt
, int ordinal
)
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
;
167 entry_tab_pointer
.cpnt
= wpnt
->lookup_table
;
169 * Let's walk through the table until we get to our entry.
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;
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
+
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 /**********************************************************************
227 return EnvironmentSelector
->base_addr
;
230 /**********************************************************************
233 static struct segment_descriptor_s
*
234 CreateEnvironment(FILE *zfile
)
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),
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");
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");
278 /**********************************************************************
281 static struct segment_descriptor_s
*
282 CreateThunks(FILE *zfile
)
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.
295 s
->selector
= (next_unused_selector
++ << 3) | 0x0007;
297 s
->base_addr
= (void *) mmap((char *) (s
->selector
<< 16),
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");
315 /**********************************************************************
318 static struct segment_descriptor_s
*
319 CreatePSP(FILE *zfile
)
321 struct dos_psp_s
*psp
;
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),
338 PROT_EXEC
| PROT_READ
| PROT_WRITE
,
339 MAP_FIXED
| MAP_PRIVATE
, fileno(zfile
), 0);
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
;
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");
374 /**********************************************************************
377 struct segment_descriptor_s
*
378 CreateSelectors(struct w_files
* wpnt
)
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
;
385 int contents
, read_only
;
386 int SelectorTableLength
;
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
)
401 * Step through the segment table in the exe header.
404 zfile
= fopen("/dev/zero","r");
405 for (i
= 0; i
< ne_header
->n_segment_tab
; i
++, s
++)
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
);
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
;
434 * Image in file, let's just point to the image in memory.
436 s
->length
= seg_table
[i
].seg_data_length
;
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?
463 if (s
->flags
& NE_SEGFLAGS_DATA
)
465 contents
= MODIFY_LDT_CONTENTS_DATA
;
466 if (s
->flags
& NE_SEGFLAGS_READONLY
)
471 contents
= MODIFY_LDT_CONTENTS_CODE
;
472 if (s
->flags
& NE_SEGFLAGS_EXECUTEONLY
)
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)
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)
498 fprintf(stderr
,"Ran out of ldt entries.\n");
503 * If this is the automatic data segment, then we must initialize
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)
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
);