2 * ELKSEMU An emulator for Linux8086 binaries.
4 * VM86 is used to process all the 8086 mode code.
5 * We trap up to 386 mode for system call emulation and naughties.
10 #include <sys/types.h>
23 #define OLD_LIBC_VERSION
26 volatile struct vm86_struct elks_cpu
;
27 unsigned char *elks_base
; /* Paragraph aligned */
30 #define dbprintf(x) db_printf x
35 static void elks_init()
37 elks_cpu
.screen_bitmap
=0;
38 elks_cpu
.cpu_type
= CPU_286
;
40 * All INT xx calls are trapped.
42 memset((void *)&elks_cpu
.int_revectored
,0xFF, sizeof(elks_cpu
.int_revectored
));
45 static void elks_take_interrupt(int arg
)
48 if(arg
==0x20) { minix_syscall(); return; }
52 dbprintf(("Took an int %d\n", arg
));
54 kill(getpid(), SIGILL
);
58 dbprintf(("syscall AX=%x BX=%x CX=%x DX=%x\n",
59 (unsigned short)elks_cpu
.regs
.eax
,
60 (unsigned short)elks_cpu
.regs
.ebx
,
61 (unsigned short)elks_cpu
.regs
.ecx
,
62 (unsigned short)elks_cpu
.regs
.edx
));
64 elks_cpu
.regs
.eax
= elks_syscall();
65 dbprintf(("elks syscall returned %d\n", elks_cpu
.regs
.eax
));
66 /* Finally return to vm86 state */
70 static int load_elks(int fd
)
72 /* Load the elks binary image and set it up in a suitable VM86 segment. Load CS and DS/SS
73 according to image type. chmem is ignored we always use 64K segments */
74 struct elks_exec_hdr mh
;
76 if(read(fd
, &mh
,sizeof(mh
))!=sizeof(mh
))
78 if(mh
.hlen
!=EXEC_HEADER_SIZE
)
80 if(mh
.type
!=ELKS_COMBID
&&mh
.type
!=ELKS_SPLITID
)
83 fprintf(stderr
,"Linux-86 binary - %lX. tseg=%ld dseg=%ld bss=%ld\n",
84 mh
.type
,mh
.tseg
,mh
.dseg
,mh
.bseg
);
86 if(read(fd
,elks_base
,mh
.tseg
)!=mh
.tseg
)
88 if(mh
.type
==ELKS_COMBID
)
89 dsp
=elks_base
+mh
.tseg
;
92 if(read(fd
,dsp
,mh
.dseg
)!=mh
.dseg
)
94 memset(dsp
+mh
.dseg
,0, mh
.bseg
);
96 * Load the VM86 registers
99 if(mh
.type
==ELKS_COMBID
)
101 elks_cpu
.regs
.ds
=PARAGRAPH(dsp
);
102 elks_cpu
.regs
.es
=PARAGRAPH(dsp
);
103 elks_cpu
.regs
.ss
=PARAGRAPH(dsp
);
104 elks_cpu
.regs
.esp
=65536; /* Args stacked later */
105 elks_cpu
.regs
.cs
=PARAGRAPH(elks_base
);
106 elks_cpu
.regs
.eip
=0; /* Run from 0 */
109 * Loaded, check for sanity.
111 if( dsp
!= ELKS_PTR(unsigned char, 0) )
113 printf("Error VM86 problem %lx!=%lx (Is DS > 16 bits ?)\n",
114 (long)dsp
, (long)ELKS_PTR(char, 0));
121 #ifndef OLD_LIBC_VERSION
123 * recent versions of libc have changed the proto for vm86()
124 * for now I'll just override ...
126 #define OLD_SYS_vm86 113
127 #define NEW_SYS_vm86 166
129 static inline int vm86_mine(struct vm86_struct
* v86
)
132 __asm__
__volatile__("int $0x80\n"
133 :"=a" (__res
):"a" ((int)OLD_SYS_vm86
), "b" ((int)v86
));
141 * Execute 8086 code for a while.
143 #ifndef OLD_LIBC_VERSION
144 int err
=vm86_mine((struct vm86_struct
*)&elks_cpu
);
146 int err
=vm86((struct vm86_struct
*)&elks_cpu
);
148 switch(VM86_TYPE(err
))
151 * Signals are just re-starts of emulation (yes the
152 * handler might alter elks_cpu)
157 fprintf(stderr
, "VM86_UNKNOWN returned\n");
160 elks_take_interrupt(VM86_ARG(err
));
163 fprintf(stderr
, "VM86_STI returned\n");
164 break; /* Shouldnt be seen */
168 void build_stack(char ** argv
, char ** envp
)
171 int argv_len
=0, argv_count
=0;
172 int envp_len
=0, envp_count
=0;
174 unsigned short * pip
;
177 /* How much space for argv */
180 argv_count
++; argv_len
+= strlen(*p
)+1;
183 /* How much space for envp */
186 envp_count
++; envp_len
+= strlen(*p
)+1;
190 stack_bytes
= 2 /* argc */
191 + argv_count
* 2 + 2 /* argv */
193 + envp_count
* 2 + 2 /* envp */
197 elks_cpu
.regs
.esp
-= stack_bytes
;
200 printf("Argv = (%d,%d), Envp=(%d,%d), stack=%d\n",
201 argv_count, argv_len, envp_count, envp_len, stack_bytes);
204 /* Now copy in the strings */
205 pip
=ELKS_PTR(unsigned short, elks_cpu
.regs
.esp
);
206 pcp
=elks_cpu
.regs
.esp
+2*(1+argv_count
+1+envp_count
+1);
212 strcpy(ELKS_PTR(char, pcp
), *p
);
220 strcpy(ELKS_PTR(char, pcp
), *p
);
227 main(int argc
, char *argv
[], char *envp
[])
231 int ruid
, euid
, rgid
, egid
;
235 fprintf(stderr
,"elksemu cmd args.....\n");
238 /* This uses the _real_ user ID If the file is exec only that's */
239 /* ok cause the suid root will override. */
240 /* BTW, be careful here, security problems are possible because of
241 * races if you change this. */
243 if( access(argv
[1], X_OK
) < 0
244 || (fd
=open(argv
[1], O_RDONLY
)) < 0
245 || fstat(fd
, &st
) < 0
252 /* Check the suid bits ... */
253 ruid
= getuid(); rgid
= getgid();
254 euid
= ruid
; egid
= rgid
;
255 if( st
.st_mode
& S_ISUID
) euid
= st
.st_uid
;
256 if( st
.st_mode
& S_ISGID
) egid
= st
.st_gid
;
258 /* Set the _real_ permissions, or revoke superuser priviliages */
259 setregid(rgid
, egid
);
260 setreuid(ruid
, euid
);
262 dbprintf(("ELKSEMU\n"));
265 /* The Linux vm will deal with not allocating the unused pages */
268 /* GNU malloc will align to 4k with large chunks */
269 elks_base
= malloc(0x20000);
271 /* But others won't */
272 elks_base
= malloc(0x20000+4096);
273 elks_base
= (void*) (((int)elks_base
+4095) & -4096);
276 /* For ELF first 128M is unmapped, it needs to be mapped manually */
277 elks_base
= mmap((void*)0x10000, 0x20000,
278 PROT_EXEC
|PROT_READ
|PROT_WRITE
,
279 MAP_ANON
|MAP_PRIVATE
|MAP_FIXED
,
282 if( (long)elks_base
< 0 || (long)elks_base
>= 0xE0000 )
284 fprintf(stderr
, "Elks memory is at an illegal address\n");
288 if(load_elks(fd
) < 0)
290 fprintf(stderr
,"Not a elks binary.\n");
296 build_stack(argv
+1, envp
);
303 void db_printf(const char * fmt
, ...)
305 static FILE * db_fd
= 0;
310 db_fd
= fopen("/tmp/ELKS_log", "a");
311 if( db_fd
== 0 ) db_fd
= stderr
;
314 fprintf(db_fd
, "%d: ", getpid());
316 rv
= vfprintf(db_fd
,fmt
,ptr
);