2 static char RCSId
[] = "$Id: selector.c,v 1.3 1993/07/04 04:04:21 root Exp root $";
3 static char Copyright
[] = "Copyright Robert J. Amstadt, 1993";
15 #include <linux/unistd.h>
16 #include <linux/head.h>
17 #include <linux/mman.h>
18 #include <linux/a.out.h>
19 #include <linux/ldt.h>
21 #if defined(__NetBSD__) || defined(__FreeBSD__)
23 #include <machine/segments.h>
30 #include "prototypes.h"
32 /* #define DEBUG_SELECTORS */
39 #if defined(__NetBSD__) || defined(__FreeBSD__)
40 #define PAGE_SIZE getpagesize()
41 #define MODIFY_LDT_CONTENTS_DATA 0
42 #define MODIFY_LDT_CONTENTS_STACK 1
43 #define MODIFY_LDT_CONTENTS_CODE 2
47 static SEGDESC
* EnvironmentSelector
= NULL
;
48 static SEGDESC
* PSP_Selector
= NULL
;
49 SEGDESC
* MakeProcThunks
= NULL
;
50 unsigned short PSPSelector
;
51 unsigned char ran_out
= 0;
52 int LastUsedSelector
= FIRST_SELECTOR
- 1;
54 unsigned short SelectorMap
[MAX_SELECTORS
];
55 SEGDESC Segments
[MAX_SELECTORS
];
58 static FILE *zfile
= NULL
;
61 extern void KERNEL_Ordinal_102();
62 extern void UNIXLIB_Ordinal_0();
67 /**********************************************************************
71 FindUnusedSelectors(int n_selectors
)
77 for (i
= LastUsedSelector
+ 1; i
!= LastUsedSelector
; i
++)
79 if (i
>= MAX_SELECTORS
)
85 if (!SelectorMap
[i
] && ++n_found
== n_selectors
)
89 if (i
== LastUsedSelector
)
93 return i
- n_selectors
+ 1;
97 /**********************************************************************
100 * Created a shared memory copy of a segment:
102 * - at a new selector location (if "new" is a 16-bit value)
103 * - at an arbitrary memory location (if "new" is a 32-bit value)
106 IPCCopySelector(int i_old
, unsigned long new, int swap_type
)
108 SEGDESC
*s_new
, *s_old
;
112 s_old
= &Segments
[i_old
];
114 if (new & 0xffff0000)
116 /**************************************************************
117 * Let's set the address parameter for no segment.
121 base_addr
= (void *) new;
125 /***************************************************************
126 * We need to fill in the segment descriptor for segment "new".
129 s_new
= &Segments
[i_new
];
131 SelectorMap
[i_new
] = i_new
;
133 s_new
->selector
= (i_new
<< 3) | 0x0007;
134 s_new
->base_addr
= (void *) ((long) s_new
->selector
<< 16);
135 s_new
->length
= s_old
->length
;
136 s_new
->flags
= s_old
->flags
;
137 s_new
->owner
= s_old
->owner
;
140 if (s_old
->type
== MODIFY_LDT_CONTENTS_DATA
)
141 s_new
->type
= MODIFY_LDT_CONTENTS_CODE
;
143 s_new
->type
= MODIFY_LDT_CONTENTS_DATA
;
146 s_new
->type
= s_old
->type
;
148 base_addr
= s_new
->base_addr
;
151 /******************************************************************
152 * If we don't have a shared memory key for s_old, then we need
153 * to get one. In this case, we'll also have to copy the data
156 if (s_old
->shm_key
== 0)
158 s_old
->shm_key
= shmget(IPC_PRIVATE
, s_old
->length
, 0600);
159 if (s_old
->shm_key
== 0)
162 memset(s_new
, 0, sizeof(*s_new
));
165 if (shmat(s_old
->shm_key
, base_addr
, 0) == NULL
)
168 memset(s_new
, 0, sizeof(*s_new
));
169 shmctl(s_old
->shm_key
, IPC_RMID
, NULL
);
172 memcpy(base_addr
, s_old
->base_addr
, s_old
->length
);
173 munmap(s_old
->base_addr
,
174 ((s_old
->length
+ PAGE_SIZE
) & ~(PAGE_SIZE
- 1)));
175 shmat(s_old
->shm_key
, s_old
->base_addr
, 0);
177 /******************************************************************
178 * If have shared memory key s_old, then just attach the new
183 if (shmat(s_old
->shm_key
, base_addr
, 0) == NULL
)
186 memset(s_new
, 0, sizeof(*s_new
));
191 /******************************************************************
192 * If we are creating a new segment, then we also need to update
193 * the LDT to include the new selector. In this return the
198 s_new
->shm_key
= s_old
->shm_key
;
200 if (set_ldt_entry(i_new
, (unsigned long) base_addr
,
201 s_old
->length
- 1, 0, s_new
->type
, 0, 0) < 0)
206 return s_new
->selector
;
208 /******************************************************************
209 * No new segment. So, just return the shared memory key.
212 return s_old
->shm_key
;
216 /**********************************************************************
219 * This is very bad!!! This function is implemented for Windows
220 * compatibility only. Do not call this from the emulation library.
222 WORD
AllocSelector(WORD old_selector
)
224 SEGDESC
*s_new
, *s_old
;
228 i_new
= FindUnusedSelectors(1);
229 s_new
= &Segments
[i_new
];
233 i_old
= (old_selector
>> 3);
235 selector
= IPCCopySelector(i_old
, i_new
, 0);
241 s_old
= &Segments
[i_old
];
242 s_new
->selector
= (i_new
<< 3) | 0x0007;
244 SelectorMap
[i_new
] = SelectorMap
[i_old
];
246 if (set_ldt_entry(i_new
, s_new
->base_addr
,
247 s_new
->length
- 1, 0,
248 s_new
->type
, 0, 0) < 0)
256 memset(s_new
, 0, sizeof(*s_new
));
257 SelectorMap
[i_new
] = i_new
;
260 return (i_new
<< 3) | 0x0007;
263 /**********************************************************************
264 * PrestoChangoSelector
266 * This is very bad!!! This function is implemented for Windows
267 * compatibility only. Do not call this from the emulation library.
269 unsigned int PrestoChangoSelector(unsigned src_selector
, unsigned dst_selector
)
273 int src_idx
, dst_idx
;
275 src_idx
= src_selector
>> 3;
276 dst_idx
= dst_selector
>> 3;
278 if (src_idx
== dst_idx
)
280 src_s
= &Segments
[src_idx
];
282 if (src_s
->type
== MODIFY_LDT_CONTENTS_DATA
)
283 src_s
->type
= MODIFY_LDT_CONTENTS_CODE
;
285 src_s
->type
= MODIFY_LDT_CONTENTS_DATA
;
287 if (set_ldt_entry(src_idx
, (long) src_s
->base_addr
,
288 src_s
->length
- 1, 0, src_s
->type
, 0, 0) < 0)
293 return src_s
->selector
;
297 return IPCCopySelector(src_idx
, dst_idx
, 1);
300 SEGDESC
*src_s
, *dst_s
;
302 int src_idx
, dst_idx
;
306 src_idx
= (SelectorMap
[src_selector
>> 3]);
307 dst_idx
= dst_selector
>> 3;
308 src_s
= &Segments
[src_idx
];
309 dst_s
= &Segments
[dst_idx
];
312 for (i
= FIRST_SELECTOR
; i
< MAX_SELECTORS
; i
++)
313 if (SelectorMap
[i
] == src_idx
)
316 if (src_s
->type
== MODIFY_LDT_CONTENTS_DATA
317 || alias_count
> 1 || src_idx
== dst_idx
)
321 if (src_s
->type
== MODIFY_LDT_CONTENTS_DATA
)
322 dst_s
->type
= MODIFY_LDT_CONTENTS_CODE
;
324 dst_s
->type
= MODIFY_LDT_CONTENTS_DATA
;
326 SelectorMap
[dst_idx
] = SelectorMap
[src_idx
];
327 if (set_ldt_entry(dst_idx
, (long) dst_s
->base_addr
,
328 dst_s
->length
- 1, 0, dst_s
->type
, 0, 0) < 0)
336 * We're changing an unaliased code segment into a data
337 * segment. The SAFEST (but ugliest) way to deal with
338 * this is to map the new segment and copy all the contents.
340 SelectorMap
[dst_idx
] = dst_idx
;
342 dst_s
->selector
= (dst_idx
<< 3) | 0x0007;
343 dst_s
->base_addr
= (void *) ((unsigned int) dst_s
->selector
<< 16);
344 dst_s
->type
= MODIFY_LDT_CONTENTS_DATA
;
347 zfile
= fopen("/dev/zero","r");
348 p
= (void *) mmap((char *) dst_s
->base_addr
,
349 ((dst_s
->length
+ PAGE_SIZE
)
351 PROT_EXEC
| PROT_READ
| PROT_WRITE
,
352 MAP_FIXED
| MAP_PRIVATE
, fileno(zfile
), 0);
354 p
= (void *) mmap((char *) dst_s
->base_addr
,
355 ((dst_s
->length
+ PAGE_SIZE
)
357 PROT_EXEC
| PROT_READ
| PROT_WRITE
,
358 MAP_FIXED
| MAP_PRIVATE
| MAP_ANON
, -1, 0);
363 memcpy((void *) dst_s
->base_addr
, (void *) src_s
->base_addr
,
365 if (set_ldt_entry(src_idx
, dst_s
->base_addr
,
366 dst_s
->length
- 1, 0, dst_s
->type
, 0, 0) < 0)
370 if (set_ldt_entry(dst_idx
, dst_s
->base_addr
,
371 dst_s
->length
- 1, 0, dst_s
->type
, 0, 0) < 0)
376 munmap(src_s
->base_addr
,
377 (src_s
->length
+ PAGE_SIZE
) & ~(PAGE_SIZE
- 1));
378 SelectorMap
[src_idx
] = dst_idx
;
379 src_s
->base_addr
= dst_s
->base_addr
;
382 return dst_s
->selector
;
383 #endif /* HAVE_IPC */
386 /**********************************************************************
389 WORD
AllocDStoCSAlias(WORD ds_selector
)
391 unsigned int cs_selector
;
393 if (ds_selector
== 0)
396 cs_selector
= AllocSelector(0);
397 return PrestoChangoSelector(ds_selector
, cs_selector
);
400 /**********************************************************************
403 WORD
FreeSelector(WORD sel
)
413 if (sel_idx
< FIRST_SELECTOR
|| sel_idx
>= MAX_SELECTORS
)
416 s
= &Segments
[sel_idx
];
419 munmap(s
->base_addr
, ((s
->length
+ PAGE_SIZE
) & ~(PAGE_SIZE
- 1)));
420 memcpy(s
, 0, sizeof(*s
));
421 SelectorMap
[sel_idx
] = 0;
428 for (i
= FIRST_SELECTOR
; i
< MAX_SELECTORS
; i
++)
429 if (SelectorMap
[i
] && Segments
[i
].shm_key
== s
->shm_key
)
432 if (alias_count
== 1)
433 shmctl(s
->shm_key
, IPC_RMID
, NULL
);
435 memcpy(s
, 0, sizeof(*s
));
436 SelectorMap
[sel_idx
] = 0;
440 sel_idx
= SelectorMap
[sel
>> 3];
442 if (sel_idx
< FIRST_SELECTOR
|| sel_idx
>= MAX_SELECTORS
)
445 if (sel_idx
!= (sel
>> 3))
447 SelectorMap
[sel
>> 3] = 0;
452 for (i
= FIRST_SELECTOR
; i
< MAX_SELECTORS
; i
++)
453 if (SelectorMap
[i
] == sel_idx
)
456 if (alias_count
== 1)
458 s
= &Segments
[sel_idx
];
459 munmap(s
->base_addr
, ((s
->length
+ PAGE_SIZE
) & ~(PAGE_SIZE
- 1)));
460 memcpy(s
, 0, sizeof(*s
));
461 SelectorMap
[sel
>> 3] = 0;
463 #endif /* HAVE_IPC */
468 /**********************************************************************
472 CreateNewSegments(int code_flag
, int read_only
, int length
, int n_segments
)
474 SEGDESC
*s
, *first_segment
;
478 i
= FindUnusedSelectors(n_segments
);
480 #ifdef DEBUG_SELECTORS
482 "Using %d segments starting at index %d.\n", n_segments
, i
);
486 * Fill in selector info.
488 first_segment
= s
= &Segments
[i
];
489 for (last_i
= i
+ n_segments
; i
< last_i
; i
++, s
++)
493 contents
= MODIFY_LDT_CONTENTS_CODE
;
498 contents
= MODIFY_LDT_CONTENTS_DATA
;
499 s
->flags
= NE_SEGFLAGS_DATA
;
502 s
->selector
= (i
<< 3) | 0x0007;
506 zfile
= fopen("/dev/zero","r");
507 s
->base_addr
= (void *) mmap((char *) (s
->selector
<< 16),
508 ((s
->length
+ PAGE_SIZE
- 1) &
510 PROT_EXEC
| PROT_READ
| PROT_WRITE
,
511 MAP_FIXED
| MAP_PRIVATE
,
514 s
->base_addr
= (void *) mmap((char *) (s
->selector
<< 16),
515 ((s
->length
+ PAGE_SIZE
- 1) &
517 PROT_EXEC
| PROT_READ
| PROT_WRITE
,
518 MAP_FIXED
| MAP_PRIVATE
| MAP_ANON
,
522 if (set_ldt_entry(i
, (unsigned long) s
->base_addr
,
523 (s
->length
- 1) & 0xffff, 0,
524 contents
, read_only
, 0) < 0)
526 memset(s
, 0, sizeof(*s
));
530 SelectorMap
[i
] = (unsigned short) i
;
534 return first_segment
;
537 /**********************************************************************
541 GetNextSegment(unsigned int flags
, unsigned int limit
)
543 return CreateNewSegments(0, 0, limit
, 1);
546 /**********************************************************************
547 * GetEntryPointFromOrdinal
550 struct entry_tab_header_s
*eth
;
551 struct entry_tab_movable_s
*etm
;
552 struct entry_tab_fixed_s
*etf
;
556 unsigned int GetEntryDLLName(char * dll_name
, char * function
, int * sel
,
559 struct dll_table_entry_s
*dll_table
;
560 struct w_files
* wpnt
;
564 dll_table
= FindDLLTable(dll_name
);
567 ordinal
= FindOrdinalFromName(dll_table
, function
);
568 *sel
= dll_table
[ordinal
].selector
;
569 *addr
= (unsigned int) dll_table
[ordinal
].address
;
571 dll_table
[ordinal
].used
++;
576 /* We need a means of determining the ordinal for the function. */
577 /* Not a builtin symbol, look to see what the file has for us */
578 for(wpnt
= wine_files
; wpnt
; wpnt
= wpnt
->next
){
579 if(strcmp(wpnt
->name
, dll_name
)) continue;
580 cpnt
= wpnt
->nrname_table
;
582 if( ((int) cpnt
) - ((int)wpnt
->nrname_table
) >
583 wpnt
->ne_header
->nrname_tab_length
) return 1;
585 if(strncmp(cpnt
, function
, len
) == 0) break;
588 ordinal
= *((unsigned short *) (cpnt
+ len
));
589 j
= GetEntryPointFromOrdinal(wpnt
, ordinal
);
598 unsigned int GetEntryDLLOrdinal(char * dll_name
, int ordinal
, int * sel
,
601 struct dll_table_entry_s
*dll_table
;
602 struct w_files
* wpnt
;
605 dll_table
= FindDLLTable(dll_name
);
608 *sel
= dll_table
[ordinal
].selector
;
609 *addr
= (unsigned int) dll_table
[ordinal
].address
;
611 dll_table
[ordinal
].used
++;
616 /* Not a builtin symbol, look to see what the file has for us */
617 for(wpnt
= wine_files
; wpnt
; wpnt
= wpnt
->next
){
618 if(strcmp(wpnt
->name
, dll_name
)) continue;
619 j
= GetEntryPointFromOrdinal(wpnt
, ordinal
);
629 GetEntryPointFromOrdinal(struct w_files
* wpnt
, int ordinal
)
632 struct mz_header_s
*mz_header
= wpnt
->mz_header
;
633 struct ne_header_s
*ne_header
= wpnt
->ne_header
;
636 union lookup entry_tab_pointer
;
637 struct entry_tab_header_s
*eth
;
638 struct entry_tab_movable_s
*etm
;
639 struct entry_tab_fixed_s
*etf
;
644 entry_tab_pointer
.cpnt
= wpnt
->lookup_table
;
646 * Let's walk through the table until we get to our entry.
652 * Read header for this bundle.
654 eth
= entry_tab_pointer
.eth
++;
656 if (eth
->n_entries
== 0)
657 return 0xffffffff; /* Yikes - we went off the end of the table */
659 if (eth
->seg_number
== 0)
661 current_ordinal
+= eth
->n_entries
;
662 if(current_ordinal
> ordinal
) return 0;
667 * Read each of the bundle entries.
669 for (i
= 0; i
< eth
->n_entries
; i
++, current_ordinal
++)
671 if (eth
->seg_number
>= 0xfe)
673 etm
= entry_tab_pointer
.etm
++;
675 if (current_ordinal
== ordinal
)
677 return ((unsigned int)
678 (wpnt
->selector_table
[etm
->seg_number
- 1].base_addr
+
684 etf
= entry_tab_pointer
.etf
++;
686 if (current_ordinal
== ordinal
)
688 return ((unsigned int)
689 (wpnt
->selector_table
[eth
->seg_number
- 1].base_addr
+
690 (int) etf
->offset
[0] +
691 ((int) etf
->offset
[1] << 8)));
698 /**********************************************************************
701 LPSTR
GetDOSEnvironment(void)
703 return (LPSTR
) EnvironmentSelector
->base_addr
;
706 /**********************************************************************
710 CreateEnvironment(void)
715 s
= CreateNewSegments(0, 0, PAGE_SIZE
, 1);
720 * Fill environment with meaningless babble.
722 p
= (char *) s
->base_addr
;
723 strcpy(p
, "PATH=C:\\WINDOWS");
728 strcpy(p
, "C:\\TEST.EXE");
733 /**********************************************************************
739 struct dos_psp_s
*psp
;
745 s
= CreateNewSegments(0, 0, PAGE_SIZE
, 1);
750 PSPSelector
= s
->selector
;
751 psp
= (struct dos_psp_s
*) s
->base_addr
;
752 psp
->pspInt20
= 0x20cd;
753 psp
->pspDispatcher
[0] = 0x9a;
754 usp
= (unsigned short *) &psp
->pspDispatcher
[1];
755 *usp
= (unsigned short) KERNEL_Ordinal_102
;
756 *(usp
+ 1) = UTEXTSEL
;
757 psp
->pspTerminateVector
[0] = (unsigned short) UNIXLIB_Ordinal_0
;
758 psp
->pspTerminateVector
[1] = UTEXTSEL
;
759 psp
->pspControlCVector
[0] = (unsigned short) UNIXLIB_Ordinal_0
;
760 psp
->pspControlCVector
[1] = UTEXTSEL
;
761 psp
->pspCritErrorVector
[0] = (unsigned short) UNIXLIB_Ordinal_0
;
762 psp
->pspCritErrorVector
[1] = UTEXTSEL
;
763 psp
->pspEnvironment
= EnvironmentSelector
->selector
;
765 p1
= psp
->pspCommandTail
;
766 for (i
= 1; i
< Argc
; i
++)
768 if ((int) ((int) p1
- (int) psp
->pspCommandTail
) +
769 strlen(Argv
[i
]) > 124)
772 for (p2
= Argv
[i
]; *p2
!= '\0'; )
779 psp
->pspCommandTailCount
= strlen(psp
->pspCommandTail
);
784 /**********************************************************************
788 CreateSelectors(struct w_files
* wpnt
)
791 struct ne_segment_table_entry_s
*seg_table
= wpnt
->seg_table
;
792 struct ne_header_s
*ne_header
= wpnt
->ne_header
;
793 SEGDESC
*selectors
, *s
, *stmp
;
794 unsigned short auto_data_sel
;
795 int contents
, read_only
;
796 int SelectorTableLength
;
799 int old_length
, file_image_length
;
800 int saved_old_length
;
803 * Allocate memory for the table to keep track of all selectors.
805 SelectorTableLength
= ne_header
->n_segment_tab
;
806 selectors
= malloc(SelectorTableLength
* sizeof(*selectors
));
807 if (selectors
== NULL
)
811 * Step through the segment table in the exe header.
814 for (i
= 0; i
< ne_header
->n_segment_tab
; i
++, s
++)
817 * Store the flags in our table.
819 s
->flags
= seg_table
[i
].seg_flags
;
822 * Is there an image for this segment in the file?
824 if (seg_table
[i
].seg_data_offset
== 0)
827 * No image in exe file, let's allocate some memory for it.
829 s
->length
= seg_table
[i
].min_alloc
;
834 * Image in file, let's just point to the image in memory.
836 s
->length
= seg_table
[i
].min_alloc
;
837 file_image_length
= seg_table
[i
].seg_data_length
;
838 if (file_image_length
== 0) file_image_length
= 0x10000;
843 old_length
= s
->length
;
846 * If this is the automatic data segment, its size must be adjusted.
847 * First we need to check for local heap. Second we nee to see if
848 * this is also the stack segment.
850 if (i
+ 1 == ne_header
->auto_data_seg
)
852 s
->length
+= ne_header
->local_heap_length
;
854 if (i
+ 1 == ne_header
->ss
)
856 s
->length
+= ne_header
->stack_length
;
857 ne_header
->sp
= s
->length
;
862 * Is this a DATA or CODE segment?
865 if (s
->flags
& NE_SEGFLAGS_DATA
)
867 contents
= MODIFY_LDT_CONTENTS_DATA
;
868 if (s
->flags
& NE_SEGFLAGS_READONLY
)
873 contents
= MODIFY_LDT_CONTENTS_CODE
;
874 if (s
->flags
& NE_SEGFLAGS_EXECUTEONLY
)
878 stmp
= CreateNewSegments(!(s
->flags
& NE_SEGFLAGS_DATA
), read_only
,
880 s
->base_addr
= stmp
->base_addr
;
881 s
->selector
= stmp
->selector
;
883 if (seg_table
[i
].seg_data_offset
!= 0)
888 status
= lseek(fd
, seg_table
[i
].seg_data_offset
*
889 (1 << ne_header
->align_shift_count
), SEEK_SET
);
890 if(read(fd
, s
->base_addr
, file_image_length
) != file_image_length
)
891 myerror("Unable to read segment from file");
895 * If this is the automatic data segment, then we must initialize
898 if (i
+ 1 == ne_header
->auto_data_seg
)
900 auto_data_sel
= s
->selector
;
901 saved_old_length
= old_length
;
906 for (i
= 0; i
< ne_header
->n_segment_tab
; i
++, s
++)
908 Segments
[s
->selector
>> 3].owner
= auto_data_sel
;
909 if (s
->selector
== auto_data_sel
)
910 HEAP_LocalInit(auto_data_sel
, s
->base_addr
+ saved_old_length
,
911 ne_header
->local_heap_length
);
914 if(!EnvironmentSelector
) {
915 EnvironmentSelector
= CreateEnvironment();
916 PSP_Selector
= CreatePSP();
917 MakeProcThunks
= CreateNewSegments(1, 0, 0x10000, 1);
922 #endif /* ifndef WINELIB */