More real ELF loading and brk handling; more tests pass.
This commit is contained in:
parent
396795105f
commit
2682c125e0
|
@ -1,6 +1,8 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -13,12 +15,11 @@ void disassemble_program();
|
||||||
#define RAM_BASE 0x08000000
|
#define RAM_BASE 0x08000000
|
||||||
#define RAM_TOP 0x08100000
|
#define RAM_TOP 0x08100000
|
||||||
|
|
||||||
|
#define BRK_TOP (RAM_TOP - 0x1000)
|
||||||
|
|
||||||
#define INIT_SP RAM_TOP
|
#define INIT_SP RAM_TOP
|
||||||
#define INIT_PC 0x08000054
|
#define INIT_PC 0x08000054
|
||||||
|
|
||||||
#define BRK_BOTTOM (RAM_BASE + 0x20000)
|
|
||||||
#define BRK_TOP (RAM_TOP - 0x1000)
|
|
||||||
|
|
||||||
/* Read/write macros */
|
/* Read/write macros */
|
||||||
#define READ_BYTE(BASE, ADDR) (BASE)[ADDR]
|
#define READ_BYTE(BASE, ADDR) (BASE)[ADDR]
|
||||||
#define READ_WORD(BASE, ADDR) (((BASE)[ADDR]<<8) | \
|
#define READ_WORD(BASE, ADDR) (((BASE)[ADDR]<<8) | \
|
||||||
|
@ -40,23 +41,24 @@ void disassemble_program();
|
||||||
static void exit_error(char* fmt, ...);
|
static void exit_error(char* fmt, ...);
|
||||||
static void emulated_syscall(void);
|
static void emulated_syscall(void);
|
||||||
|
|
||||||
unsigned int cpu_read_byte(unsigned int address);
|
uint32_t cpu_read_byte(uint32_t address);
|
||||||
unsigned int cpu_read_word(unsigned int address);
|
uint32_t cpu_read_word(uint32_t address);
|
||||||
unsigned int cpu_read_long(unsigned int address);
|
uint32_t cpu_read_long(uint32_t address);
|
||||||
void cpu_write_byte(unsigned int address, unsigned int value);
|
void cpu_write_byte(uint32_t address, uint32_t value);
|
||||||
void cpu_write_word(unsigned int address, unsigned int value);
|
void cpu_write_word(uint32_t address, uint32_t value);
|
||||||
void cpu_write_long(unsigned int address, unsigned int value);
|
void cpu_write_long(uint32_t address, uint32_t value);
|
||||||
|
|
||||||
unsigned char g_ram[RAM_TOP - RAM_BASE];
|
unsigned char g_ram[RAM_TOP - RAM_BASE];
|
||||||
unsigned int brkpos = BRK_BOTTOM;
|
uint32_t brkbase = RAM_BASE;
|
||||||
|
uint32_t brkpos = RAM_BASE;
|
||||||
|
uint32_t entrypoint = RAM_BASE;
|
||||||
|
|
||||||
/* Exit with an error message. Use printf syntax. */
|
/* Exit with an error message. Use printf syntax. */
|
||||||
void exit_error(char* fmt, ...)
|
void exit_error(char* fmt, ...)
|
||||||
{
|
{
|
||||||
static int guard_val = 0;
|
static int guard_val = 0;
|
||||||
char buff[100];
|
char buff[100];
|
||||||
unsigned int pc;
|
uint32_t pc;
|
||||||
va_list args;
|
va_list args;
|
||||||
|
|
||||||
if(guard_val)
|
if(guard_val)
|
||||||
|
@ -75,71 +77,78 @@ void exit_error(char* fmt, ...)
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned int transform_address(unsigned int address)
|
static inline uint32_t transform_address(uint32_t address)
|
||||||
{
|
{
|
||||||
unsigned int i = (address & ADDRESS_MASK) - RAM_BASE;
|
uint32_t i = (address & ADDRESS_MASK) - RAM_BASE;
|
||||||
if (i >= (unsigned int)(RAM_TOP - RAM_BASE))
|
if (i >= (uint32_t)(RAM_TOP - RAM_BASE))
|
||||||
exit_error("Attempted to read from RAM address %08x", address);
|
exit_error("Attempted to read from RAM address %08x", address);
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int cpu_read_long(unsigned int address)
|
uint32_t cpu_read_long(uint32_t address)
|
||||||
{
|
{
|
||||||
switch (address)
|
switch (address)
|
||||||
{
|
{
|
||||||
case 0x00: return INIT_SP;
|
case 0x00: return INIT_SP;
|
||||||
case 0x04: return INIT_PC;
|
case 0x04: return entrypoint;
|
||||||
case 0x80: emulated_syscall(); return 0x10000;
|
case 0x80: emulated_syscall(); return 0x10000;
|
||||||
case 0x10000: return 0x4e734e73; /* rte; rte */
|
case 0x10000: return 0x4e734e73; /* rte; rte */
|
||||||
case 0x10004: return 0;
|
case 0x10004: return 0;
|
||||||
default: return READ_LONG(g_ram, transform_address(address));
|
default:
|
||||||
|
{
|
||||||
|
uint32_t value = READ_LONG(g_ram, transform_address(address));
|
||||||
|
#if 0
|
||||||
|
printf("read %08x from %08x\n", value, address);
|
||||||
|
#endif
|
||||||
|
return value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned int cpu_read_word(unsigned int address)
|
uint32_t cpu_read_word(uint32_t address)
|
||||||
{
|
{
|
||||||
unsigned int l = cpu_read_long(address & ~3);
|
uint32_t l = cpu_read_long(address & ~3);
|
||||||
l >>= 16 - (address & 2)*8;
|
l >>= 16 - (address & 2)*8;
|
||||||
return l & 0xffff;
|
return l & 0xffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int cpu_read_byte(unsigned int address)
|
uint32_t cpu_read_byte(uint32_t address)
|
||||||
{
|
{
|
||||||
unsigned int l = cpu_read_long(address & ~3);
|
uint32_t l = cpu_read_long(address & ~3);
|
||||||
l >>= 24 - (address & 3)*8;
|
l >>= 24 - (address & 3)*8;
|
||||||
return l & 0xff;
|
return l & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int cpu_read_word_dasm(unsigned int address)
|
uint32_t cpu_read_word_dasm(uint32_t address)
|
||||||
{
|
{
|
||||||
return cpu_read_word(address);
|
return cpu_read_word(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int cpu_read_long_dasm(unsigned int address)
|
uint32_t cpu_read_long_dasm(uint32_t address)
|
||||||
{
|
{
|
||||||
return cpu_read_long(address);
|
return cpu_read_long(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Write data to RAM or a device */
|
/* Write data to RAM or a device */
|
||||||
void cpu_write_byte(unsigned int address, unsigned int value)
|
void cpu_write_byte(uint32_t address, uint32_t value)
|
||||||
{
|
{
|
||||||
WRITE_BYTE(g_ram, transform_address(address), value);
|
WRITE_BYTE(g_ram, transform_address(address), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpu_write_word(unsigned int address, unsigned int value)
|
void cpu_write_word(uint32_t address, uint32_t value)
|
||||||
{
|
{
|
||||||
WRITE_WORD(g_ram, transform_address(address), value);
|
WRITE_WORD(g_ram, transform_address(address), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpu_write_long(unsigned int address, unsigned int value)
|
void cpu_write_long(uint32_t address, uint32_t value)
|
||||||
{
|
{
|
||||||
WRITE_LONG(g_ram, transform_address(address), value);
|
WRITE_LONG(g_ram, transform_address(address), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disassembler */
|
/* Disassembler */
|
||||||
void make_hex(char* buff, unsigned int pc, unsigned int length)
|
void make_hex(char* buff, uint32_t pc, uint32_t length)
|
||||||
{
|
{
|
||||||
char* ptr = buff;
|
char* ptr = buff;
|
||||||
|
|
||||||
|
@ -155,8 +164,8 @@ void make_hex(char* buff, unsigned int pc, unsigned int length)
|
||||||
|
|
||||||
void disassemble_program()
|
void disassemble_program()
|
||||||
{
|
{
|
||||||
unsigned int pc;
|
uint32_t pc;
|
||||||
unsigned int instr_size;
|
uint32_t instr_size;
|
||||||
char buff[100];
|
char buff[100];
|
||||||
char buff2[100];
|
char buff2[100];
|
||||||
|
|
||||||
|
@ -174,7 +183,7 @@ void disassemble_program()
|
||||||
|
|
||||||
void cpu_instr_callback()
|
void cpu_instr_callback()
|
||||||
{
|
{
|
||||||
unsigned int pc = m68k_get_reg(NULL, M68K_REG_PC);
|
uint32_t pc = m68k_get_reg(NULL, M68K_REG_PC);
|
||||||
if (pc == 0xc)
|
if (pc == 0xc)
|
||||||
exit_error("address exception");
|
exit_error("address exception");
|
||||||
|
|
||||||
|
@ -183,7 +192,7 @@ void cpu_instr_callback()
|
||||||
#if 0
|
#if 0
|
||||||
static char buff[100];
|
static char buff[100];
|
||||||
static char buff2[100];
|
static char buff2[100];
|
||||||
static unsigned int instr_size;
|
static uint32_t instr_size;
|
||||||
|
|
||||||
instr_size = m68k_disassemble(buff, pc, M68K_CPU_TYPE_68020);
|
instr_size = m68k_disassemble(buff, pc, M68K_CPU_TYPE_68020);
|
||||||
make_hex(buff2, pc, instr_size);
|
make_hex(buff2, pc, instr_size);
|
||||||
|
@ -220,19 +229,19 @@ static void emulated_syscall(void)
|
||||||
|
|
||||||
case 4: /* write */
|
case 4: /* write */
|
||||||
{
|
{
|
||||||
unsigned int fd = m68k_get_reg(NULL, M68K_REG_D1);
|
uint32_t fd = m68k_get_reg(NULL, M68K_REG_D1);
|
||||||
unsigned int ptr = m68k_get_reg(NULL, M68K_REG_D2);
|
uint32_t ptr = m68k_get_reg(NULL, M68K_REG_D2);
|
||||||
unsigned int len = m68k_get_reg(NULL, M68K_REG_D3);
|
uint32_t len = m68k_get_reg(NULL, M68K_REG_D3);
|
||||||
m68k_set_reg(M68K_REG_D0, write(fd, g_ram + transform_address(ptr), len));
|
m68k_set_reg(M68K_REG_D0, write(fd, g_ram + transform_address(ptr), len));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 45: /* brk */
|
case 45: /* brk */
|
||||||
{
|
{
|
||||||
unsigned int newpos = m68k_get_reg(NULL, M68K_REG_D1);
|
uint32_t newpos = m68k_get_reg(NULL, M68K_REG_D1);
|
||||||
if (newpos == 0)
|
if (newpos == 0)
|
||||||
m68k_set_reg(M68K_REG_D0, brkpos);
|
m68k_set_reg(M68K_REG_D0, brkpos);
|
||||||
else if ((newpos < BRK_BOTTOM) || (newpos >= BRK_TOP))
|
else if ((newpos < brkbase) || (newpos >= BRK_TOP))
|
||||||
m68k_set_reg(M68K_REG_D0, -ENOMEM);
|
m68k_set_reg(M68K_REG_D0, -ENOMEM);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -251,6 +260,37 @@ static void emulated_syscall(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void load_program(FILE* fd)
|
||||||
|
{
|
||||||
|
fseek(fd, 0, SEEK_SET);
|
||||||
|
if (fread(g_ram, 1, 0x34, fd) != 0x34)
|
||||||
|
exit_error("couldn't read ELF header");
|
||||||
|
|
||||||
|
uint32_t phoff = READ_LONG(g_ram, 0x1c);
|
||||||
|
uint16_t phentsize = READ_WORD(g_ram, 0x2a);
|
||||||
|
uint16_t phnum = READ_WORD(g_ram, 0x2c);
|
||||||
|
entrypoint = READ_LONG(g_ram, 0x18);
|
||||||
|
if ((phentsize != 0x20) || (phnum != 1))
|
||||||
|
exit_error("unsupported ELF file");
|
||||||
|
|
||||||
|
fseek(fd, phoff, SEEK_SET);
|
||||||
|
if (fread(g_ram, 1, phentsize, fd) != phentsize)
|
||||||
|
exit_error("couldn't read program header");
|
||||||
|
|
||||||
|
uint32_t offset = READ_LONG(g_ram, 0x04);
|
||||||
|
uint32_t vaddr = READ_LONG(g_ram, 0x08);
|
||||||
|
uint32_t filesz = READ_LONG(g_ram, 0x10);
|
||||||
|
uint32_t memsz = READ_LONG(g_ram, 0x14);
|
||||||
|
brkbase = brkpos = vaddr + memsz;
|
||||||
|
|
||||||
|
uint32_t vaddroffset = transform_address(vaddr);
|
||||||
|
transform_address(vaddr + memsz); /* bounds check */
|
||||||
|
memset(g_ram+vaddroffset, 0, memsz);
|
||||||
|
fseek(fd, offset, SEEK_SET);
|
||||||
|
if (fread(g_ram+vaddroffset, 1, filesz, fd) != filesz)
|
||||||
|
exit_error("couldn't read program data");
|
||||||
|
}
|
||||||
|
|
||||||
/* The main loop */
|
/* The main loop */
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
@ -265,8 +305,7 @@ int main(int argc, char* argv[])
|
||||||
if((fhandle = fopen(argv[1], "rb")) == NULL)
|
if((fhandle = fopen(argv[1], "rb")) == NULL)
|
||||||
exit_error("Unable to open %s", argv[1]);
|
exit_error("Unable to open %s", argv[1]);
|
||||||
|
|
||||||
if(fread(g_ram, 1, RAM_TOP - RAM_BASE, fhandle) <= 0)
|
load_program(fhandle);
|
||||||
exit_error("Error reading %s", argv[1]);
|
|
||||||
|
|
||||||
// disassemble_program();
|
// disassemble_program();
|
||||||
|
|
||||||
|
@ -287,9 +326,9 @@ int main(int argc, char* argv[])
|
||||||
*/
|
*/
|
||||||
|
|
||||||
{
|
{
|
||||||
unsigned int sp = INIT_SP;
|
uint32_t sp = INIT_SP;
|
||||||
cpu_write_long(sp -= 4, 0);
|
cpu_write_long(sp -= 4, 0);
|
||||||
unsigned int envp = sp;
|
uint32_t envp = sp;
|
||||||
cpu_write_long(sp -= 4, envp);
|
cpu_write_long(sp -= 4, envp);
|
||||||
cpu_write_long(sp -= 4, 0);
|
cpu_write_long(sp -= 4, 0);
|
||||||
unsigned long argv = sp;
|
unsigned long argv = sp;
|
||||||
|
|
Loading…
Reference in a new issue