xref: /qemu/linux-user/main.c (revision 66fb9763)
131e31b8aSbellard /*
26dbad63eSbellard  *  gemu main
331e31b8aSbellard  *
431e31b8aSbellard  *  Copyright (c) 2003 Fabrice Bellard
531e31b8aSbellard  *
631e31b8aSbellard  *  This program is free software; you can redistribute it and/or modify
731e31b8aSbellard  *  it under the terms of the GNU General Public License as published by
831e31b8aSbellard  *  the Free Software Foundation; either version 2 of the License, or
931e31b8aSbellard  *  (at your option) any later version.
1031e31b8aSbellard  *
1131e31b8aSbellard  *  This program is distributed in the hope that it will be useful,
1231e31b8aSbellard  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1331e31b8aSbellard  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1431e31b8aSbellard  *  GNU General Public License for more details.
1531e31b8aSbellard  *
1631e31b8aSbellard  *  You should have received a copy of the GNU General Public License
1731e31b8aSbellard  *  along with this program; if not, write to the Free Software
1831e31b8aSbellard  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
1931e31b8aSbellard  */
2031e31b8aSbellard #include <stdlib.h>
2131e31b8aSbellard #include <stdio.h>
2231e31b8aSbellard #include <stdarg.h>
2304369ff2Sbellard #include <string.h>
2431e31b8aSbellard #include <errno.h>
250ecfa993Sbellard #include <unistd.h>
2631e31b8aSbellard 
2731e31b8aSbellard #include "gemu.h"
2831e31b8aSbellard 
290ecfa993Sbellard #include "cpu-i386.h"
3031e31b8aSbellard 
31586314f2Sbellard #define DEBUG_LOGFILE "/tmp/gemu.log"
32586314f2Sbellard 
33586314f2Sbellard FILE *logfile = NULL;
34586314f2Sbellard int loglevel;
35586314f2Sbellard 
3631e31b8aSbellard unsigned long x86_stack_size;
3731e31b8aSbellard unsigned long stktop;
3831e31b8aSbellard 
3931e31b8aSbellard void gemu_log(const char *fmt, ...)
4031e31b8aSbellard {
4131e31b8aSbellard     va_list ap;
4231e31b8aSbellard 
4331e31b8aSbellard     va_start(ap, fmt);
4431e31b8aSbellard     vfprintf(stderr, fmt, ap);
4531e31b8aSbellard     va_end(ap);
4631e31b8aSbellard }
4731e31b8aSbellard 
4831e31b8aSbellard /***********************************************************/
490ecfa993Sbellard /* CPUX86 core interface */
50367e86e8Sbellard 
51ba1c6e37Sbellard void cpu_x86_outb(int addr, int val)
52367e86e8Sbellard {
53367e86e8Sbellard     fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val);
54367e86e8Sbellard }
55367e86e8Sbellard 
56ba1c6e37Sbellard void cpu_x86_outw(int addr, int val)
57367e86e8Sbellard {
58367e86e8Sbellard     fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val);
59367e86e8Sbellard }
60367e86e8Sbellard 
61ba1c6e37Sbellard void cpu_x86_outl(int addr, int val)
62367e86e8Sbellard {
63367e86e8Sbellard     fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val);
64367e86e8Sbellard }
65367e86e8Sbellard 
66ba1c6e37Sbellard int cpu_x86_inb(int addr)
67367e86e8Sbellard {
68367e86e8Sbellard     fprintf(stderr, "inb: port=0x%04x\n", addr);
69367e86e8Sbellard     return 0;
70367e86e8Sbellard }
71367e86e8Sbellard 
72ba1c6e37Sbellard int cpu_x86_inw(int addr)
73367e86e8Sbellard {
74367e86e8Sbellard     fprintf(stderr, "inw: port=0x%04x\n", addr);
75367e86e8Sbellard     return 0;
76367e86e8Sbellard }
77367e86e8Sbellard 
78ba1c6e37Sbellard int cpu_x86_inl(int addr)
79367e86e8Sbellard {
80367e86e8Sbellard     fprintf(stderr, "inl: port=0x%04x\n", addr);
81367e86e8Sbellard     return 0;
82367e86e8Sbellard }
83367e86e8Sbellard 
846dbad63eSbellard void write_dt(void *ptr, unsigned long addr, unsigned long limit,
856dbad63eSbellard               int seg32_bit)
866dbad63eSbellard {
876dbad63eSbellard     unsigned int e1, e2, limit_in_pages;
886dbad63eSbellard     limit_in_pages = 0;
896dbad63eSbellard     if (limit > 0xffff) {
906dbad63eSbellard         limit = limit >> 12;
916dbad63eSbellard         limit_in_pages = 1;
926dbad63eSbellard     }
936dbad63eSbellard     e1 = (addr << 16) | (limit & 0xffff);
946dbad63eSbellard     e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
956dbad63eSbellard     e2 |= limit_in_pages << 23; /* byte granularity */
966dbad63eSbellard     e2 |= seg32_bit << 22; /* 32 bit segment */
976dbad63eSbellard     stl((uint8_t *)ptr, e1);
986dbad63eSbellard     stl((uint8_t *)ptr + 4, e2);
996dbad63eSbellard }
1006dbad63eSbellard 
1016dbad63eSbellard uint64_t gdt_table[6];
10231e31b8aSbellard 
1031b6b029eSbellard void cpu_loop(struct CPUX86State *env)
1041b6b029eSbellard {
1051b6b029eSbellard     for(;;) {
1061b6b029eSbellard         int err;
1071b6b029eSbellard         uint8_t *pc;
1081b6b029eSbellard 
1091b6b029eSbellard         err = cpu_x86_exec(env);
1101b6b029eSbellard         pc = env->seg_cache[R_CS].base + env->eip;
1111b6b029eSbellard         switch(err) {
1121b6b029eSbellard         case EXCP0D_GPF:
1131b6b029eSbellard             if (pc[0] == 0xcd && pc[1] == 0x80) {
1141b6b029eSbellard                 /* syscall */
1151b6b029eSbellard                 env->eip += 2;
1161b6b029eSbellard                 env->regs[R_EAX] = do_syscall(env,
1171b6b029eSbellard                                               env->regs[R_EAX],
1181b6b029eSbellard                                               env->regs[R_EBX],
1191b6b029eSbellard                                               env->regs[R_ECX],
1201b6b029eSbellard                                               env->regs[R_EDX],
1211b6b029eSbellard                                               env->regs[R_ESI],
1221b6b029eSbellard                                               env->regs[R_EDI],
1231b6b029eSbellard                                               env->regs[R_EBP]);
1241b6b029eSbellard             } else {
1251b6b029eSbellard                 goto trap_error;
1261b6b029eSbellard             }
1271b6b029eSbellard             break;
1281b6b029eSbellard         default:
1291b6b029eSbellard         trap_error:
1301b6b029eSbellard             fprintf(stderr, "0x%08lx: Unknown exception %d, aborting\n",
1311b6b029eSbellard                     (long)pc, err);
1321b6b029eSbellard             abort();
1331b6b029eSbellard         }
134*66fb9763Sbellard         process_pending_signals(env);
1351b6b029eSbellard     }
1361b6b029eSbellard }
1371b6b029eSbellard 
13831e31b8aSbellard void usage(void)
13931e31b8aSbellard {
1407d13299dSbellard     printf("gemu version " GEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
141586314f2Sbellard            "usage: gemu [-d] program [arguments...]\n"
14231e31b8aSbellard            "Linux x86 emulator\n"
14331e31b8aSbellard            );
14431e31b8aSbellard     exit(1);
14531e31b8aSbellard }
14631e31b8aSbellard 
14731e31b8aSbellard int main(int argc, char **argv)
14831e31b8aSbellard {
14931e31b8aSbellard     const char *filename;
15001ffc75bSbellard     struct target_pt_regs regs1, *regs = &regs1;
15131e31b8aSbellard     struct image_info info1, *info = &info1;
1520ecfa993Sbellard     CPUX86State *env;
153586314f2Sbellard     int optind;
15431e31b8aSbellard 
15531e31b8aSbellard     if (argc <= 1)
15631e31b8aSbellard         usage();
157586314f2Sbellard     loglevel = 0;
158586314f2Sbellard     optind = 1;
159586314f2Sbellard     if (argv[optind] && !strcmp(argv[optind], "-d")) {
160586314f2Sbellard         loglevel = 1;
161586314f2Sbellard         optind++;
162586314f2Sbellard     }
163586314f2Sbellard     filename = argv[optind];
16431e31b8aSbellard 
165586314f2Sbellard     /* init debug */
166586314f2Sbellard     if (loglevel) {
167586314f2Sbellard         logfile = fopen(DEBUG_LOGFILE, "w");
168586314f2Sbellard         if (!logfile) {
169586314f2Sbellard             perror(DEBUG_LOGFILE);
170586314f2Sbellard             exit(1);
171586314f2Sbellard         }
172586314f2Sbellard         setvbuf(logfile, NULL, _IOLBF, 0);
173586314f2Sbellard     }
17431e31b8aSbellard 
17531e31b8aSbellard     /* Zero out regs */
17601ffc75bSbellard     memset(regs, 0, sizeof(struct target_pt_regs));
17731e31b8aSbellard 
17831e31b8aSbellard     /* Zero out image_info */
17931e31b8aSbellard     memset(info, 0, sizeof(struct image_info));
18031e31b8aSbellard 
1814b74fe1fSbellard     if(elf_exec(filename, argv+optind, environ, regs, info) != 0) {
18231e31b8aSbellard 	printf("Error loading %s\n", filename);
18331e31b8aSbellard 	exit(1);
18431e31b8aSbellard     }
18531e31b8aSbellard 
1864b74fe1fSbellard     if (loglevel) {
1874b74fe1fSbellard         fprintf(logfile, "start_brk   0x%08lx\n" , info->start_brk);
1884b74fe1fSbellard         fprintf(logfile, "end_code    0x%08lx\n" , info->end_code);
1894b74fe1fSbellard         fprintf(logfile, "start_code  0x%08lx\n" , info->start_code);
1904b74fe1fSbellard         fprintf(logfile, "end_data    0x%08lx\n" , info->end_data);
1914b74fe1fSbellard         fprintf(logfile, "start_stack 0x%08lx\n" , info->start_stack);
1924b74fe1fSbellard         fprintf(logfile, "brk         0x%08lx\n" , info->brk);
1934b74fe1fSbellard         fprintf(logfile, "esp         0x%08lx\n" , regs->esp);
1944b74fe1fSbellard         fprintf(logfile, "eip         0x%08lx\n" , regs->eip);
1954b74fe1fSbellard     }
19631e31b8aSbellard 
19731e31b8aSbellard     target_set_brk((char *)info->brk);
19831e31b8aSbellard     syscall_init();
199*66fb9763Sbellard     signal_init();
20031e31b8aSbellard 
2010ecfa993Sbellard     env = cpu_x86_init();
20231e31b8aSbellard 
2036dbad63eSbellard     /* linux register setup */
2040ecfa993Sbellard     env->regs[R_EAX] = regs->eax;
2050ecfa993Sbellard     env->regs[R_EBX] = regs->ebx;
2060ecfa993Sbellard     env->regs[R_ECX] = regs->ecx;
2070ecfa993Sbellard     env->regs[R_EDX] = regs->edx;
2080ecfa993Sbellard     env->regs[R_ESI] = regs->esi;
2090ecfa993Sbellard     env->regs[R_EDI] = regs->edi;
2100ecfa993Sbellard     env->regs[R_EBP] = regs->ebp;
2110ecfa993Sbellard     env->regs[R_ESP] = regs->esp;
212dab2ed99Sbellard     env->eip = regs->eip;
21331e31b8aSbellard 
2146dbad63eSbellard     /* linux segment setup */
2156dbad63eSbellard     env->gdt.base = (void *)gdt_table;
2166dbad63eSbellard     env->gdt.limit = sizeof(gdt_table) - 1;
2176dbad63eSbellard     write_dt(&gdt_table[__USER_CS >> 3], 0, 0xffffffff, 1);
2186dbad63eSbellard     write_dt(&gdt_table[__USER_DS >> 3], 0, 0xffffffff, 1);
2196dbad63eSbellard     cpu_x86_load_seg(env, R_CS, __USER_CS);
2206dbad63eSbellard     cpu_x86_load_seg(env, R_DS, __USER_DS);
2216dbad63eSbellard     cpu_x86_load_seg(env, R_ES, __USER_DS);
2226dbad63eSbellard     cpu_x86_load_seg(env, R_SS, __USER_DS);
2236dbad63eSbellard     cpu_x86_load_seg(env, R_FS, __USER_DS);
2246dbad63eSbellard     cpu_x86_load_seg(env, R_GS, __USER_DS);
22531e31b8aSbellard 
2261b6b029eSbellard     cpu_loop(env);
2271b6b029eSbellard     /* never exits */
22831e31b8aSbellard     return 0;
22931e31b8aSbellard }
230