symbian-qemu-0.9.1-12/qemu-symbian-svp/tests/qruncom.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     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 
       
    19 void cpu_outb(CPUState *env, int addr, int val)
       
    20 {
       
    21     fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val);
       
    22 }
       
    23 
       
    24 void cpu_outw(CPUState *env, int addr, int val)
       
    25 {
       
    26     fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val);
       
    27 }
       
    28 
       
    29 void cpu_outl(CPUState *env, int addr, int val)
       
    30 {
       
    31     fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val);
       
    32 }
       
    33 
       
    34 int cpu_inb(CPUState *env, int addr)
       
    35 {
       
    36     fprintf(stderr, "inb: port=0x%04x\n", addr);
       
    37     return 0;
       
    38 }
       
    39 
       
    40 int cpu_inw(CPUState *env, int addr)
       
    41 {
       
    42     fprintf(stderr, "inw: port=0x%04x\n", addr);
       
    43     return 0;
       
    44 }
       
    45 
       
    46 int cpu_inl(CPUState *env, int addr)
       
    47 {
       
    48     fprintf(stderr, "inl: port=0x%04x\n", addr);
       
    49     return 0;
       
    50 }
       
    51 
       
    52 int cpu_get_pic_interrupt(CPUState *env)
       
    53 {
       
    54     return -1;
       
    55 }
       
    56 
       
    57 uint64_t cpu_get_tsc(CPUState *env)
       
    58 {
       
    59     return 0;
       
    60 }
       
    61 
       
    62 static 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 
       
    72 uint64_t idt_table[256];
       
    73 
       
    74 /* only dpl matters as we do only user space emulation */
       
    75 static void set_idt(int n, unsigned int dpl)
       
    76 {
       
    77     set_gate(idt_table + n, 0, dpl, 0, 0);
       
    78 }
       
    79 
       
    80 void qemu_free(void *ptr)
       
    81 {
       
    82     free(ptr);
       
    83 }
       
    84 
       
    85 void *qemu_malloc(size_t size)
       
    86 {
       
    87     return malloc(size);
       
    88 }
       
    89 
       
    90 void *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 
       
   100 void *qemu_vmalloc(size_t size)
       
   101 {
       
   102     return memalign(4096, size);
       
   103 }
       
   104 
       
   105 void qemu_vfree(void *ptr)
       
   106 {
       
   107     free(ptr);
       
   108 }
       
   109 
       
   110 void 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 */
       
   119 int errno;
       
   120 
       
   121 /**********************************************/
       
   122 
       
   123 #define COM_BASE_ADDR    0x10100
       
   124 
       
   125 void 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 
       
   133 static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg)
       
   134 {
       
   135     return (uint8_t *)((seg << 4) + (reg & 0xffff));
       
   136 }
       
   137 
       
   138 static 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 
       
   144 static 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 
       
   153 int 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     }
       
   197 
       
   198     //    cpu_set_log(CPU_LOG_TB_IN_ASM | CPU_LOG_TB_OUT_ASM | CPU_LOG_EXEC);
       
   199 
       
   200     env = cpu_init("qemu32");
       
   201 
       
   202     /* set user mode state (XXX: should be done automatically by
       
   203        cpu_init ?) */
       
   204     env->user_mode_only = 1;
       
   205 
       
   206     cpu_x86_set_cpl(env, 3);
       
   207 
       
   208     env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
       
   209     /* NOTE: hflags duplicates some of the virtual CPU state */
       
   210     env->hflags |= HF_PE_MASK | VM_MASK;
       
   211 
       
   212     /* flags setup : we activate the IRQs by default as in user
       
   213        mode. We also activate the VM86 flag to run DOS code */
       
   214     env->eflags |= IF_MASK | VM_MASK;
       
   215 
       
   216     /* init basic registers */
       
   217     env->eip = 0x100;
       
   218     env->regs[R_ESP] = 0xfffe;
       
   219     seg = (COM_BASE_ADDR - 0x100) >> 4;
       
   220 
       
   221     cpu_x86_load_seg_cache(env, R_CS, seg,
       
   222                            (seg << 4), 0xffff, 0);
       
   223     cpu_x86_load_seg_cache(env, R_SS, seg,
       
   224                            (seg << 4), 0xffff, 0);
       
   225     cpu_x86_load_seg_cache(env, R_DS, seg,
       
   226                            (seg << 4), 0xffff, 0);
       
   227     cpu_x86_load_seg_cache(env, R_ES, seg,
       
   228                            (seg << 4), 0xffff, 0);
       
   229     cpu_x86_load_seg_cache(env, R_FS, seg,
       
   230                            (seg << 4), 0xffff, 0);
       
   231     cpu_x86_load_seg_cache(env, R_GS, seg,
       
   232                            (seg << 4), 0xffff, 0);
       
   233 
       
   234     /* exception support */
       
   235     env->idt.base = (unsigned long)idt_table;
       
   236     env->idt.limit = sizeof(idt_table) - 1;
       
   237     set_idt(0, 0);
       
   238     set_idt(1, 0);
       
   239     set_idt(2, 0);
       
   240     set_idt(3, 3);
       
   241     set_idt(4, 3);
       
   242     set_idt(5, 3);
       
   243     set_idt(6, 0);
       
   244     set_idt(7, 0);
       
   245     set_idt(8, 0);
       
   246     set_idt(9, 0);
       
   247     set_idt(10, 0);
       
   248     set_idt(11, 0);
       
   249     set_idt(12, 0);
       
   250     set_idt(13, 0);
       
   251     set_idt(14, 0);
       
   252     set_idt(15, 0);
       
   253     set_idt(16, 0);
       
   254     set_idt(17, 0);
       
   255     set_idt(18, 0);
       
   256     set_idt(19, 0);
       
   257 
       
   258     /* put return code */
       
   259     *seg_to_linear(env->segs[R_CS].selector, 0) = 0xb4; /* mov ah, $0 */
       
   260     *seg_to_linear(env->segs[R_CS].selector, 1) = 0x00;
       
   261     *seg_to_linear(env->segs[R_CS].selector, 2) = 0xcd; /* int $0x21 */
       
   262     *seg_to_linear(env->segs[R_CS].selector, 3) = 0x21;
       
   263     pushw(env, 0x0000);
       
   264 
       
   265     /* the value of these registers seem to be assumed by pi_10.com */
       
   266     env->regs[R_ESI] = 0x100;
       
   267     env->regs[R_ECX] = 0xff;
       
   268     env->regs[R_EBP] = 0x0900;
       
   269     env->regs[R_EDI] = 0xfffe;
       
   270 
       
   271     /* inform the emulator of the mmaped memory */
       
   272     page_set_flags(0x00000000, 0x110000,
       
   273                    PAGE_WRITE | PAGE_READ | PAGE_EXEC | PAGE_VALID);
       
   274 
       
   275     for(;;) {
       
   276         ret = cpu_x86_exec(env);
       
   277         switch(ret) {
       
   278         case EXCP0D_GPF:
       
   279             {
       
   280                 int int_num, ah;
       
   281                 int_num = *(uint8_t *)(env->segs[R_CS].base + env->eip + 1);
       
   282                 if (int_num != 0x21)
       
   283                     goto unknown_int;
       
   284                 ah = (env->regs[R_EAX] >> 8) & 0xff;
       
   285                 switch(ah) {
       
   286                 case 0x00: /* exit */
       
   287                     exit(0);
       
   288                 case 0x02: /* write char */
       
   289                     {
       
   290                         uint8_t c = env->regs[R_EDX];
       
   291                         write(1, &c, 1);
       
   292                     }
       
   293                     break;
       
   294                 case 0x09: /* write string */
       
   295                     {
       
   296                         uint8_t c;
       
   297                         for(;;) {
       
   298                             c = *seg_to_linear(env->segs[R_DS].selector, env->regs[R_EAX]);
       
   299                             if (c == '$')
       
   300                                 break;
       
   301                             write(1, &c, 1);
       
   302                         }
       
   303                         env->regs[R_EAX] = (env->regs[R_EAX] & ~0xff) | '$';
       
   304                     }
       
   305                     break;
       
   306                 default:
       
   307                 unknown_int:
       
   308                     fprintf(stderr, "unsupported int 0x%02x\n", int_num);
       
   309                     cpu_dump_state(env, stderr, fprintf, 0);
       
   310                     //                    exit(1);
       
   311                 }
       
   312                 env->eip += 2;
       
   313             }
       
   314             break;
       
   315         default:
       
   316             fprintf(stderr, "unhandled cpu_exec return code (0x%x)\n", ret);
       
   317             cpu_dump_state(env, stderr, fprintf, 0);
       
   318             exit(1);
       
   319         }
       
   320     }
       
   321 }