Commit 367e86e8 authored by bellard's avatar bellard
Browse files

new x86 CPU core


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@14 c046a42c-6fe2-441c-8c8c-71466251a162
parent 7bfdb6d1
ARCH=i386
#ARCH=ppc
HOST_CC=gcc
ifeq ($(ARCH),i386)
CFLAGS=-Wall -O2 -g
CFLAGS=-Wall -O2 -g -fomit-frame-pointer
LDFLAGS=-g
LIBS=
CC=gcc
......@@ -27,38 +28,59 @@ endif
#########################################################
DEFINES+=-D_GNU_SOURCE -DGEMU -DDOSEMU #-DNO_TRACE_MSGS
DEFINES+=-D_GNU_SOURCE -DGEMU -DDOSEMU -DNO_TRACE_MSGS
DEFINES+=-DCONFIG_PREFIX=\"/usr/local\"
LDSCRIPT=$(ARCH).ld
LIBS+=-ldl
OBJS= i386/fp87.o i386/interp_main.o i386/interp_modrm.o i386/interp_16_32.o \
i386/interp_32_16.o i386/interp_32_32.o i386/emu-utils.o \
i386/dis8086.o i386/emu-ldt.o
OBJS+=translate-i386.o op-i386.o
OBJS+= elfload.o main.o thunk.o syscall.o
SRCS = $(OBJS:.o=.c)
all: gemu
gemu: $(OBJS)
$(CC) -Wl,-T,$(LDSCRIPT) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
$(CC) -Wl,-T,$(LDSCRIPT) $(LDFLAGS) -o $@ $^ $(LIBS)
depend: $(SRCS)
$(CC) -MM $(CFLAGS) $^ 1>.depend
# old i386 emulator
i386/interp_32_32.o: i386/interp_32_32.c i386/interp_gen.h
i386/interp_gen.h: i386/gencode
./i386/gencode > $@
i386/gencode: i386/gencode.c
$(CC) -O2 -Wall -g $< -o $@
# new i386 emulator
dyngen: dyngen.c
$(HOST_CC) -O2 -Wall -g $< -o $@
translate-i386.o: translate-i386.c op-i386.h cpu-i386.h
op-i386.h: op-i386.o dyngen
./dyngen -o $@ $<
op-i386.o: op-i386.c opreg_template.h ops_template.h
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
%.o: %.c
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
clean:
rm -f *.o *~ i386/*.o i386/*~ gemu hello test1 test2 TAGS
hello: hello.c
$(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $<
rm -f *.o *~ i386/*.o i386/*~ gemu TAGS
test1: test1.c
$(CC) $(CFLAGS) -static $(LDFLAGS) -o $@ $<
# various test targets
test speed: gemu
make -C tests $@
test2: test2.c
$(CC) $(CFLAGS) -static $(LDFLAGS) -o $@ $<
TAGS:
etags *.[ch] i386/*.[ch]
ifneq ($(wildcard .depend),)
include .depend
......
- swap all elf paramters
- tests
- signals
- threads
- fix printf for doubles (fp87.c bug ?)
- make it self runnable (use same trick as ld.so : include its own relocator and libc)
#ifndef CPU_I386_H
#define CPU_I386_H
#define R_EAX 0
#define R_ECX 1
#define R_EDX 2
#define R_EBX 3
#define R_ESP 4
#define R_EBP 5
#define R_ESI 6
#define R_EDI 7
#define R_AL 0
#define R_CL 1
#define R_DL 2
#define R_BL 3
#define R_AH 4
#define R_CH 5
#define R_DH 6
#define R_BH 7
#define R_ES 0
#define R_CS 1
#define R_SS 2
#define R_DS 3
#define R_FS 4
#define R_GS 5
#define CC_C 0x0001
#define CC_P 0x0004
#define CC_A 0x0010
#define CC_Z 0x0040
#define CC_S 0x0080
#define CC_O 0x0800
#define TRAP_FLAG 0x0100
#define INTERRUPT_FLAG 0x0200
#define DIRECTION_FLAG 0x0400
#define IOPL_FLAG_MASK 0x3000
#define NESTED_FLAG 0x4000
#define BYTE_FL 0x8000 /* Intel reserved! */
#define RF_FLAG 0x10000
#define VM_FLAG 0x20000
/* AC 0x40000 */
enum {
CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */
CC_OP_MUL, /* modify all flags, C, O = (CC_SRC != 0) */
CC_OP_ADDB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_ADDW,
CC_OP_ADDL,
CC_OP_SUBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_SUBW,
CC_OP_SUBL,
CC_OP_LOGICB, /* modify all flags, CC_DST = res */
CC_OP_LOGICW,
CC_OP_LOGICL,
CC_OP_INCB, /* modify all flags except, CC_DST = res */
CC_OP_INCW,
CC_OP_INCL,
CC_OP_DECB, /* modify all flags except, CC_DST = res */
CC_OP_DECW,
CC_OP_DECL,
CC_OP_SHLB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */
CC_OP_SHLW,
CC_OP_SHLL,
CC_OP_NB,
};
typedef struct CPU86State {
/* standard registers */
uint32_t regs[8];
uint32_t pc; /* cs_case + eip value */
/* eflags handling */
uint32_t eflags;
uint32_t cc_src;
uint32_t cc_dst;
uint32_t cc_op;
int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */
/* segments */
uint8_t *segs_base[6];
uint32_t segs[6];
/* emulator internal variables */
uint32_t t0; /* temporary t0 storage */
uint32_t t1; /* temporary t1 storage */
uint32_t a0; /* temporary a0 storage (address) */
} CPU86State;
static inline int ldub(void *ptr)
{
return *(uint8_t *)ptr;
}
static inline int ldsb(void *ptr)
{
return *(int8_t *)ptr;
}
static inline int lduw(void *ptr)
{
return *(uint16_t *)ptr;
}
static inline int ldsw(void *ptr)
{
return *(int16_t *)ptr;
}
static inline int ldl(void *ptr)
{
return *(uint32_t *)ptr;
}
static inline void stb(void *ptr, int v)
{
*(uint8_t *)ptr = v;
}
static inline void stw(void *ptr, int v)
{
*(uint16_t *)ptr = v;
}
static inline void stl(void *ptr, int v)
{
*(uint32_t *)ptr = v;
}
void port_outb(int addr, int val);
void port_outw(int addr, int val);
void port_outl(int addr, int val);
int port_inb(int addr);
int port_inw(int addr);
int port_inl(int addr);
#endif /* CPU_I386_H */
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <inttypes.h>
#include <elf.h>
#include <unistd.h>
#include <fcntl.h>
#include "thunk.h"
/* all dynamically generated functions begin with this code */
#define OP_PREFIX "op"
int elf_must_swap(Elf32_Ehdr *h)
{
union {
uint32_t i;
uint8_t b[4];
} swaptest;
swaptest.i = 1;
return (h->e_ident[EI_DATA] == ELFDATA2MSB) !=
(swaptest.b[0] == 0);
}
void swab16s(uint16_t *p)
{
*p = bswap16(*p);
}
void swab32s(uint32_t *p)
{
*p = bswap32(*p);
}
void swab64s(uint32_t *p)
{
*p = bswap64(*p);
}
void elf_swap_ehdr(Elf32_Ehdr *h)
{
swab16s(&h->e_type); /* Object file type */
swab16s(&h-> e_machine); /* Architecture */
swab32s(&h-> e_version); /* Object file version */
swab32s(&h-> e_entry); /* Entry point virtual address */
swab32s(&h-> e_phoff); /* Program header table file offset */
swab32s(&h-> e_shoff); /* Section header table file offset */
swab32s(&h-> e_flags); /* Processor-specific flags */
swab16s(&h-> e_ehsize); /* ELF header size in bytes */
swab16s(&h-> e_phentsize); /* Program header table entry size */
swab16s(&h-> e_phnum); /* Program header table entry count */
swab16s(&h-> e_shentsize); /* Section header table entry size */
swab16s(&h-> e_shnum); /* Section header table entry count */
swab16s(&h-> e_shstrndx); /* Section header string table index */
}
void elf_swap_shdr(Elf32_Shdr *h)
{
swab32s(&h-> sh_name); /* Section name (string tbl index) */
swab32s(&h-> sh_type); /* Section type */
swab32s(&h-> sh_flags); /* Section flags */
swab32s(&h-> sh_addr); /* Section virtual addr at execution */
swab32s(&h-> sh_offset); /* Section file offset */
swab32s(&h-> sh_size); /* Section size in bytes */
swab32s(&h-> sh_link); /* Link to another section */
swab32s(&h-> sh_info); /* Additional section information */
swab32s(&h-> sh_addralign); /* Section alignment */
swab32s(&h-> sh_entsize); /* Entry size if section holds table */
}
void elf_swap_phdr(Elf32_Phdr *h)
{
swab32s(&h->p_type); /* Segment type */
swab32s(&h->p_offset); /* Segment file offset */
swab32s(&h->p_vaddr); /* Segment virtual address */
swab32s(&h->p_paddr); /* Segment physical address */
swab32s(&h->p_filesz); /* Segment size in file */
swab32s(&h->p_memsz); /* Segment size in memory */
swab32s(&h->p_flags); /* Segment flags */
swab32s(&h->p_align); /* Segment alignment */
}
int do_swap;
int e_machine;
uint16_t get16(uint16_t *p)
{
uint16_t val;
val = *p;
if (do_swap)
val = bswap16(val);
return val;
}
uint32_t get32(uint32_t *p)
{
uint32_t val;
val = *p;
if (do_swap)
val = bswap32(val);
return val;
}
void put16(uint16_t *p, uint16_t val)
{
if (do_swap)
val = bswap16(val);
*p = val;
}
void put32(uint32_t *p, uint32_t val)
{
if (do_swap)
val = bswap32(val);
*p = val;
}
void __attribute__((noreturn)) error(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "dyngen: ");
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
exit(1);
}
Elf32_Shdr *find_elf_section(Elf32_Shdr *shdr, int shnum, const char *shstr,
const char *name)
{
int i;
const char *shname;
Elf32_Shdr *sec;
for(i = 0; i < shnum; i++) {
sec = &shdr[i];
if (!sec->sh_name)
continue;
shname = shstr + sec->sh_name;
if (!strcmp(shname, name))
return sec;
}
return NULL;
}
void *load_data(int fd, long offset, unsigned int size)
{
char *data;
data = malloc(size);
if (!data)
return NULL;
lseek(fd, offset, SEEK_SET);
if (read(fd, data, size) != size) {
free(data);
return NULL;
}
return data;
}
int strstart(const char *str, const char *val, const char **ptr)
{
const char *p, *q;
p = str;
q = val;
while (*q != '\0') {
if (*p != *q)
return 0;
p++;
q++;
}
if (ptr)
*ptr = p;
return 1;
}
#define MAX_ARGS 3
/* generate op code */
void gen_code(const char *name, unsigned long offset, unsigned long size,
FILE *outfile, uint8_t *text, void *relocs, int nb_relocs, int reloc_sh_type,
Elf32_Sym *symtab, char *strtab)
{
int copy_size = 0;
uint8_t *p_start, *p_end;
int nb_args, i;
uint8_t args_present[MAX_ARGS];
const char *sym_name, *p;
/* compute exact size excluding return instruction */
p_start = text + offset;
p_end = p_start + size;
switch(e_machine) {
case EM_386:
{
uint8_t *p;
p = p_end - 1;
/* find ret */
while (p > p_start && *p != 0xc3)
p--;
/* skip double ret */
if (p > p_start && p[-1] == 0xc3)
p--;
if (p == p_start)
error("empty code for %s", name);
copy_size = p - p_start;
}
break;
case EM_PPC:
{
uint8_t *p;
p = (void *)(p_end - 4);
/* find ret */
while (p > p_start && get32((uint32_t *)p) != 0x4e800020)
p -= 4;
/* skip double ret */
if (p > p_start && get32((uint32_t *)(p - 4)) == 0x4e800020)
p -= 4;
if (p == p_start)
error("empty code for %s", name);
copy_size = p - p_start;
}
break;
default:
error("unsupported CPU (%d)", e_machine);
}
/* compute the number of arguments by looking at the relocations */
for(i = 0;i < MAX_ARGS; i++)
args_present[i] = 0;
if (reloc_sh_type == SHT_REL) {
Elf32_Rel *rel;
int n;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
if (strstart(sym_name, "__op_param", &p)) {
n = strtoul(p, NULL, 10);
if (n >= MAX_ARGS)
error("too many arguments in %s", name);
args_present[n - 1] = 1;
}
}
}
} else {
Elf32_Rela *rel;
int n;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
if (strstart(sym_name, "__op_param", &p)) {
n = strtoul(p, NULL, 10);
if (n >= MAX_ARGS)
error("too many arguments in %s", name);
args_present[n - 1] = 1;
}
}
}
}
nb_args = 0;
while (nb_args < MAX_ARGS && args_present[nb_args])
nb_args++;
for(i = nb_args; i < MAX_ARGS; i++) {
if (args_present[i])
error("inconsistent argument numbering in %s", name);
}
/* output C code */
fprintf(outfile, "extern void %s();\n", name);
fprintf(outfile, "static inline void gen_%s(", name);
if (nb_args == 0) {
fprintf(outfile, "void");
} else {
for(i = 0; i < nb_args; i++) {
if (i != 0)
fprintf(outfile, ", ");
fprintf(outfile, "long param%d", i + 1);
}
}
fprintf(outfile, ")\n");
fprintf(outfile, "{\n");
fprintf(outfile, " memcpy(gen_code_ptr, &%s, %d);\n", name, copy_size);
/* patch relocations */
switch(e_machine) {
case EM_386:
{
Elf32_Rel *rel;
char name[256];
int type;
long addend;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
if (strstart(sym_name, "__op_param", &p)) {
snprintf(name, sizeof(name), "param%s", p);
} else {
snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
}
type = ELF32_R_TYPE(rel->r_info);
addend = get32((uint32_t *)(text + rel->r_offset));
switch(type) {
case R_386_32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = %s + %ld;\n",
rel->r_offset - offset, name, addend);
break;
case R_386_PC32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = %s - (long)(gen_code_ptr + %ld) + %ld;\n",
rel->r_offset - offset, name, rel->r_offset - offset, addend);
break;
default:
error("unsupported i386 relocation (%d)", type);
}
}
}
}
break;
default:
error("unsupported CPU for relocations (%d)", e_machine);
}
fprintf(outfile, " gen_code_ptr += %d;\n", copy_size);
fprintf(outfile, "}\n\n");
}
/* load an elf object file */
int load_elf(const char *filename, FILE *outfile)
{
int fd;
Elf32_Ehdr ehdr;
Elf32_Shdr *sec, *shdr, *symtab_sec, *strtab_sec, *text_sec;
int i, j, nb_syms;
Elf32_Sym *symtab, *sym;
const char *cpu_name;
char *shstr, *strtab;
uint8_t *text;
void *relocs;
int nb_relocs, reloc_sh_type;
fd = open(filename, O_RDONLY);
if (fd < 0)
error("can't open file '%s'", filename);
/* Read ELF header. */
if (read(fd, &ehdr, sizeof (ehdr)) != sizeof (ehdr))
error("unable to read file header");
/* Check ELF identification. */
if (ehdr.e_ident[EI_MAG0] != ELFMAG0
|| ehdr.e_ident[EI_MAG1] != ELFMAG1
|| ehdr.e_ident[EI_MAG2] != ELFMAG2
|| ehdr.e_ident[EI_MAG3] != ELFMAG3
|| ehdr.e_ident[EI_CLASS] != ELFCLASS32
|| ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
error("bad ELF header");
}
do_swap = elf_must_swap(&ehdr);
if (do_swap)
elf_swap_ehdr(&ehdr);
if (ehdr.e_type != ET_REL)
error("ELF object file expected");
if (ehdr.e_version != EV_CURRENT)
error("Invalid ELF version");
e_machine = ehdr.e_machine;
/* read section headers */
shdr = load_data(fd, ehdr.e_shoff, ehdr.e_shnum * sizeof(Elf32_Shdr));
if (do_swap) {
for(i = 0; i < ehdr.e_shnum; i++) {
elf_swap_shdr(&shdr[i]);
}
}
sec = &shdr[ehdr.e_shstrndx];
shstr = load_data(fd, sec->sh_offset, sec->sh_size);
/* text section */
text_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".text");
if (!text_sec)
error("could not find .text section");
text = load_data(fd, text_sec->sh_offset, text_sec->sh_size);
/* find text relocations, if any */
nb_relocs = 0;
relocs = NULL;
reloc_sh_type = 0;
for(i = 0; i < ehdr.e_shnum; i++) {
sec = &shdr[i];