root/morphix/trunk/ddcxinfo/bioscall.c

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

Initial import, branching from morphix svn

Line 
1 #include <sys/types.h>
2 #include <sys/io.h>
3 #include <sys/stat.h>
4 #include <sys/vm86.h>
5 #include <sys/syscall.h>
6 #include <sys/mman.h>
7 #include <ctype.h>
8 #include <stdio.h>
9 #include <fcntl.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <stdlib.h>
13 #include <signal.h>
14 #include <netinet/in.h>
15 #include "bioscall.h"
16 #ident "$Id: bioscall.c 1815 2005-04-25 08:27:54Z alextreme $"
17
18 #define DFLAG 0x0400
19 #define IFLAG 0x0200
20 #define TFLAG 0x0100
21 #define SFLAG 0x0080
22 #define ZFLAG 0x0040
23 #define AFLAG 0x0010
24 #define PFLAG 0x0004
25 #define CFLAG 0x0001
26
27 /* Dump some of the interesting parts of a register struct to stdout. */
28 void dump_regs(struct vm86_regs *regs)
29 {
30         printf("ax = 0x%04lx\n", regs->eax & 0xffff);
31         printf("bx = 0x%04lx\n", regs->ebx & 0xffff);
32         printf("cx = 0x%04lx\n", regs->ecx & 0xffff);
33         printf("dx = 0x%04lx\n", regs->edx & 0xffff);
34         printf("cs = 0x%04x\n", regs->cs  & 0xffff);
35         printf("ip = 0x%08lx\n", regs->eip & 0xffffffff);
36         printf("ss = 0x%04x\n", regs->ss  & 0xffff);
37         printf("sp = 0x%08lx\n", regs->esp & 0xffffffff);
38         printf("%04x:%08lx = (%ld)\n",
39                regs->cs & 0xffff, regs->eip,
40                regs->cs * 16 + regs->eip);
41 }
42
43 /* Call vm86, but do I/O that gets trapped. We could skip vm86() altogether,
44    but then I'm not trying to emulate an entire CPU here.  Luckily, none of
45    the I/O instructions (or push/pop) affect the flags, so we can leave them
46    alone and just deal with performing the I/O operation that caused a return
47    to 32-bit mode. */
48 void do_vm86(struct vm86_struct *vm, char *memory, unsigned stop_eip) {
49         int ret;
50         unsigned start_cs, start_eip;
51         unsigned char *ip = NULL;
52
53         /* Save the starting instruction address. */
54         start_cs = vm->regs.cs;
55         start_eip = vm->regs.eip;
56
57         /* We'll need to pass I/O through.  PCI devices have higher addresses
58            than we can get access to with ioperm(). */
59         if(iopl(3) != 0) {
60                 return;
61         }
62
63         /* Do it. */
64         ret = syscall(SYS_vm86old, vm);
65         while((vm->regs.cs * 16 + vm->regs.eip) != (start_cs * 16 + stop_eip)) {
66                 ip = &memory[vm->regs.cs * 16 + vm->regs.eip];
67 #ifdef DEBUG2
68                 printf("Unexpected return:\n");
69                 dump_regs(&vm->regs);
70                 printf("Offending instructions: %02x %02x %02x %02x\n",
71                        ip[0], ip[1], ip[2], ip[3]);
72 #endif
73                 switch(ip[0]) {
74                         case 0xe4: { /* in al, literal */
75                                 vm->regs.eax &= 0xffffff00;
76                                 vm->regs.eax |= inb(ip[1]);
77                                 vm->regs.eip += 2;
78                                 break;
79                         }
80                         case 0xe6: { /* out al, literal */
81                                 outb(vm->regs.eax & 0xff, ip[1]);
82                                 vm->regs.eip += 2;
83                                 break;
84                         }
85                         case 0xec: { /* in al, dx */
86                                 vm->regs.eax &= 0xffffff00;
87                                 vm->regs.eax |= inb(vm->regs.edx & 0xffff);
88                                 vm->regs.eip++;
89                                 break;
90                         }
91                         case 0xed: { /* in ax, dx */
92                                 vm->regs.eax &= 0xffff0000;
93                                 vm->regs.eax |= inw(vm->regs.edx & 0xffff);
94                                 vm->regs.eip++;
95                                 break;
96                         }
97                         case 0xee: { /* out al, dx */
98                                 outb(vm->regs.eax & 0xff,
99                                      vm->regs.edx & 0xffff);
100                                 vm->regs.eip++;
101                                 break;
102                         }
103                         case 0xef: { /* out ax, dx */
104                                 outw(vm->regs.eax & 0xffff,
105                                      vm->regs.edx & 0xffff);
106                                 vm->regs.eip++;
107                                 break;
108                         }
109                         case 0x6c: { /* insb */
110                                 unsigned char *result = (unsigned char*)
111                                         &memory[vm->regs.es*16 + vm->regs.edi];
112                                 *result = inb(vm->regs.edx & 0xffff);
113                                 if(vm->regs.eflags & DFLAG) {
114                                         vm->regs.edi -= 1;
115                                 } else {
116                                         vm->regs.edi += 1;
117                                 }
118                                 if(ip[-1] == 0xf3) { /* rep'ped */
119                                         vm->regs.ecx--;
120                                         vm->regs.eip--;
121                                 } else {
122                                         vm->regs.eip++;
123                                 }
124                                 break;
125                         }
126                         case 0x6d: { /* insw */
127                                 u_int16_t *result = (u_int16_t*)
128                                         &memory[vm->regs.es*16 + vm->regs.edi];
129                                 *result = inw(vm->regs.edx & 0xffff);
130                                 if(vm->regs.eflags & DFLAG) {
131                                         vm->regs.edi -= 2;
132                                 } else {
133                                         vm->regs.edi += 2;
134                                 }
135                                 if(ip[-1] == 0xf3) { /* rep'ped */
136                                         vm->regs.ecx--;
137                                         vm->regs.eip--;
138                                 } else {
139                                         vm->regs.eip++;
140                                 }
141                                 break;
142                         }
143                         case 0x6e: { /* outsb */
144                                 unsigned char *result = (unsigned char*)
145                                         &memory[vm->regs.es*16 + vm->regs.edi];
146                                 outb(*result,
147                                      vm->regs.edx & 0xffff);
148                                 if(vm->regs.eflags & DFLAG) {
149                                         vm->regs.edi -= 1;
150                                 } else {
151                                         vm->regs.edi += 1;
152                                 }
153                                 if(ip[-1] == 0xf3) { /* rep'ped */
154                                         vm->regs.ecx--;
155                                         vm->regs.eip--;
156                                 } else {
157                                         vm->regs.eip++;
158                                 }
159                                 break;
160                         }
161                         case 0x6f: { /* outsw */
162                                 u_int16_t *result = (u_int16_t*)
163                                         &memory[vm->regs.es*16 + vm->regs.edi];
164                                 outw(*result,
165                                      vm->regs.edx & 0xffff);
166                                 if(vm->regs.eflags & DFLAG) {
167                                         vm->regs.edi -= 2;
168                                 } else {
169                                         vm->regs.edi += 2;
170                                 }
171                                 if(ip[-1] == 0xf3) { /* rep'ped */
172                                         vm->regs.ecx--;
173                                         vm->regs.eip--;
174                                 } else {
175                                         vm->regs.eip++;
176                                 }
177                                 break;
178                         }
179                         case 0xfa: { /* cli */
180                                 vm->regs.eflags &= ~(IFLAG);
181                                 vm->regs.eip++;
182                                 break;
183                         }
184                         case 0xfb: { /* sti */
185                                 vm->regs.eflags |= ~(IFLAG);
186                                 vm->regs.eip++;
187                                 break;
188                         }
189                         case 0x9c: { /* pushf */
190                                 vm->regs.esp -= 2;
191                                 *(u_int16_t*) &memory[vm->regs.ss * 16 +
192                                                       vm->regs.esp]
193                                                     = vm->regs.eflags & 0xffff;
194                                 vm->regs.eip++;
195                                 break;
196                         }
197                         case 0x9d: { /* popf */
198                                 vm->regs.esp += 2;
199                                 vm->regs.eflags &= 0xffff0000;
200                                 vm->regs.eflags |=
201                                 *(u_int16_t*) &memory[vm->regs.ss * 16 +
202                                                       vm->regs.esp];
203                                 vm->regs.eip++;
204                                 break;
205                         }
206                         case 0xf0: { /* lock prefix */
207                                 /* ignore it */
208                                 vm->regs.eip++;
209                                 break;
210                         }
211                         case 0x66: {
212                                 /* 32-bit extension prefix.  Valid, even in
213                                    v86 mode.  Weird. */
214                                 vm->regs.eip++;
215                                 ip++;
216                                 switch(ip[0]) {
217                                         case 0xed: { /* in eax, dx */
218                                                 vm->regs.eax =
219                                                 inl(vm->regs.edx & 0xffff);
220                                                 vm->regs.eip++;
221                                                 break;
222                                         }
223                                         case 0xef: { /* out eax, dx */
224                                                 outl(vm->regs.eax,
225                                                      vm->regs.edx & 0xffff);
226                                                 vm->regs.eip++;
227                                                 break;
228                                         }
229                                         default: {
230                                                 fprintf(stderr, "unhandled "
231                                                         "32-bit opcode\n");
232                                                 exit(1);
233                                         }
234                                 }
235                                 break;
236                         }
237                         case 0x55: { /* push bp */
238                                 vm->regs.esp -= 2;
239                                 *(u_int16_t*) &memory[vm->regs.ss * 16 +
240                                                       vm->regs.esp]
241                                                     = vm->regs.ebp & 0xffff;
242                                 vm->regs.eip++;
243                                 break;
244                         }
245                         case 0x5d: { /* pop bp */
246                                 vm->regs.ebp &= 0xffff0000;
247                                 vm->regs.ebp |= *(u_int16_t*)
248                                         &memory[vm->regs.ss*16 + vm->regs.esp];
249                                 vm->regs.esp += 2;
250                                 vm->regs.eip++;
251                                 break;
252                         }
253                         case 0x59: { /* pop cx -- Banshee */
254                                 vm->regs.ecx &= 0xffff0000;
255                                 vm->regs.ecx |= *(u_int16_t*)
256                                         &memory[vm->regs.ss*16 + vm->regs.esp];
257                                 vm->regs.esp += 2;
258                                 vm->regs.eip++;
259                         }
260                         case 0xc3: { /* ret near, just pop ip */
261                                 vm->regs.eip &= 0xffff0000;
262                                 vm->regs.eip |= *(u_int16_t*)
263                                         &memory[vm->regs.ss*16 + vm->regs.esp];
264                                 vm->regs.esp += 2;
265                                 break;
266                         }
267                         case 0xcb: { /* ret far, pop both ip and cs */
268                                 vm->regs.eip &= 0xffff0000;
269                                 vm->regs.eip |= *(u_int16_t*)
270                                         &memory[vm->regs.ss*16 + vm->regs.esp];
271                                 vm->regs.esp += 2;
272                                 vm->regs.cs = *(u_int16_t*)
273                                         &memory[vm->regs.ss*16 + vm->regs.esp];
274                                 vm->regs.esp += 2;
275                                 break;
276                         }
277                         default: {
278                                 fprintf(stderr, "Unexpected stop!\n");
279                                 dump_regs(&vm->regs);
280                                 printf("Offending instructions: %02x %02x %02x %02x\n",
281                                        ip[0], ip[1], ip[2], ip[3]);
282                                 exit(1);
283                         }
284                 }
285                 ip = &memory[vm->regs.cs * 16 + vm->regs.eip];
286 #ifdef DEBUG
287                 printf("Resuming execution:\n");
288                 dump_regs(&vm->regs);
289                 printf("Offending instructions: %02x %02x %02x %02x\n",
290                        ip[0], ip[1], ip[2], ip[3]);
291 #endif
292                 ret = syscall(SYS_vm86old, vm);
293         }
294 #ifdef DEBUG
295         printf("Reached stopping point, returning.\n");
296 #endif
297         return;
298 }
299
300 /* Get a snapshot of the first megabyte of memory for use with vm86. */
301 unsigned char *vm86_ram_alloc()
302 {
303         unsigned char *memory;
304         int fd;
305
306         /* Grab address 0 for this process.  mmap() 1 megabyte + 64k HMA */
307         memory = mmap(0, 0x110000, PROT_READ | PROT_EXEC | PROT_WRITE,
308                       MAP_PRIVATE | MAP_FIXED | MAP_ANON, -1, 0x00000);
309         if(memory == MAP_FAILED) {
310                 perror("error mmap()ing memory for the BIOS");
311                 return MAP_FAILED;
312         }
313
314         /* Copy the low megabyte to our mmap()'ed buffer. */
315         fd = open("/dev/mem", O_RDONLY);
316         if(fd == -1) {
317                 perror("reading kernel memory");
318                 return MAP_FAILED;
319         }
320         // read(fd, memory, 0x110000);
321         lseek(fd, 0, SEEK_SET);
322         read(fd, &memory[0], 0x10000);
323         lseek(fd, 0xa0000, SEEK_SET);
324         read(fd, &memory[0xa0000], 0x50000);
325         close(fd);
326
327         return memory;
328 }
329
330 void vm86_ram_free(unsigned char *ram)
331 {
332         munmap(ram, 0x110000);
333 }
334
335 void bioscall(unsigned char int_no, struct vm86_regs *regs, unsigned char *mem)
336 {
337         unsigned char call[] = {0xcd, int_no, 0xcd, 0x09};
338         struct vm86_struct vm;
339         memset(&vm, 0, sizeof(vm));
340         memcpy(&vm.regs, regs, sizeof(vm.regs));
341         vm.regs.cs  = BIOSCALL_START_SEG;
342         vm.regs.eip = BIOSCALL_START_OFS;
343         vm.regs.ss  = BIOSCALL_START_SEG;
344         vm.regs.esp = 0xfff0 - BIOSCALL_START_OFS;
345         vm.regs.eflags = VM_MASK | IOPL_MASK;
346         memcpy(&mem[BIOSCALL_START_SEG * 16 + BIOSCALL_START_OFS], call,
347                sizeof(call));
348         do_vm86(&vm, mem, BIOSCALL_START_OFS + sizeof(call));
349         memcpy(regs, &vm.regs, sizeof(vm.regs));
350 }
Note: See TracBrowser for help on using the browser.