Release 0.0.2
[wine] / selector.c
1 /* $Id: exedump.c,v 1.1 1993/06/09 03:28:10 root Exp root $
2  */
3 /*
4  * Copyright  Robert J. Amstadt, 1993
5  */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12 #include <unistd.h>
13 #include <linux/unistd.h>
14 #include <linux/head.h>
15 #include <linux/mman.h>
16 #include <linux/a.out.h>
17 #include <linux/ldt.h>
18 #include <errno.h>
19 #include "neexe.h"
20 #include "segmem.h"
21 #include "prototypes.h"
22
23 struct segment_descriptor_s *SelectorTable;
24 int SelectorTableLength;
25 int EnvironmentSelectorIdx;
26 int PSPSelectorIdx;
27 unsigned short PSPSelector;
28
29 extern void KERNEL_Ordinal_102();
30 extern void UNIXLIB_Ordinal_0();
31
32 \f
33 /**********************************************************************
34  *                                      GetDOSEnvironment
35  */
36 void *
37 GetDOSEnvironment()
38 {
39     return SelectorTable[EnvironmentSelectorIdx].base_addr;
40 }
41 \f
42 /**********************************************************************
43  *                                      CreateEnvironment
44  */
45 void
46 CreateEnvironment(int sel_idx, struct segment_descriptor_s *s, FILE *zfile)
47 {
48     char *p;
49
50     EnvironmentSelectorIdx = sel_idx;
51
52     /*
53      * Create memory to hold environment.
54      */
55     s->flags = NE_SEGFLAGS_DATA;
56     s->selector = (sel_idx << 3) | 0x0007;
57     s->length = PAGE_SIZE;
58     s->base_addr = (void *) mmap((char *) (s->selector << 16),
59                                  PAGE_SIZE,
60                                  PROT_EXEC | PROT_READ | PROT_WRITE,
61                                  MAP_FIXED | MAP_PRIVATE, fileno(zfile), 0);
62
63     /*
64      * Fill environment with meaningless babble.
65      */
66     p = (char *) s->base_addr;
67     strcpy(p, "PATH=C:\\WINDOWS");
68     p += strlen(p) + 1;
69     *p++ = '\0';
70     *p++ = 11;
71     *p++ = 0;
72     strcpy(p, "C:\\TEST.EXE");
73
74     /*
75      * Create entry in LDT for this segment.
76      */
77     if (set_ldt_entry(sel_idx, (unsigned long) s->base_addr, s->length, 0, 
78                       MODIFY_LDT_CONTENTS_DATA, 0, 0) < 0)
79     {
80         myerror("Could not create LDT entry for environment");
81     }
82 }
83 \f
84 /**********************************************************************
85  *                                      CreatePSP
86  */
87 void
88 CreatePSP(int sel_idx, struct segment_descriptor_s *s, FILE *zfile)
89 {
90     struct dos_psp_s *psp;
91     unsigned short *usp;
92     
93     PSPSelectorIdx = sel_idx;
94
95     /*
96      * Create memory to hold PSP.
97      */
98     s->flags = NE_SEGFLAGS_DATA;
99     s->selector = (sel_idx << 3) | 0x0007;
100     s->length = PAGE_SIZE;
101     s->base_addr = (void *) mmap((char *) (s->selector << 16),
102                                  PAGE_SIZE,
103                                  PROT_EXEC | PROT_READ | PROT_WRITE,
104                                  MAP_FIXED | MAP_PRIVATE, fileno(zfile), 0);
105
106     /*
107      * Fill PSP
108      */
109     PSPSelector = s->selector;
110     psp = (struct dos_psp_s *) s->base_addr;
111     psp->pspInt20 = 0x20cd;
112     psp->pspDispatcher[0] = 0x9a;
113     usp = (unsigned short *) &psp->pspDispatcher[1];
114     *usp       = (unsigned short) KERNEL_Ordinal_102;
115     *(usp + 1) = 0x23;
116     psp->pspTerminateVector = 0x00230000 | ((int) UNIXLIB_Ordinal_0 & 0xffff);
117     psp->pspControlCVector = 0x00230000 | ((int) UNIXLIB_Ordinal_0 & 0xffff);
118     psp->pspCritErrorVector = 0x00230000 | ((int) UNIXLIB_Ordinal_0 & 0xffff);
119     psp->pspEnvironment = SelectorTable[EnvironmentSelectorIdx].selector;
120     psp->pspCommandTailCount = 1;
121     strcpy(psp->pspCommandTail, "\r");
122     
123
124     /*
125      * Create entry in LDT for this segment.
126      */
127     if (set_ldt_entry(sel_idx, (unsigned long) s->base_addr, s->length, 0, 
128                       MODIFY_LDT_CONTENTS_DATA, 0, 0) < 0)
129     {
130         myerror("Could not create LDT entry for PSP");
131     }
132 }
133 \f
134 /**********************************************************************
135  *                                      CreateSelectors
136  */
137 struct segment_descriptor_s *
138 CreateSelectors(int fd, struct ne_segment_table_entry_s *seg_table,
139                 struct ne_header_s *ne_header)
140 {
141     struct segment_descriptor_s *selectors, *s;
142     int contents, read_only;
143     int i;
144     int status;
145     FILE * zfile;
146     int old_length;
147
148     /*
149      * Allocate memory for the table to keep track of all selectors.
150      */
151     SelectorTableLength = ne_header->n_segment_tab + 2;
152     selectors = malloc(SelectorTableLength * sizeof(*selectors));
153     if (selectors == NULL)
154         return NULL;
155     SelectorTable = selectors;
156
157     /*
158      * Step through the segment table in the exe header.
159      */
160     s = selectors;
161     zfile = fopen("/dev/zero","r");
162     for (i = 0; i < ne_header->n_segment_tab; i++, s++)
163     {
164         /*
165          * Store the flags in our table.
166          */
167         s->flags = seg_table[i].seg_flags;
168         s->selector = (i << 3) | 0x0007;
169
170         /*
171          * Is there an image for this segment in the file?
172          */
173         if (seg_table[i].seg_data_offset == 0)
174         {
175             /*
176              * No image in exe file, let's allocate some memory for it.
177              */
178             s->length = seg_table[i].min_alloc;
179         }
180         else
181         {
182             /*
183              * Image in file, let's just point to the image in memory.
184              */
185             s->length    = seg_table[i].seg_data_length;
186         }
187
188         if (s->length == 0)
189             s->length = 0x10000;
190         old_length = s->length;
191
192         /*
193          * If this is the automatic data segment, its size must be adjusted.
194          * First we need to check for local heap.  Second we nee to see if
195          * this is also the stack segment.
196          */
197         if (i + 1 == ne_header->auto_data_seg)
198         {
199             s->length += ne_header->local_heap_length;
200
201             if (i + 1 == ne_header->ss)
202             {
203                 s->length += ne_header->stack_length;
204                 ne_header->sp = s->length;
205             }
206         }
207
208         /*
209          * Is this a DATA or CODE segment?
210          */
211         read_only = 0;
212         if (s->flags & NE_SEGFLAGS_DATA)
213         {
214             contents = MODIFY_LDT_CONTENTS_DATA;
215             if (s->flags & NE_SEGFLAGS_READONLY)
216                 read_only = 1;
217         }
218         else
219         {
220             contents = MODIFY_LDT_CONTENTS_CODE;
221             if (s->flags & NE_SEGFLAGS_EXECUTEONLY)
222                 read_only = 1;
223         }
224         s->base_addr =
225           (void *) mmap((char *) (s->selector << 16),
226                         (s->length + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1),
227                         PROT_EXEC | PROT_READ | PROT_WRITE,
228                         MAP_FIXED | MAP_PRIVATE, fileno(zfile), 0);
229         if (seg_table[i].seg_data_offset != 0)
230         {
231             /*
232              * Image in file.
233              */
234             status = lseek(fd, seg_table[i].seg_data_offset * 512, SEEK_SET);
235             if(read(fd, s->base_addr, old_length) != old_length)
236               myerror("Unable to read segment from file");
237         }
238         /*
239          * Create entry in LDT for this segment.
240          */
241         if (set_ldt_entry(i, (unsigned long) s->base_addr, s->length, 0, 
242                           contents, read_only, 0) < 0)
243         {
244             free(selectors);
245             return NULL;
246         }
247         /*
248          * If this is the automatic data segment, then we must initialize
249          * the local heap.
250          */
251         if (i + 1 == ne_header->auto_data_seg)
252         {
253             HEAP_LocalInit(s->base_addr + old_length, 
254                            ne_header->local_heap_length);
255         }
256     }
257
258     CreateEnvironment(i++, s++, zfile);
259     CreatePSP(i++, s++, zfile);
260
261     fclose(zfile);
262
263     return selectors;
264 }