Skip to content

Commit

Permalink
Implement enough instructions to run up to the system call
Browse files Browse the repository at this point in the history
  • Loading branch information
tbodt committed Apr 28, 2017
1 parent 7a492fb commit 4455edd
Show file tree
Hide file tree
Showing 11 changed files with 301 additions and 52 deletions.
180 changes: 156 additions & 24 deletions emu/cpu.c
Original file line number Diff line number Diff line change
@@ -1,70 +1,202 @@
#ifndef AGAIN
#include "misc.h"
#include "emu/cpu.h"
#include "emu/modrm.h"
#include "emu/interrupt.h"

static void trace_cpu(struct cpu_state *cpu) {
TRACE("eax=%x ebx=%x ecx=%x edx=%x esi=%x edi=%x ebp=%x esp=%x",
cpu->eax, cpu->ebx, cpu->ecx, cpu->edx, cpu->esi, cpu->edi, cpu->ebp, cpu->esp);
}

// fuck preprocessor
#define OP_SIZE 32
#define cpu_step CONCAT(cpu_step, OP_SIZE)
#endif

#undef oprnd_t
#if OP_SIZE == 32
#define oprnd_t dword_t
#else
#define oprnd_t word_t
#endif

// this will be the next PyEval_EvalFrameEx.
int cpu_step(struct cpu_state *cpu) {
// watch out: these macros can evaluate the arguments any number of times
#define MEM(addr, size) MEM_GET(cpu, addr, size)
#define REG(reg_id, size) REG_VAL(cpu, reg_id, size)
#define REGPTR(regptr, size) REG(regptr.reg##size##_id, size)
#define MEM(addr) MEM_GET(cpu, addr, OP_SIZE)
#define MEM8(addr) MEM_GET(cpu, addr, 8)
#define REG(reg_id) REG_VAL(cpu, reg_id, OP_SIZE)
#define REGPTR(regptr) REG(CONCAT3(regptr.reg,OP_SIZE,_id))

// used by MODRM_MEM, don't use for anything else
struct modrm_info modrm;
dword_t modrm_addr;
#define DECODE_MODRM(size) \
modrm_decode##size(cpu, &modrm_addr, &modrm)
#define PUSH(thing, size) \
cpu->esp -= size; \
MEM(cpu->esp, size) = thing
#define MODRM_VAL \
*(modrm.type == mod_reg ? &REGPTR(modrm.modrm_reg) : &MEM(modrm_addr))

#define PUSH(thing) \
cpu->esp -= OP_SIZE/8; \
MEM(cpu->esp) = thing

#undef imm
#define imm CONCAT(imm, OP_SIZE)
byte_t imm8;
oprnd_t imm;
#define READIMM \
imm = MEM(cpu->eip); \
cpu->eip += OP_SIZE/8; \
TRACE("immediate: %x", imm)
#define READIMM8 \
imm8 = MEM8(cpu->eip); \
cpu->eip++; \
TRACE("immediate: %x", imm8)

byte_t insn = MEM(cpu->eip,8);
printf("0x%x\n", insn);
// TODO use different registers in 16-bit mode

byte_t insn = MEM8(cpu->eip);
printf("0x%x: ", insn);
cpu->eip++;
switch (insn) {
// if any instruction handlers declare variables, they should create a
// new block for those variables

// push dword register
case 0x50:
PUSH(cpu->eax,32); break;
TRACE("push eax");
PUSH(cpu->eax); break;
case 0x51:
PUSH(cpu->ecx,32); break;
TRACE("push ecx");
PUSH(cpu->ecx); break;
case 0x52:
PUSH(cpu->edx,32); break;
TRACE("push edx");
PUSH(cpu->edx); break;
case 0x53:
PUSH(cpu->ebx,32); break;
TRACE("push ebx");
PUSH(cpu->ebx); break;
case 0x54: {
TRACE("push esp");
// need to make sure to push the old value
dword_t old_esp = cpu->esp;
PUSH(old_esp, 32);
PUSH(old_esp);
break;
}
case 0x55:
PUSH(cpu->ebp,32); break;
TRACE("push ebp");
PUSH(cpu->ebp); break;
case 0x56:
PUSH(cpu->esi,32); break;
TRACE("push esi");
PUSH(cpu->esi); break;
case 0x57:
PUSH(cpu->edi,32); break;
TRACE("push edi");
PUSH(cpu->edi); break;

// operand size prefix
case 0x66:
#if OP_SIZE == 32
TRACE("entering 16 bit mode");
return cpu_step16(cpu);
#else
TRACE("entering 32 bit mode");
return cpu_step32(cpu);
#endif

// move register to dword modrm
case 0x89: {
// subtract dword immediate byte from modrm
case 0x83:
TRACE("sub imm, modrm");
DECODE_MODRM(32);
READIMM8;
// must cast to a signed value so sign extension occurs
MODRM_VAL -= (int8_t) imm8;
break;

// move dword register to dword modrm
case 0x89:
TRACE("mov reg, modrm");
DECODE_MODRM(32);
MODRM_VAL = REGPTR(modrm.reg);
break;

// lea dword modrm to register
case 0x8d:
TRACE("lea modrm, reg");
DECODE_MODRM(32);
if (modrm.type == mod_reg) {
REGPTR(modrm.modrm_reg,32) = REGPTR(modrm.reg,32);
} else {
MEM(modrm_addr,32) = REGPTR(modrm.reg,32);
return INT_UNDEFINED;
}
REGPTR(modrm.reg) = modrm_addr;
break;
}

// move dword immediate to register
case 0xb8:
TRACE("mov immediate, eax");
READIMM; cpu->eax = imm; break;
case 0xb9:
TRACE("mov immediate, ecx");
READIMM; cpu->ecx = imm; break;
case 0xba:
TRACE("mov immediate, edx");
READIMM; cpu->edx = imm; break;
case 0xbb:
TRACE("mov immediate, ebx");
READIMM; cpu->ebx = imm; break;
case 0xbc:
TRACE("mov immediate, esp");
READIMM; cpu->esp = imm; break;
case 0xbd:
TRACE("mov immediate, ebx");
READIMM; cpu->ebx = imm; break;
case 0xbe:
TRACE("mov immediate, ebx");
READIMM; cpu->ebx = imm; break;
case 0xbf:
TRACE("mov immediate, ebx");
READIMM; cpu->ebx = imm; break;

case 0xcd:
TRACE("interrupt");
READIMM8; return imm8;

// move byte immediate to modrm
case 0xc6:
TRACE("mov imm8, modrm8");
DECODE_MODRM(32);
READIMM8; MODRM_VAL = imm8;
break;
// move dword immediate to modrm
case 0xc7:
TRACE("mov imm, modrm");
DECODE_MODRM(32);
READIMM; MODRM_VAL = imm;
break;

default:
TRACE("undefined");
debugger;
return INT_UNDEFINED;
}
return 0;
trace_cpu(cpu);
return -1; // everything is ok.
}

#ifndef AGAIN
#define AGAIN

#undef OP_SIZE
#define OP_SIZE 16
#include "cpu.c"

void cpu_run(struct cpu_state *cpu) {
while (true) {
int interrupt = cpu_step(cpu);
int interrupt = cpu_step32(cpu);
if (interrupt != INT_NONE) {
TRACE("interrupt %d", interrupt);
/* handle_interrupt(interrupt); */
return;
}
}
}

#endif
51 changes: 47 additions & 4 deletions emu/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@
#define EMU_H

#include <stddef.h>
#include "emu/types.h"
#include "misc.h"
#include "emu/memory.h"

struct cpu_state;
void cpu_run(struct cpu_state *cpu);
int cpu_step32(struct cpu_state *cpu);
int cpu_step16(struct cpu_state *cpu);

struct cpu_state {
pagetable pt;

Expand Down Expand Up @@ -45,10 +50,48 @@ struct cpu_state {

typedef uint8_t reg_id_t;
#define REG_ID(reg) offsetof(struct cpu_state, reg)
#define REG_VAL(cpu, reg_id, size) (*((uint##size##_t *) (((char *) (cpu)) + reg_id)))
#define REG_VAL(cpu, reg_id, size) (*((UINT(size) *) (((char *) (cpu)) + reg_id)))
inline const char *reg8_name(uint8_t reg_id) {
switch (reg_id) {
case REG_ID(al): return "al";
case REG_ID(bl): return "bl";
case REG_ID(cl): return "cl";
case REG_ID(dl): return "dl";
case REG_ID(ah): return "ah";
case REG_ID(bh): return "bh";
case REG_ID(ch): return "ch";
case REG_ID(dh): return "dh";
}
return "??";
}
inline const char *reg16_name(uint8_t reg_id) {
switch (reg_id) {
case REG_ID(ax): return "ax";
case REG_ID(bx): return "bx";
case REG_ID(cx): return "cx";
case REG_ID(dx): return "dx";
case REG_ID(si): return "si";
case REG_ID(di): return "di";
case REG_ID(bp): return "bp";
case REG_ID(sp): return "sp";
}
return "??";
}
inline const char *reg32_name(uint8_t reg_id) {
switch (reg_id) {
case REG_ID(eax): return "eax";
case REG_ID(ebx): return "ebx";
case REG_ID(ecx): return "ecx";
case REG_ID(edx): return "edx";
case REG_ID(esi): return "esi";
case REG_ID(edi): return "edi";
case REG_ID(ebp): return "ebp";
case REG_ID(esp): return "esp";
}
return "???";
}

#define MEM_GET(cpu, addr, size) (((uint##size##_t *) cpu->pt[PAGE_ADDR(addr)]->data) [OFFSET_ADDR(addr)])
#define MEM_GET(cpu, addr, size) (*((UINT(size) *) &((char *) cpu->pt[PAGE_ADDR(addr)]->data)[OFFSET_ADDR(addr)]))

void cpu_run(struct cpu_state *cpu);

#endif
6 changes: 6 additions & 0 deletions emu/debug.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include "emu/cpu.h"
#include "emu/modrm.h"
extern inline const char *reg8_name(uint8_t reg_id);
extern inline const char *reg16_name(uint8_t reg_id);
extern inline const char *reg32_name(uint8_t reg_id);
extern inline const char *regptr_name(struct regptr regptr);
4 changes: 2 additions & 2 deletions emu/interrupt.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#define INT_BREAKPOINT 3
#define INT_OVERFLOW 4
#define INT_BOUND 5
#define INT_INVALID 6
#define INT_FPU 7 // apparently "device not available"
#define INT_UNDEFINED 6
#define INT_FPU 7 // do not try to use the fpu. instead, try to realize the truth: there is no fpu.
#define INT_DOUBLE 8 // interrupt during interrupt, i.e. interruptception
#define INT_SYSCALL 0x80
2 changes: 1 addition & 1 deletion emu/memory.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#ifndef MEMORY_H
#define MEMORY_H

#include "emu/types.h"
#include "misc.h"
#include <unistd.h>

#define PAGE_BITS 12
Expand Down
Loading

0 comments on commit 4455edd

Please sign in to comment.