More real ELF loading and brk handling; more tests pass.
This commit is contained in:
		
							parent
							
								
									396795105f
								
							
						
					
					
						commit
						2682c125e0
					
				
					 1 changed files with 80 additions and 41 deletions
				
			
		|  | @ -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: | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| unsigned int cpu_read_word(unsigned int address) |  | ||||||
| 		{ | 		{ | ||||||
| 	unsigned int l = cpu_read_long(address & ~3); | 			uint32_t value = READ_LONG(g_ram, transform_address(address)); | ||||||
|  | 			#if 0 | ||||||
|  | 			printf("read %08x from %08x\n", value, address); | ||||||
|  | 			#endif | ||||||
|  | 			return value; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | uint32_t cpu_read_word(uint32_t address) | ||||||
|  | { | ||||||
|  | 	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…
	
	Add table
		
		Reference in a new issue