Skip to content

Commit

Permalink
Everything to get Hello World working
Browse files Browse the repository at this point in the history
on both gcc and clang!
  • Loading branch information
tbodt committed May 8, 2017
1 parent 4455edd commit 9b6eed2
Show file tree
Hide file tree
Showing 13 changed files with 215 additions and 71 deletions.
87 changes: 60 additions & 27 deletions emu/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "emu/cpu.h"
#include "emu/modrm.h"
#include "emu/interrupt.h"
#include "sys/calls.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",
Expand All @@ -24,35 +25,41 @@ static void trace_cpu(struct cpu_state *cpu) {
// 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) 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))
#define MEM_(addr,size) MEM_GET(cpu, addr, size)
#define MEM(addr) MEM_(addr,OP_SIZE)
#define MEM8(addr) MEM_(addr,8)
#define REG_(reg_id,size) REG_VAL(cpu, reg_id, size)
#define REG(reg_id) REG_(reg_id, OP_SIZE)
#define REGPTR_(regptr,size) REG_(CONCAT3(regptr.reg,size,_id),size)
#define REGPTR(regptr) REGPTR_(regptr, OP_SIZE)
#define REGPTR8(regptr) REGPTR_(regptr, 8)

// used by MODRM_MEM, don't use for anything else
struct modrm_info modrm;
dword_t modrm_addr;
dword_t addr;
#define DECODE_MODRM(size) \
modrm_decode##size(cpu, &modrm_addr, &modrm)
#define MODRM_VAL \
*(modrm.type == mod_reg ? &REGPTR(modrm.modrm_reg) : &MEM(modrm_addr))
modrm_decode##size(cpu, &addr, &modrm)
#define MODRM_VAL_(size) \
*(modrm.type == mod_reg ? &REGPTR_(modrm.modrm_reg, size) : &MEM_(addr, size))
#define MODRM_VAL MODRM_VAL_(OP_SIZE)
#define MODRM_VAL8 MODRM_VAL_(8)

#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)
word_t imm16;
dword_t imm32;
#define READIMM_(name,size) \
name = MEM_(cpu->eip,size); \
cpu->eip += size/8; \
TRACE("immediate: %x", name)
#define imm CONCAT(imm, OP_SIZE)
#define READIMM READIMM_(imm, OP_SIZE)
#define READIMM8 READIMM_(imm8, 8)
#define READADDR READIMM_(addr, 32)

// TODO use different registers in 16-bit mode

Expand Down Expand Up @@ -106,27 +113,54 @@ int cpu_step(struct cpu_state *cpu) {
// subtract dword immediate byte from modrm
case 0x83:
TRACE("sub imm, modrm");
DECODE_MODRM(32);
READIMM8;
DECODE_MODRM(32); READIMM8;
// must cast to a signed value so sign extension occurs
MODRM_VAL -= (int8_t) imm8;
break;

// move byte register to byte modrm
case 0x88:
TRACE("movb reg, modrm");
DECODE_MODRM(32);
MODRM_VAL8 = REGPTR8(modrm.reg);
break;

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

// move byte modrm to byte register
case 0x8a:
TRACE("mov modrm, reg");
DECODE_MODRM(32);
REGPTR8(modrm.reg) = MODRM_VAL8;
break;

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

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

// move *immediate to eax
case 0xa1:
TRACE("mov (immediate), eax");
READADDR;
cpu->eax = MEM(addr);
break;

// move dword immediate to register
Expand Down Expand Up @@ -162,14 +196,14 @@ int cpu_step(struct cpu_state *cpu) {
// move byte immediate to modrm
case 0xc6:
TRACE("mov imm8, modrm8");
DECODE_MODRM(32);
READIMM8; MODRM_VAL = imm8;
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;
DECODE_MODRM(32); READIMM;
MODRM_VAL = imm;
break;

default:
Expand All @@ -193,8 +227,7 @@ void cpu_run(struct cpu_state *cpu) {
int interrupt = cpu_step32(cpu);
if (interrupt != INT_NONE) {
TRACE("interrupt %d", interrupt);
/* handle_interrupt(interrupt); */
return;
handle_interrupt(cpu, interrupt);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion emu/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ inline const char *reg32_name(uint8_t reg_id) {
return "???";
}

#define MEM_GET(cpu, addr, size) (*((UINT(size) *) &((char *) 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)]))


#endif
4 changes: 2 additions & 2 deletions emu/memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

#define PAGE_BITS 12
typedef uint8_t page[1 << PAGE_BITS];
#define PAGE_ADDR(addr) (addr >> PAGE_BITS)
#define OFFSET_ADDR(addr) (addr & ~(UINT32_MAX << PAGE_BITS))
#define PAGE_ADDR(addr) ((addr) >> PAGE_BITS)
#define OFFSET_ADDR(addr) ((addr) & ~(UINT32_MAX << PAGE_BITS))

// flags
#define P_WRITABLE (1 << 1)
Expand Down
4 changes: 2 additions & 2 deletions emu/modrm.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ struct modrm_info modrm_compute_info(byte_t byte) {
// [reg], disp32, [sib]
info.type = mod_disp0;
switch (RM(byte)) {
case 0b011:
info.sib = true; break;
case 0b100:
info.sib = true; break;
case 0b101:
info.type = mod_disp32;
info.modrm_reg = (struct regptr) {0,0,0};
break;
Expand Down
8 changes: 4 additions & 4 deletions emu/modrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ struct regptr {
reg_id_t reg16_id;
reg_id_t reg32_id;
};
inline const char *regptr_name(struct regptr regptr) {
static const char *regptr_name(struct regptr regptr) {
static char buf[15];
sprintf(buf, "%s/%s/%s",
reg8_name(regptr.reg8_id),
Expand Down Expand Up @@ -39,7 +39,7 @@ struct modrm_info {
struct modrm_info modrm_compute_info(byte_t byte);
#else
struct modrm_info modrm_table[0x100];
inline struct modrm_info modrm_get_info(byte_t byte) {
static inline struct modrm_info modrm_get_info(byte_t byte) {
struct modrm_info info = modrm_table[byte];
TRACE_("modrm ");
TRACE_("reg %s opcode %d ", regptr_name(info.reg), info.opcode);
Expand Down Expand Up @@ -69,7 +69,7 @@ inline struct modrm_info modrm_get_info(byte_t byte) {
// Decodes ModR/M and SIB byte pointed to by cpu->eip, increments cpu->eip past
// them, and returns everything in out parameters.
// TODO currently only does 32-bit
inline void modrm_decode32(struct cpu_state *cpu, addr_t *addr_out, struct modrm_info *info_out) {
static inline void modrm_decode32(struct cpu_state *cpu, addr_t *addr_out, struct modrm_info *info_out) {
struct modrm_info info = modrm_get_info(MEM_GET(cpu, cpu->eip, 8));
cpu->eip++;
*info_out = info;
Expand All @@ -94,7 +94,7 @@ inline void modrm_decode32(struct cpu_state *cpu, addr_t *addr_out, struct modrm
break;
}
case mod_disp32: {
disp = (int8_t) MEM_GET(cpu, cpu->eip, 32);
disp = (int32_t) MEM_GET(cpu, cpu->eip, 32);
TRACE("disp %s0x%x", (disp < 0 ? "-" : ""), (disp < 0 ? -disp : disp));
*addr_out += disp;
cpu->eip += 4;
Expand Down
2 changes: 1 addition & 1 deletion main.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
int main(int argc, const char *argv[]) {
int err;
current = process_create();
if ((err = sys_execve(argv[1], argv + 1, NULL)) < 0) {
if ((err = sys_execve(argv[1], NULL, NULL)) < 0) {
return -err;
}
cpu_run(&current->cpu);
Expand Down
3 changes: 3 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ add_global_arguments('-std=gnu99', language: 'c')
includes = [include_directories('.')]

sys_src = [
'sys/calls.c',
'sys/exec/exec.c',
'sys/exit.c',
'sys/write.c',
]
emu_src = [
'emu/memory.c',
Expand Down
53 changes: 53 additions & 0 deletions sys/calls.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#include "emu/process.h"
#include "sys/calls.h"
#include "sys/errno.h"

syscall_t syscall_table[] = {
NULL, // 0
(syscall_t) sys_exit, // 1
NULL, // 2
NULL, // 3
(syscall_t) _sys_write, // 4
NULL, // 5
NULL, // 6
NULL, // 7
NULL, // 8
NULL, // 9
NULL, // 10
(syscall_t) _sys_execve, // 11
};

void handle_interrupt(struct cpu_state *cpu, int interrupt) {
if (interrupt == INT_SYSCALL) {
int syscall_num = cpu->eax;
int result;
if (syscall_num >= NUM_SYSCALLS || syscall_table[syscall_num] == NULL) {
result = _ENOSYS;
} else {
result = syscall_table[syscall_num](cpu->ebx, cpu->ecx, cpu->edx, cpu->esi, cpu->edi, cpu->ebp);
}
cpu->eax = result;
} else {
printf("interrupt %d, exiting\n", interrupt);
sys_exit(interrupt);
}
}

int user_get_string(addr_t addr, char *buf, size_t max) {
size_t i = 0;
while (i < max) {
buf[i] = MEM_GET(&current->cpu, addr + i, 8);
if (buf[i] == '\0') break;
i++;
}
return i;
}

int user_get_count(addr_t addr, char *buf, size_t count) {
size_t i = 0;
while (i < count) {
buf[i] = MEM_GET(&current->cpu, addr + i, 8);
i++;
}
return i;
}
19 changes: 19 additions & 0 deletions sys/calls.h
Original file line number Diff line number Diff line change
@@ -1 +1,20 @@
#include "emu/cpu.h"
#include "emu/interrupt.h"
#include "misc.h"

void handle_interrupt(struct cpu_state *cpu, int interrupt);

int user_get_string(addr_t addr, char *buf, size_t max);
int user_get_count(addr_t addr, char *buf, size_t count);

int sys_execve(const char *file, char *const argv[], char *const envp[]);
int _sys_execve(addr_t file, addr_t argv, addr_t envp);

int sys_exit(dword_t status);

ssize_t sys_write(int fd, const char *buf, size_t count);
dword_t _sys_write(dword_t fd, addr_t data, dword_t count);

typedef int (*syscall_t)(dword_t,dword_t,dword_t,dword_t,dword_t,dword_t);

#define NUM_SYSCALLS (sizeof(syscall_table)/sizeof(syscall_table[0]))
Loading

0 comments on commit 9b6eed2

Please sign in to comment.