root/morphix/trunk/ddcxinfo/lrmi.c

Revision 2, 17.0 kB (checked in by nextime, 2 years ago)

Initial import, branching from morphix svn

Line 
1 /*
2 Linux Real Mode Interface - A library of DPMI-like functions for Linux.
3
4 Copyright (C) 1998 by Josh Vanderhoof
5
6 You are free to distribute and modify this file, as long as you
7 do not remove this copyright notice and clearly label modified
8 versions as being modified.
9
10 This software has NO WARRANTY.  Use it at your own risk.
11 */
12
13 #include <signal.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <sys/io.h>
17 #include <asm/vm86.h>
18
19 #ifdef USE_LIBC_VM86
20 #include <sys/vm86.h>
21 #endif
22
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <sys/mman.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28
29 #include "lrmi.h"
30
31 #define REAL_MEM_BASE   ((void *)0x10000)
32 #define REAL_MEM_SIZE   0x10000
33 #define REAL_MEM_BLOCKS         0x100
34
35 struct mem_block
36         {
37         unsigned int size : 20;
38         unsigned int free : 1;
39         };
40
41 static struct
42         {
43         int ready;
44         int count;
45         struct mem_block blocks[REAL_MEM_BLOCKS];
46         } mem_info = { 0 };
47
48 static int
49 real_mem_init(void)
50         {
51         void *m;
52         int fd_zero;
53
54         if (mem_info.ready)
55                 return 1;
56
57         fd_zero = open("/dev/zero", O_RDONLY);
58         if (fd_zero == -1)
59                 {
60                 perror("open /dev/zero");
61                 return 0;
62                 }
63
64         m = mmap((void *)REAL_MEM_BASE, REAL_MEM_SIZE,
65          PROT_READ | PROT_WRITE | PROT_EXEC,
66          MAP_FIXED | MAP_PRIVATE, fd_zero, 0);
67
68         if (m == (void *)-1)
69                 {
70                 perror("mmap /dev/zero");
71                 close(fd_zero);
72                 return 0;
73                 }
74
75         mem_info.ready = 1;
76         mem_info.count = 1;
77         mem_info.blocks[0].size = REAL_MEM_SIZE;
78         mem_info.blocks[0].free = 1;
79
80         return 1;
81         }
82
83
84 static void
85 insert_block(int i)
86         {
87         memmove(
88          mem_info.blocks + i + 1,
89          mem_info.blocks + i,
90          (mem_info.count - i) * sizeof(struct mem_block));
91
92         mem_info.count++;
93         }
94
95 static void
96 delete_block(int i)
97         {
98         mem_info.count--;
99
100         memmove(
101          mem_info.blocks + i,
102          mem_info.blocks + i + 1,
103          (mem_info.count - i) * sizeof(struct mem_block));
104         }
105
106 void *
107 LRMI_alloc_real(int size)
108         {
109         int i;
110         char *r = (char *)REAL_MEM_BASE;
111
112         if (!mem_info.ready)
113                 return NULL;
114
115         if (mem_info.count == REAL_MEM_BLOCKS)
116                 return NULL;
117
118         size = (size + 15) & ~15;
119
120         for (i = 0; i < mem_info.count; i++)
121                 {
122                 if (mem_info.blocks[i].free && size < mem_info.blocks[i].size)
123                         {
124                         insert_block(i);
125
126                         mem_info.blocks[i].size = size;
127                         mem_info.blocks[i].free = 0;
128                         mem_info.blocks[i + 1].size -= size;
129
130                         return (void *)r;
131                         }
132
133                 r += mem_info.blocks[i].size;
134                 }
135
136         return NULL;
137         }
138
139
140 void
141 LRMI_free_real(void *m)
142         {
143         int i;
144         char *r = (char *)REAL_MEM_BASE;
145
146         if (!mem_info.ready)
147                 return;
148
149         i = 0;
150         while (m != (void *)r)
151                 {
152                 r += mem_info.blocks[i].size;
153                 i++;
154                 if (i == mem_info.count)
155                         return;
156                 }
157
158         mem_info.blocks[i].free = 1;
159
160         if (i + 1 < mem_info.count && mem_info.blocks[i + 1].free)
161                 {
162                 mem_info.blocks[i].size += mem_info.blocks[i + 1].size;
163                 delete_block(i + 1);
164                 }
165
166         if (i - 1 >= 0 && mem_info.blocks[i - 1].free)
167                 {
168                 mem_info.blocks[i - 1].size += mem_info.blocks[i].size;
169                 delete_block(i);
170                 }
171         }
172
173
174 #define DEFAULT_VM86_FLAGS      (IF_MASK | IOPL_MASK)
175 #define DEFAULT_STACK_SIZE      0x1000
176 #define RETURN_TO_32_INT        255
177
178 static struct
179         {
180         int ready;
181         unsigned short ret_seg, ret_off;
182         unsigned short stack_seg, stack_off;
183         struct vm86_struct vm;
184         } context = { 0 };
185
186
187 static inline void
188 set_bit(unsigned int bit, void *array)
189         {
190         unsigned char *a = array;
191
192         a[bit / 8] |= (1 << (bit % 8));
193         }
194
195
196 static inline unsigned int
197 get_int_seg(int i)
198         {
199         return *(unsigned short *)(i * 4 + 2);
200         }
201
202
203 static inline unsigned int
204 get_int_off(int i)
205         {
206         return *(unsigned short *)(i * 4);
207         }
208
209
210 static inline void
211 pushw(unsigned short i)
212         {
213         struct vm86_regs *r = &context.vm.regs;
214         r->esp -= 2;
215         *(unsigned short *)(((unsigned int)r->ss << 4) + r->esp) = i;
216         }
217
218
219 int
220 LRMI_init(void)
221         {
222         void *m;
223         int fd_mem;
224
225         if (context.ready)
226                 return 1;
227
228         if (!real_mem_init())
229                 return 0;
230
231         /*
232          Map the Interrupt Vectors (0x0 - 0x400) + BIOS data (0x400 - 0x502)
233          and the ROM (0xa0000 - 0x100000)
234         */
235         fd_mem = open("/dev/mem", O_RDWR);
236
237         if (fd_mem == -1)
238                 {
239                 perror("open /dev/mem");
240                 return 0;
241                 }
242
243         m = mmap((void *)0, 0x502,
244          PROT_READ | PROT_WRITE | PROT_EXEC,
245          MAP_FIXED | MAP_PRIVATE, fd_mem, 0);
246
247         if (m == (void *)-1)
248                 {
249                 perror("mmap /dev/mem");
250                 return 0;
251                 }
252
253         m = mmap((void *)0xa0000, 0x100000 - 0xa0000,
254          PROT_READ | PROT_WRITE,
255          MAP_FIXED | MAP_SHARED, fd_mem, 0xa0000);
256
257         if (m == (void *)-1)
258                 {
259                 perror("mmap /dev/mem");
260                 return 0;
261                 }
262
263
264         /*
265          Allocate a stack
266         */
267         m = LRMI_alloc_real(DEFAULT_STACK_SIZE);
268
269         context.stack_seg = (unsigned int)m >> 4;
270         context.stack_off = DEFAULT_STACK_SIZE;
271
272         /*
273          Allocate the return to 32 bit routine
274         */
275         m = LRMI_alloc_real(2);
276
277         context.ret_seg = (unsigned int)m >> 4;
278         context.ret_off = (unsigned int)m & 0xf;
279
280         ((unsigned char *)m)[0] = 0xcd;         /* int opcode */
281         ((unsigned char *)m)[1] = RETURN_TO_32_INT;
282
283         memset(&context.vm, 0, sizeof(context.vm));
284
285         /*
286          Enable kernel emulation of all ints except RETURN_TO_32_INT
287         */
288         memset(&context.vm.int_revectored, 0, sizeof(context.vm.int_revectored));
289         set_bit(RETURN_TO_32_INT, &context.vm.int_revectored);
290
291         context.ready = 1;
292
293         return 1;
294         }
295
296
297 static void
298 set_regs(struct LRMI_regs *r)
299         {
300         context.vm.regs.edi = r->edi;
301         context.vm.regs.esi = r->esi;
302         context.vm.regs.ebp = r->ebp;
303         context.vm.regs.ebx = r->ebx;
304         context.vm.regs.edx = r->edx;
305         context.vm.regs.ecx = r->ecx;
306         context.vm.regs.eax = r->eax;
307         context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
308         context.vm.regs.es = r->es;
309         context.vm.regs.ds = r->ds;
310         context.vm.regs.fs = r->fs;
311         context.vm.regs.gs = r->gs;
312         }
313
314
315 static void
316 get_regs(struct LRMI_regs *r)
317         {
318         r->edi = context.vm.regs.edi;
319         r->esi = context.vm.regs.esi;
320         r->ebp = context.vm.regs.ebp;
321         r->ebx = context.vm.regs.ebx;
322         r->edx = context.vm.regs.edx;
323         r->ecx = context.vm.regs.ecx;
324         r->eax = context.vm.regs.eax;
325         r->flags = context.vm.regs.eflags;
326         r->es = context.vm.regs.es;
327         r->ds = context.vm.regs.ds;
328         r->fs = context.vm.regs.fs;
329         r->gs = context.vm.regs.gs;
330         }
331
332 #define DIRECTION_FLAG  (1 << 10)
333
334 static void
335 em_ins(int size)
336         {
337         unsigned int edx, edi;
338
339         edx = context.vm.regs.edx & 0xffff;
340         edi = context.vm.regs.edi & 0xffff;
341         edi += (unsigned int)context.vm.regs.ds << 4;
342
343         if (context.vm.regs.eflags & DIRECTION_FLAG)
344                 {
345                 if (size == 4)
346                         asm volatile ("std; insl; cld"
347                          : "=D" (edi) : "d" (edx), "0" (edi));
348                 else if (size == 2)
349                         asm volatile ("std; insw; cld"
350                          : "=D" (edi) : "d" (edx), "0" (edi));
351                 else
352                         asm volatile ("std; insb; cld"
353                          : "=D" (edi) : "d" (edx), "0" (edi));
354                 }
355         else
356                 {
357                 if (size == 4)
358                         asm volatile ("cld; insl"
359                          : "=D" (edi) : "d" (edx), "0" (edi));
360                 else if (size == 2)
361                         asm volatile ("cld; insw"
362                          : "=D" (edi) : "d" (edx), "0" (edi));
363                 else
364                         asm volatile ("cld; insb"
365                          : "=D" (edi) : "d" (edx), "0" (edi));
366                 }
367
368         edi -= (unsigned int)context.vm.regs.ds << 4;
369
370         context.vm.regs.edi &= 0xffff0000;
371         context.vm.regs.edi |= edi & 0xffff;
372         }
373
374 static void
375 em_rep_ins(int size)
376         {
377         unsigned int ecx, edx, edi;
378
379         ecx = context.vm.regs.ecx & 0xffff;
380         edx = context.vm.regs.edx & 0xffff;
381         edi = context.vm.regs.edi & 0xffff;
382         edi += (unsigned int)context.vm.regs.ds << 4;
383
384         if (context.vm.regs.eflags & DIRECTION_FLAG)
385                 {
386                 if (size == 4)
387                         asm volatile ("std; rep; insl; cld"
388                          : "=D" (edi), "=c" (ecx)
389                          : "d" (edx), "0" (edi), "1" (ecx));
390                 else if (size == 2)
391                         asm volatile ("std; rep; insw; cld"
392                          : "=D" (edi), "=c" (ecx)
393                          : "d" (edx), "0" (edi), "1" (ecx));
394                 else
395                         asm volatile ("std; rep; insb; cld"
396                          : "=D" (edi), "=c" (ecx)
397                          : "d" (edx), "0" (edi), "1" (ecx));
398                 }
399         else
400                 {
401                 if (size == 4)
402                         asm volatile ("cld; rep; insl"
403                          : "=D" (edi), "=c" (ecx)
404                          : "d" (edx), "0" (edi), "1" (ecx));
405                 else if (size == 2)
406                         asm volatile ("cld; rep; insw"
407                          : "=D" (edi), "=c" (ecx)
408                          : "d" (edx), "0" (edi), "1" (ecx));
409                 else
410                         asm volatile ("cld; rep; insb"
411                          : "=D" (edi), "=c" (ecx)
412                          : "d" (edx), "0" (edi), "1" (ecx));
413                 }
414
415         edi -= (unsigned int)context.vm.regs.ds << 4;
416
417         context.vm.regs.edi &= 0xffff0000;
418         context.vm.regs.edi |= edi & 0xffff;
419
420         context.vm.regs.ecx &= 0xffff0000;
421         context.vm.regs.ecx |= ecx & 0xffff;
422         }
423
424 static void
425 em_outs(int size)
426         {
427         unsigned int edx, esi;
428
429         edx = context.vm.regs.edx & 0xffff;
430         esi = context.vm.regs.esi & 0xffff;
431         esi += (unsigned int)context.vm.regs.ds << 4;
432
433         if (context.vm.regs.eflags & DIRECTION_FLAG)
434                 {
435                 if (size == 4)
436                         asm volatile ("std; outsl; cld"
437                          : "=S" (esi) : "d" (edx), "0" (esi));
438                 else if (size == 2)
439                         asm volatile ("std; outsw; cld"
440                          : "=S" (esi) : "d" (edx), "0" (esi));
441                 else
442                         asm volatile ("std; outsb; cld"
443                          : "=S" (esi) : "d" (edx), "0" (esi));
444                 }
445         else
446                 {
447                 if (size == 4)
448                         asm volatile ("cld; outsl"
449                          : "=S" (esi) : "d" (edx), "0" (esi));
450                 else if (size == 2)
451                         asm volatile ("cld; outsw"
452                          : "=S" (esi) : "d" (edx), "0" (esi));
453                 else
454                         asm volatile ("cld; outsb"
455                          : "=S" (esi) : "d" (edx), "0" (esi));
456                 }
457
458         esi -= (unsigned int)context.vm.regs.ds << 4;
459
460         context.vm.regs.esi &= 0xffff0000;
461         context.vm.regs.esi |= esi & 0xffff;
462         }
463
464 static void
465 em_rep_outs(int size)
466         {
467         unsigned int ecx, edx, esi;
468
469         ecx = context.vm.regs.ecx & 0xffff;
470         edx = context.vm.regs.edx & 0xffff;
471         esi = context.vm.regs.esi & 0xffff;
472         esi += (unsigned int)context.vm.regs.ds << 4;
473
474         if (context.vm.regs.eflags & DIRECTION_FLAG)
475                 {
476                 if (size == 4)
477                         asm volatile ("std; rep; outsl; cld"
478                          : "=S" (esi), "=c" (ecx)
479                          : "d" (edx), "0" (esi), "1" (ecx));
480                 else if (size == 2)
481                         asm volatile ("std; rep; outsw; cld"
482                          : "=S" (esi), "=c" (ecx