VirtualBox

source: vbox/trunk/src/recompiler/tests/qruncom.c@ 16680

Last change on this file since 16680 was 2426, checked in by vboxsync, 18 years ago

Removed the old recompiler code. (wonder why subversion didn't pick up these changes right way)

  • Property svn:eol-style set to native
File size: 8.2 KB
Line 
1/*
2 * Example of use of user mode libqemu: launch a basic .com DOS
3 * executable
4 */
5#include <stdlib.h>
6#include <stdio.h>
7#include <string.h>
8#include <inttypes.h>
9#include <unistd.h>
10#include <fcntl.h>
11#include <sys/mman.h>
12#include <signal.h>
13#include <malloc.h>
14
15#include "cpu.h"
16
17//#define SIGTEST
18
19void cpu_outb(CPUState *env, int addr, int val)
20{
21 fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val);
22}
23
24void cpu_outw(CPUState *env, int addr, int val)
25{
26 fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val);
27}
28
29void cpu_outl(CPUState *env, int addr, int val)
30{
31 fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val);
32}
33
34int cpu_inb(CPUState *env, int addr)
35{
36 fprintf(stderr, "inb: port=0x%04x\n", addr);
37 return 0;
38}
39
40int cpu_inw(CPUState *env, int addr)
41{
42 fprintf(stderr, "inw: port=0x%04x\n", addr);
43 return 0;
44}
45
46int cpu_inl(CPUState *env, int addr)
47{
48 fprintf(stderr, "inl: port=0x%04x\n", addr);
49 return 0;
50}
51
52int cpu_get_pic_interrupt(CPUState *env)
53{
54 return -1;
55}
56
57uint64_t cpu_get_tsc(CPUState *env)
58{
59 return 0;
60}
61
62static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
63 unsigned long addr, unsigned int sel)
64{
65 unsigned int e1, e2;
66 e1 = (addr & 0xffff) | (sel << 16);
67 e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
68 stl((uint8_t *)ptr, e1);
69 stl((uint8_t *)ptr + 4, e2);
70}
71
72uint64_t idt_table[256];
73
74/* only dpl matters as we do only user space emulation */
75static void set_idt(int n, unsigned int dpl)
76{
77 set_gate(idt_table + n, 0, dpl, 0, 0);
78}
79
80void qemu_free(void *ptr)
81{
82 free(ptr);
83}
84
85void *qemu_malloc(size_t size)
86{
87 return malloc(size);
88}
89
90void *qemu_mallocz(size_t size)
91{
92 void *ptr;
93 ptr = qemu_malloc(size);
94 if (!ptr)
95 return NULL;
96 memset(ptr, 0, size);
97 return ptr;
98}
99
100void *qemu_vmalloc(size_t size)
101{
102 return memalign(4096, size);
103}
104
105void qemu_vfree(void *ptr)
106{
107 free(ptr);
108}
109
110void qemu_printf(const char *fmt, ...)
111{
112 va_list ap;
113 va_start(ap, fmt);
114 vprintf(fmt, ap);
115 va_end(ap);
116}
117
118/* XXX: this is a bug in helper2.c */
119int errno;
120
121/**********************************************/
122
123#define COM_BASE_ADDR 0x10100
124
125void usage(void)
126{
127 printf("qruncom version 0.1 (c) 2003 Fabrice Bellard\n"
128 "usage: qruncom file.com\n"
129 "user mode libqemu demo: run simple .com DOS executables\n");
130 exit(1);
131}
132
133static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg)
134{
135 return (uint8_t *)((seg << 4) + (reg & 0xffff));
136}
137
138static inline void pushw(CPUState *env, int val)
139{
140 env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) | ((env->regs[R_ESP] - 2) & 0xffff);
141 *(uint16_t *)seg_to_linear(env->segs[R_SS].selector, env->regs[R_ESP]) = val;
142}
143
144static void host_segv_handler(int host_signum, siginfo_t *info,
145 void *puc)
146{
147 if (cpu_signal_handler(host_signum, info, puc)) {
148 return;
149 }
150 abort();
151}
152
153int main(int argc, char **argv)
154{
155 uint8_t *vm86_mem;
156 const char *filename;
157 int fd, ret, seg;
158 CPUState *env;
159
160 if (argc != 2)
161 usage();
162 filename = argv[1];
163
164 vm86_mem = mmap((void *)0x00000000, 0x110000,
165 PROT_WRITE | PROT_READ | PROT_EXEC,
166 MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
167 if (vm86_mem == MAP_FAILED) {
168 perror("mmap");
169 exit(1);
170 }
171
172 /* load the MSDOS .com executable */
173 fd = open(filename, O_RDONLY);
174 if (fd < 0) {
175 perror(filename);
176 exit(1);
177 }
178 ret = read(fd, vm86_mem + COM_BASE_ADDR, 65536 - 256);
179 if (ret < 0) {
180 perror("read");
181 exit(1);
182 }
183 close(fd);
184
185 /* install exception handler for CPU emulator */
186 {
187 struct sigaction act;
188
189 sigfillset(&act.sa_mask);
190 act.sa_flags = SA_SIGINFO;
191 // act.sa_flags |= SA_ONSTACK;
192
193 act.sa_sigaction = host_segv_handler;
194 sigaction(SIGSEGV, &act, NULL);
195 sigaction(SIGBUS, &act, NULL);
196#if defined (TARGET_I386) && defined(USE_CODE_COPY)
197 sigaction(SIGFPE, &act, NULL);
198#endif
199 }
200
201 // cpu_set_log(CPU_LOG_TB_IN_ASM | CPU_LOG_TB_OUT_ASM | CPU_LOG_EXEC);
202
203 env = cpu_init();
204
205 /* disable code copy to simplify debugging */
206 code_copy_enabled = 0;
207
208 /* set user mode state (XXX: should be done automatically by
209 cpu_init ?) */
210 env->user_mode_only = 1;
211
212 cpu_x86_set_cpl(env, 3);
213
214 env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
215 /* NOTE: hflags duplicates some of the virtual CPU state */
216 env->hflags |= HF_PE_MASK | VM_MASK;
217
218 /* flags setup : we activate the IRQs by default as in user
219 mode. We also activate the VM86 flag to run DOS code */
220 env->eflags |= IF_MASK | VM_MASK;
221
222 /* init basic registers */
223 env->eip = 0x100;
224 env->regs[R_ESP] = 0xfffe;
225 seg = (COM_BASE_ADDR - 0x100) >> 4;
226
227 cpu_x86_load_seg_cache(env, R_CS, seg,
228 (seg << 4), 0xffff, 0);
229 cpu_x86_load_seg_cache(env, R_SS, seg,
230 (seg << 4), 0xffff, 0);
231 cpu_x86_load_seg_cache(env, R_DS, seg,
232 (seg << 4), 0xffff, 0);
233 cpu_x86_load_seg_cache(env, R_ES, seg,
234 (seg << 4), 0xffff, 0);
235 cpu_x86_load_seg_cache(env, R_FS, seg,
236 (seg << 4), 0xffff, 0);
237 cpu_x86_load_seg_cache(env, R_GS, seg,
238 (seg << 4), 0xffff, 0);
239
240 /* exception support */
241 env->idt.base = (unsigned long)idt_table;
242 env->idt.limit = sizeof(idt_table) - 1;
243 set_idt(0, 0);
244 set_idt(1, 0);
245 set_idt(2, 0);
246 set_idt(3, 3);
247 set_idt(4, 3);
248 set_idt(5, 3);
249 set_idt(6, 0);
250 set_idt(7, 0);
251 set_idt(8, 0);
252 set_idt(9, 0);
253 set_idt(10, 0);
254 set_idt(11, 0);
255 set_idt(12, 0);
256 set_idt(13, 0);
257 set_idt(14, 0);
258 set_idt(15, 0);
259 set_idt(16, 0);
260 set_idt(17, 0);
261 set_idt(18, 0);
262 set_idt(19, 0);
263
264 /* put return code */
265 *seg_to_linear(env->segs[R_CS].selector, 0) = 0xb4; /* mov ah, $0 */
266 *seg_to_linear(env->segs[R_CS].selector, 1) = 0x00;
267 *seg_to_linear(env->segs[R_CS].selector, 2) = 0xcd; /* int $0x21 */
268 *seg_to_linear(env->segs[R_CS].selector, 3) = 0x21;
269 pushw(env, 0x0000);
270
271 /* the value of these registers seem to be assumed by pi_10.com */
272 env->regs[R_ESI] = 0x100;
273 env->regs[R_ECX] = 0xff;
274 env->regs[R_EBP] = 0x0900;
275 env->regs[R_EDI] = 0xfffe;
276
277 /* inform the emulator of the mmaped memory */
278 page_set_flags(0x00000000, 0x110000,
279 PAGE_WRITE | PAGE_READ | PAGE_EXEC | PAGE_VALID);
280
281 for(;;) {
282 ret = cpu_x86_exec(env);
283 switch(ret) {
284 case EXCP0D_GPF:
285 {
286 int int_num, ah;
287 int_num = *(uint8_t *)(env->segs[R_CS].base + env->eip + 1);
288 if (int_num != 0x21)
289 goto unknown_int;
290 ah = (env->regs[R_EAX] >> 8) & 0xff;
291 switch(ah) {
292 case 0x00: /* exit */
293 exit(0);
294 case 0x02: /* write char */
295 {
296 uint8_t c = env->regs[R_EDX];
297 write(1, &c, 1);
298 }
299 break;
300 case 0x09: /* write string */
301 {
302 uint8_t c;
303 for(;;) {
304 c = *seg_to_linear(env->segs[R_DS].selector, env->regs[R_EAX]);
305 if (c == '$')
306 break;
307 write(1, &c, 1);
308 }
309 env->regs[R_EAX] = (env->regs[R_EAX] & ~0xff) | '$';
310 }
311 break;
312 default:
313 unknown_int:
314 fprintf(stderr, "unsupported int 0x%02x\n", int_num);
315 cpu_dump_state(env, stderr, fprintf, 0);
316 // exit(1);
317 }
318 env->eip += 2;
319 }
320 break;
321 default:
322 fprintf(stderr, "unhandled cpu_exec return code (0x%x)\n", ret);
323 cpu_dump_state(env, stderr, fprintf, 0);
324 exit(1);
325 }
326 }
327}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette