⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dyn_arm_emul.cpp

📁 arm的模拟器
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/*************************************************************************    Copyright (C) 2002 - 2007 Wei Qin    See file COPYING for more information.    This program is free software; you can redistribute it and/or modify        it under the terms of the GNU General Public License as published by    the Free Software Foundation; either version 2 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.*************************************************************************/#include <cstdlib>#include <cstdio>#include <pthread.h>#include <dlfcn.h>#include <unistd.h>#include <sys/stat.h>#include <sys/types.h>#include <fcntl.h>#include <cassert>#include <list>#include <map>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <pthread.h>#include <errno.h>#include "dyn_arm_emul.hpp"#include "armmmu.h"#include "arm_io.h"#include "armcopro.h"#include "build_dll.hpp"using std::list;using std::map;using std::multimap;using std::pair;using namespace simit;typedef arm_emulator emulator_t;typedef arm_inst_t target_inst_t;typedef arm_addr_t target_addr_t;#define PID_LIST  reinterpret_cast<list<unsigned> *>(pid_list)#define DLL_INFO  reinterpret_cast<map<fptr_t, dll_info_t *> *>(dll_info)#define DLL_INFO2 reinterpret_cast<map<unsigned, dll_info_t *> *>(dll_info2)#define DLL_DICT  reinterpret_cast<multimap<unsigned, unsigned> *>(dll_dict)/* Two types of simulation are implemented, interpretation and translation.   The user level interpretation routines here are identical to those   in the emulator directory. However, the system-level interpretation   routines are slightly different. They must take into account   self-modifying code. If a MEM_WRITE_* modifies a compiled address,   the corresponding DLL must be unloaded.    The translated code is very different from the interpretation code.   For user-level translation, care must be taken on WRITE_REG. If   an instruction writes to register 15, then it is a jump instruction.   The WRITE_REG should be translated into a goto or a return, depending on   whether the target address is within the same translation block.   Therefore, the WRITE_REG macro must be redefined to check if the   destination is 15. If so, it will jump immediately. A prerequisite   for this to work is that an instruction can only modify the PC in   its last statement. Otherwise some effects of the instruction will   be lost. Fortunately, the requirement can be satisfied for all ARM   instructions. See arm.isa file for details.   For system-level translation, additional care is given to memory write   instructions due to the existence of self-modifying code. If a   write modifies a compiled block. Then the compiled block should   be invalidated immediately. Since in theory an instruction may modify   itself, the invalidation cannot be done by the instruction itself.   (I don't think a DLL can unload itself.) Therefore, the instruction   must abort to the main execution loop, which will unload the compiled   DLL, and then restart the instruction. A prerequisite for this to   work is that all memory write instructions can restart. Fortunately,   the requirement can be satisfied under the base-register restore   abort model. See arm.isa for details.*/static const uint16_t cond_table[] ={0xf0f0, 0x0f0f, 0xcccc, 0x3333, 0xff00, 0x00ff, 0xaaaa, 0x5555, 0x0c0c, 0xf3f3, 0xaa55, 0x55aa, 0x0a05, 0xf5fa, 0xffff, 0x0000};static inline uint32_t eval_cond(arm_emulator *emu, arm_inst_t inst){	uint32_t val;	val = (cond_table[COND] >> CC) & 1;#if 0	switch (COND) {		case 0: val = Z_FLAG; break;		case 1: val = !Z_FLAG; break;		case 2: val = C_FLAG; break;		case 3: val = !C_FLAG; break;		case 4: val = N_FLAG; break;		case 5: val = !N_FLAG; break;		case 6: val = V_FLAG; break;		case 7: val = !V_FLAG; break;		case 8: val = C_FLAG & ~Z_FLAG; break;		case 9: val = !(C_FLAG & ~Z_FLAG); break;		case 10: val = N_FLAG == V_FLAG; break;		case 11: val = N_FLAG ^ V_FLAG; break;		case 12: val = !(Z_FLAG | (N_FLAG ^ V_FLAG)); break;		case 13: val = Z_FLAG | (N_FLAG ^ V_FLAG); break;		case 14: val = 1; break;		default: val = 0; break;	}#endif	return val;}static bool write_check(void *e, arm_addr_t addr){	dyn_arm_emulator *emu = reinterpret_cast<dyn_arm_emulator *>(e);	return emu->check_write_range(addr, ~MMU_HASH_MASK + 1);}static bool write_alarm(void *e, arm_addr_t addr){	dyn_arm_emulator *emu = reinterpret_cast<dyn_arm_emulator *>(e);	if (emu->check_write(addr))	{		emu->set_invalidate_flag(addr);		return true;	}	return false;}/* constructor */dyn_arm_emulator::dyn_arm_emulator(bool verbose, bool showmsg,	bool user_level, uint32_t thr, uint32_t blkbits) :	arm_emulator(verbose, user_level), threshold(thr),	shiftval(blkbits), showmsg(showmsg){	/* limit threshold so that blk count never reaches -1u, -1u	 * is a special value meaning that the block is awaiting compilation	 */	if (threshold > -3u) threshold = -3u;	/* limit shiftval so that the blk_info table is not too big */	if (shiftval < 9) shiftval = 9;	/* for system level, the blk size should be no bigger than 1K, the	   size of a tiny page for ARM.	 */	if (!user_level && shiftval > 10) shiftval = 10;	inval_flag = false;	inval_addr = 0;	hit_num = 0;	req_num = 0;	dll_ind = 0;	cache_dir = NULL;	pid_list = reinterpret_cast<void *>(new list<unsigned>);	blk_info = (blk_info_t *)calloc(1 << (32 - shiftval), sizeof(blk_info_t));	dll_info = reinterpret_cast<void *>(new map<fptr_t, dll_info_t *>);	dll_info2= reinterpret_cast<void *>(new map<unsigned, dll_info_t *>);	dll_dict = reinterpret_cast<void *>(new multimap<unsigned, unsigned>);	srv_count = 0;	srv_index = 0;	com_done = false;	memset(srv_dir, 0, sizeof(srv_dir));	pthread_cond_init(&pid_cond, NULL);	pthread_mutex_init(&pid_mut, NULL);	pthread_mutex_init(&srv_mut, NULL);	temp_buf1 = (byte_t*)malloc(1 << shiftval);	temp_buf2 = (byte_t*)malloc(1 << shiftval);	if (blk_info==NULL || dll_info==NULL || dll_info2==NULL ||		dll_dict==NULL || temp_buf1==NULL || temp_buf2==NULL)	{		fprintf(stderr, "Error: Insufficient memory.\n");		exit(1);	}	if (!user_level)		mmu->register_write_checker(this, write_check, write_alarm);}/* destructor */dyn_arm_emulator::~dyn_arm_emulator(){	// close all dll libraries	map<fptr_t, dll_info_t *>::iterator mit;	for (mit = DLL_INFO->begin(); mit != DLL_INFO->end(); mit++)	{		dll_info_t *pdll = (*mit).second;		dlclose(pdll->handle);		free(pdll);	}	delete DLL_INFO;	delete DLL_INFO2;	delete DLL_DICT;	delete PID_LIST;	free(blk_info);	free(temp_buf1);	free(temp_buf2);	if (cache_dir) free(cache_dir);	com_cleanup();}/* The impl_xxxx routines for system level simulation is duplicated * in jit directory (in arm_iss_jit.cpp). When linking, ld will choose * those in arm_iss_jit.o instead of those in libarmemu.a since arm_iss_jit * appears first. The difference between the two is check_write. */#define  SIMIT_SYSTEM_LEVEL#include "auto_impl.h" #include "arm_iss.hpp"#include "arm_dec.h"void dyn_arm_emulator::execute_system(arm_inst_t inst, word_t addr){	/* set default next PC; operation can override */	write_gpr2(PC_REAL_IND, addr+4);	if (COND == 0xe || eval_cond(this, inst)) {		/*operation sees PC+8*/		write_gpr2(PC_AHEAD_IND, addr+8);		decode_main_system(this, inst);	}}/* The uimpl_xxxx routines are those in libarmemu.a */#undef   SIMIT_SYSTEM_LEVEL#include "auto_impl.h" #include "arm_iss.hpp"#include "arm_dec.h"void dyn_arm_emulator::execute_user(arm_inst_t inst, word_t addr){	/* set default next PC; operation can override */	write_gpr2(PC_REAL_IND, addr+4);	if (COND == 0xe || eval_cond(this, inst)) {		/*operation sees PC+8*/		write_gpr2(PC_AHEAD_IND, addr+8);		decode_main_user(this, inst);	}}void dyn_arm_emulator::step_system(){	arm_addr_t phy_addr;	arm_inst_t  inst;	byte_t *ptr;	//  if (EventSet)	//	  EnvokeEvent();	if (SigSet)	{		/* Any exceptions ?  */		if (!NresetSig)		{			raise_exception(ResetV);			return;		}		else if ((!NfiqSig) && (!my_regs.f_flag))		{			raise_exception(FIQV);			return;		}		else if ((!NirqSig) && (!my_regs.i_flag))		{			raise_exception(IRQV);			return;		}	}	if (pcount <= 0)	{		/* the compile_count includes interpret_count,		   adjust at the end of the function */		io->do_cycle();		icount += prescale - pcount;		pcount = prescale;			if (max_count_set && icount >= max_count)			status = ST_EXIT; 	}#ifdef SINGLESTEPif (icount > (30*(1<<20) + 585300) && icount < (30*(1<<20) + 585360)){unsigned sum = 0;for (int ii=0; ii<15; ii++) sum += read_gpr(ii);fprintf(stderr, "=%x %x %x\n", get_pc(), sum, read_cpsr());}#endif	/* see if the current PC can be loaded */	if (mmu->translate_instr_addr(get_pc(), &phy_addr, &ptr)) 	{		abort_addr = get_pc();		inst = ABORTWORD;		execute_system(inst, get_pc()); 		pcount--;	}	else 	{		unsigned ind = phy_addr >> shiftval;#ifdef SINGLESTEPL1:#endif		if (blk_info[ind].dll_fptr)		{			int oldpcount = pcount;			cc_to_cfs();			(*(blk_info[ind].dll_fptr))(this, get_pc());			cfs_to_cc();#ifdef SINGLESTEP //debug			pcount--;#endif			increment_compile_count(oldpcount - pcount);		}		else 		{			if (blk_info[ind].count > threshold)			{				if (blk_info[ind].count != -1u) 				{					req_num++;					build_andor_load_lib(ind);#ifdef SINGLESTEP					goto L1;#endif					return;				}			}			else				blk_info[ind].count++;			if (ptr)				DIRECT_READ_WORD(ptr,inst);			else				mem->read_word(phy_addr, &inst);			execute_system(inst, get_pc()); 			pcount--;		}	}	/* if invalidation occurs */	if (inval_flag)	{		unload_lib(inval_addr >> shiftval);		if (showmsg) fprintf(stderr, "invalidate %x\n", inval_addr);		inval_flag = false;	}}void dyn_arm_emulator::step_user(){	arm_inst_t  inst;	unsigned ind;	ind = get_pc() >> shiftval;	if (blk_info[ind].dll_fptr)	{		cc_to_cfs();		while (blk_info[ind].dll_fptr && status==ST_RUNNING)		{			(*(blk_info[ind].dll_fptr))(this, get_pc());			ind = get_pc() >> shiftval;		}		cfs_to_cc();		return;	}	else if(blk_info[ind].count > threshold) 	{		if (blk_info[ind].count != -1u) 		{			req_num++;			build_andor_load_lib(ind);			return;		}	}	else		blk_info[ind].count++;	inst = fetch_inst_user(get_pc());	execute_user(inst, get_pc()); 	icount++;}uint64_t dyn_arm_emulator::run_system(){	icount = 0;	ccount = 0;	pcount = prescale;	status = ST_RUNNING;	while (status==ST_RUNNING)		step_system();	com_done = true;	pthread_cond_broadcast(&pid_cond);	increment_interpret_count(prescale - pcount);	icount -= ccount;	// icount includes ccount;	return icount + ccount;}uint64_t dyn_arm_emulator::run_user(){	icount = 0;	ccount = 0;	status = ST_RUNNING;	while(status==ST_RUNNING)		step_user();	com_done = true;	pthread_cond_broadcast(&pid_cond);	return icount + ccount;}uint64_t dyn_arm_emulator::run(){	max_count_set = (max_count != (uint64_t)-1);	if (user_level) 		return run_user();	else 		return run_system();}/* this is called by the communication thread */void dyn_arm_emulator::get_block_to_compile(unsigned *dll, unsigned *pblk){	pthread_mutex_lock(&pid_mut);	while (PID_LIST->empty() && !com_done)		pthread_cond_wait(&pid_cond, &pid_mut);	// thr_inds acts as a FIFO, can use stack style by popping the back	if (!com_done)	{		*pblk = PID_LIST->front();		PID_LIST->pop_front();		*dll = dll_ind++;	}	pthread_mutex_unlock(&pid_mut);}unsigned dyn_arm_emulator::lookup_dict(byte_t *buf, unsigned *pcrc){	/* compute checksum first */	unsigned crc = 0;	for (unsigned curpc = 0; curpc < (1u << shiftval); curpc+=4)	{		target_inst_t inst;		DIRECT_READ_WORD(buf + curpc, inst);		crc += inst;	}	if (pcrc) *pcrc = crc;	char fname[1024];	/* need to lock this region since temp_buf2 is shared. Also	 * DLL_DICT may not be thread safe, some one may be updating it */	pthread_mutex_lock(&srv_mut);	/* we compute check sum first to see if this is in cache */	if (DLL_DICT->find(crc) != DLL_DICT->end())	{		pair<multimap<unsigned, unsigned>::iterator,			 multimap<unsigned, unsigned>::iterator> ii;		ii = DLL_DICT->equal_range(crc);		/* lets compare the content of the files */		multimap<unsigned, unsigned>::iterator nit;		for (nit=ii.first; nit!=ii.second; nit++)		{			sprintf(fname,"%s/Xcompiled_%u.dat", cache_dir, (*nit).second);			FILE *fp = fopen(fname, "rb");			if (fp == NULL) /* possibly corrupted cache */			{				DLL_DICT->erase(nit);				continue;			}			/* something is wrong */			if (fread(temp_buf2, 1, 1 << shiftval, fp) != (1u << shiftval))			{				DLL_DICT->erase(nit);				fclose(fp);			}			else if (memcmp(buf, temp_buf2, 1 << shiftval) == 0)			{				pthread_mutex_unlock(&srv_mut);				if (showmsg)					fprintf(stderr, "Found DLL in cache %s.\n", fname);				hit_num++;				fclose(fp);				return (*nit).second;			}		}	}	pthread_mutex_unlock(&srv_mut);	return -1u;}void dyn_arm_emulator::build_andor_load_lib(unsigned pblk){	/* mark the block as in compilation */	blk_info[pblk].count = -1u;	/* remove mmu translation cache entry*/	mmu->invalidate_write_cache(get_pc());	/* if threads are ready, send the task for communication threads */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -