diff --git a/.gitignore b/.gitignore index c042e43..57ec230 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,7 @@ *.i*86 *.x86_64 *.hex +*.bin # Debug files *.dSYM/ diff --git a/README.md b/README.md index 16c15bd..ac5a9f1 100644 --- a/README.md +++ b/README.md @@ -72,12 +72,43 @@ In my sophomore year, I took the CSE3666 course - Introduction to Computer Archi ### Is there a well-known open-source MIPS emulator project? Yes, there is. The famous PCSX2 is a free and open-source PlayStation 2 (PS2) emulator project. The processor inside the PS2 is based on MIPS Architecture. -### What big difference does this project make? -- It is the access-controlled memory-virtualization feature. +### What big difference does this project make in comparison to CSE3666 assignment? +- There is access-controlled memory-virtualization feature. - This project is written in C programming language. - This software is implemented by inspirations from AMD64 architecture. - This project aims to support more instructions. -- This project uses most techniques on optimizations. +- This project is designed to support multiple presets for simulation. With different preset, mipsivm may support multi-processing system. + +## Build +If it is your first time to build mipsivm, you will have execute `build_prep.bat` script file to prepare for compilation prior to execute any build scripts.
+Currently, mipsivm supports 64-bit Windows. + +### Windows +To build mipsivm for Windows, you will need to install [Windows Driver Kit 7.1.0](https://www.microsoft.com/en-us/download/details.aspx?id=11800) to default path on C drive. Compiler of WDK 7.1.0 can be considered as Visual C++ 2008 with a minor update.
+Execute `compchk_win7x64.bat` to compile mipsivm with `Debug/Checked` (unoptimized) compilation preset. + +## Command-Line Argument +Here list all command-line arguments. + +- `/nologo` suppresses the logo printer. +- `/runtime` specifies the runtime preset of MIPS Virtual Machine. Default runtime preset is `MARS`. + +Following runtime presets are available: + +### MARS Runtime Preset +MARS, acronym that stands for MIPS Assembler and Runtime Simulator, is an MIPS Assembly Development IDE written by Dr. Pete Sanderson and Dr.Ken Vollmar at Missouri State University. This preset would let mipsivm to simulate the MARS environment.
+MARS runtime preset simulates the program in user-mode. It is a uniprocessor preset - no multi-processing is available.
+Here list command-line arguments specific to MARS Runtime Preset. + +- `/ds` specifies the file path to `.data` section of program. +- `/ts` specifies the file path to `.text` section of program. +- `/ss` specifies the stack size in bytes for the program. Default stack size is 64KiB. + +### Example +``` +mipsivm /nologo /runtime mars /ds helloworld.data.bin /ts helloworld.text.bin +``` +This code would suppress the logo printer then load `helloworld.data.bin` as `.data` section and `helloworld.text.bin` as `.text` section of the program, with 64KiB stack, and run the program. ## License This repository is licensed under the MIT license. \ No newline at end of file diff --git a/build_prep.bat b/build_prep.bat new file mode 100644 index 0000000..358de23 --- /dev/null +++ b/build_prep.bat @@ -0,0 +1,14 @@ +@echo off + +title Compiling mipsivm, Checked Build, 64-Bit Windows (AMD64 Architecture) +echo Project: mipsivm +echo Platform: Universal +echo Preset: Preparation +pause + +mkdir .\bin +mkdir .\bin\compchk_win7x64 +mkdir .\bin\compchk_win7x64\Intermediate + +echo Completed! +pause. \ No newline at end of file diff --git a/compchk_win7x64.bat b/compchk_win7x64.bat index bfa2736..677c4e9 100644 --- a/compchk_win7x64.bat +++ b/compchk_win7x64.bat @@ -12,10 +12,14 @@ echo Preset: Debug/Checked Build pause echo ============Start Compiling============ +%ddkpath%\amd64\cl.exe .\src\xpf\windows\system.c /I"%incpath%\api" /I"%incpath%\crt" /I".\src\include" /Zi /nologo /W3 /WX /Od /D"_MBCS" /D"_WIN64" /D"_M_AMD64" /D"_AMD64_" /Zc:wchar_t /Zc:forScope /FAcs /Fa"%objpath%\system.cod" /Fo"%objpath%\system.obj" /Fd"%objpath%\vc90.pdb" /GS- /Gd /TC /c /errorReport:queue + %ddkpath%\amd64\cl.exe .\src\entry.c /I"%incpath%\api" /I"%incpath%\crt" /I".\src\include" /Zi /nologo /W3 /WX /Od /D"_msvc" /D"_amd64" /Zc:wchar_t /Zc:forScope /FAcs /Fa"%objpath%\entry.cod" /Fo"%objpath%\entry.obj" /Fd"%objpath%\vc90.pdb" /GS- /Gd /TC /c /errorReport:queue %ddkpath%\amd64\cl.exe .\src\vcpu.c /I".\src\include" /Zi /nologo /W3 /WX /Oi /Od /D"_msvc" /D"_amd64" /D"_mips_hvm" /Zc:wchar_t /Zc:forScope /FAcs /Fa"%objpath%\vcpu.cod" /Fo"%objpath%\vcpu.obj" /Fd"%objpath%\vc90.pdb" /GS- /Gd /TC /c /errorReport:queue +%ddkpath%\amd64\cl.exe .\src\mars.c /I".\src\include" /Zi /nologo /W3 /WX /Oi /Od /D"_msvc" /D"_amd64" /D"_mips_hvm_mars" /Zc:wchar_t /Zc:forScope /FAcs /Fa"%objpath%\mars.cod" /Fo"%objpath%\mars.obj" /Fd"%objpath%\vc90.pdb" /GS- /Gd /TC /c /errorReport:queue + %ddkpath%\amd64\cl.exe .\src\sim-r.c /I".\src\include" /Zi /nologo /W3 /WX /Oi /Od /D"_msvc" /D"_amd64" /D"_mips_simr" /Zc:wchar_t /Zc:forScope /FAcs /Fa"%objpath%\sim-r.cod" /Fo"%objpath%\sim-r.obj" /Fd"%objpath%\vc90.pdb" /GS- /Gd /TC /c /errorReport:queue %ddkpath%\amd64\cl.exe .\src\sim-i.c /I".\src\include" /Zi /nologo /W3 /WX /Oi /Od /D"_msvc" /D"_amd64" /D"_mips_simi" /Zc:wchar_t /Zc:forScope /FAcs /Fa"%objpath%\sim-i.cod" /Fo"%objpath%\sim-i.obj" /Fd"%objpath%\vc90.pdb" /GS- /Gd /TC /c /errorReport:queue @@ -23,6 +27,6 @@ echo ============Start Compiling============ %ddkpath%\amd64\cl.exe .\src\sim-j.c /I".\src\include" /Zi /nologo /W3 /WX /Oi /Od /D"_msvc" /D"_amd64" /D"_mips_simj" /Zc:wchar_t /Zc:forScope /FAcs /Fa"%objpath%\sim-j.cod" /Fo"%objpath%\sim-j.obj" /Fd"%objpath%\vc90.pdb" /GS- /Gd /TC /c /errorReport:queue echo ============Start Linking============ -%ddkpath%\amd64\link.exe "%objpath%\vcpu.obj" "%objpath%\entry.obj" "%objpath%\sim-r.obj" "%objpath%\sim-i.obj" "%objpath%\sim-j.obj" /LIBPATH:"%libpath%\win7\amd64" /LIBPATH:"%libpath%\Crt\amd64" /NODEFAULTLIB "msvcrt.lib" /NOLOGO /DEBUG /PDB:"%objpath%\mipsivm.pdb" /INCREMENTAL:NO /OUT:"%binpath%\mipsivm.exe" /SUBSYSTEM:CONSOLE /ENTRY:"main" /Machine:X64 /ERRORREPORT:QUEUE +%ddkpath%\amd64\link.exe "%objpath%\*.obj" /LIBPATH:"%libpath%\win7\amd64" /LIBPATH:"%libpath%\Crt\amd64" /NODEFAULTLIB "libcmt.lib" "msvcrt.lib" "kernel32.lib" /NOLOGO /DEBUG /PDB:"%objpath%\mipsivm.pdb" /INCREMENTAL:NO /OUT:"%binpath%\mipsivm.exe" /SUBSYSTEM:CONSOLE /Machine:X64 /ERRORREPORT:QUEUE pause \ No newline at end of file diff --git a/src/entry.c b/src/entry.c index ee6217b..dafcb98 100644 --- a/src/entry.c +++ b/src/entry.c @@ -16,10 +16,147 @@ #include #include #include +#include "include/midef.h" +#include "include/devkit.h" -void main() +void cdecl sim_printf(const char* format,...) { - printf("Welcome to mipsivm!\n"); - printf("Powered by Yaotian \"Zero\" Tang. All rights reserved.\n"); + va_list arg_list; + va_start(arg_list,format); + vprintf(format,arg_list); + va_end(arg_list); +} + +i32 sim_readint() +{ + int x=0; + scanf("%d",&x); + return x; +} + +float sim_readfloat() +{ + float x=0.0; + scanf("%f",&x); + return x; +} + +double sim_readdouble() +{ + double x=0.0; + scanf("%lf",&x); + return x; +} + +void sim_readstring(char* string,u32 limit) +{ + fgets(string,limit,stdin); +} + +char sim_readchar() +{ + return (char)getc(stdin); +} + +void sim_setseed(u32 seed) +{ + srand(seed); +} + +u32 sim_getrand() +{ + return rand(); +} + +void print_compiler() +{ +#if defined(_msvc) + int major=_MSC_VER/100; + int minor=_MSC_VER%100; + int build=_MSC_FULL_VER%100000; + printf("Compiler Version: Microsoft Visual C++ %02d.%02d.%05d.%d\n",major,minor,build,_MSC_BUILD); +#endif + printf("Compilation Date: %s %s\n",__DATE__,__TIME__); +} + +int main(int argc,char* argv[],char* envp[]) +{ + int i; + bool nologo=false; + char* runtime="mars"; + char* data_path=null; + char* text_path=null; + int stack_size=0x10000; + for(i=1;i>12) + +bool mips_init_mars_vm(void* ds,void* ts,u32 ds_size,u32 ts_size,u32 stack_size); +void mips_run_mars_vm(); + +void cdecl sim_printf(const char* format,...); +i32 sim_readint(); +float sim_readfloat(); +double sim_readdouble(); +void sim_readstring(char* string,u32 limit); +char sim_readchar(); +void sim_setseed(u32 seed); +u32 sim_getrand(); + +void* load_section(char* file_path,u32* size); +bool unload_section(void* section); +void* alloc_page(u32 size); +bool free_page(void* address); +void* alloc_mem(u32 size); +bool free_mem(void* address); \ No newline at end of file diff --git a/src/include/mars.h b/src/include/mars.h new file mode 100644 index 0000000..029dd83 --- /dev/null +++ b/src/include/mars.h @@ -0,0 +1,45 @@ +/* + mipsivm - MIPS Interpreting Virtual Machine + + Copyright 2018-2020, Yaotian "Zero" Tang. All rights reserved. + + This file defines the Runtime VM based on MARS. + + This program is distributed in the hope that it will be useful, but + without any warranty (no matter implied warranty or merchantability + or fitness for a particular purpose, etc.). + + File Location: /mars.h +*/ + +#include "midef.h" + +#define mips_mars_syscall_print_integer 1 +#define mips_mars_syscall_print_float 2 +#define mips_mars_syscall_print_double 3 +#define mips_mars_syscall_print_string 4 +#define mips_mars_syscall_read_integer 5 +#define mips_mars_syscall_read_float 6 +#define mips_mars_syscall_read_double 7 +#define mips_mars_syscall_read_string 8 +#define mips_mars_syscall_alloc_heap 9 +#define mips_mars_syscall_exit 10 +#define mips_mars_syscall_print_char 11 +#define mips_mars_syscall_read_char 12 +#define mips_mars_syscall_open_file 13 +#define mips_mars_syscall_read_file 14 +#define mips_mars_syscall_write_file 15 +#define mips_mars_syscall_close_file 16 +#define mips_mars_syscall_exit2 17 +#define mips_mars_syscall_time 30 +#define mips_mars_syscall_midi_out 31 +#define mips_mars_syscall_sleep 32 +#define mips_mars_syscall_midi_out_sync 33 +#define mips_mars_syscall_print_hex 34 +#define mips_mars_syscall_print_bin 35 +#define mips_mars_syscall_print_unsigned 36 +#define mips_mars_syscall_set_seed 40 +#define mips_mars_syscall_rnd_int 41 +#define mips_mars_syscall_rnd_int_range 42 +#define mips_mars_syscall_rnd_float 43 +#define mips_mars_syscall_rnd_double 44 \ No newline at end of file diff --git a/src/include/mipsdef.h b/src/include/mipsdef.h index 5c48e47..5623f98 100644 --- a/src/include/mipsdef.h +++ b/src/include/mipsdef.h @@ -69,6 +69,40 @@ typedef union _mips_instruction #define j_format 3 #define f_format 4 +// Registers +#define mips_gpr_zero 0x00 +#define mips_gpr_at 0x01 +#define mips_gpr_v0 0x02 +#define mips_gpr_v1 0x03 +#define mips_gpr_a0 0x04 +#define mips_gpr_a1 0x05 +#define mips_gpr_a2 0x06 +#define mips_gpr_a3 0x07 +#define mips_gpr_t0 0x08 +#define mips_gpr_t1 0x09 +#define mips_gpr_t2 0x0A +#define mips_gpr_t3 0x0B +#define mips_gpr_t4 0x0C +#define mips_gpr_t5 0x0D +#define mips_gpr_t6 0x0E +#define mips_gpr_t7 0x0F +#define mips_gpr_s0 0x10 +#define mips_gpr_s1 0x11 +#define mips_gpr_s2 0x12 +#define mips_gpr_s3 0x13 +#define mips_gpr_s4 0x14 +#define mips_gpr_s5 0x15 +#define mips_gpr_s6 0x16 +#define mips_gpr_s7 0x17 +#define mips_gpr_t8 0x18 +#define mips_gpr_t9 0x19 +#define mips_gpr_k0 0x1A +#define mips_gpr_k1 0x1B +#define mips_gpr_gp 0x1C +#define mips_gpr_sp 0x1D +#define mips_gpr_fp 0x1E +#define mips_gpr_ra 0x1F + #if defined(_mips_hvm) u8 mips_opcode_class[64]= { diff --git a/src/include/simulation.h b/src/include/simulation.h index 3232ff2..ffd8347 100644 --- a/src/include/simulation.h +++ b/src/include/simulation.h @@ -75,6 +75,9 @@ void mips_interpreter_i_sb(vmcb_p vcpu,mips_instruction instruction); void mips_interpreter_i_sh(vmcb_p vcpu,mips_instruction instruction); void mips_interpreter_i_sw(vmcb_p vcpu,mips_instruction instruction); +// RegImm I-Format Instructions +void mips_interpreter_i_bgez(vmcb_p vcpu,mips_instruction instruction); + // J-Format Instructions void mips_interpreter_j_j(vmcb_p vcpu,mips_instruction instruction); void mips_interpreter_j_jal(vmcb_p vcpu,mips_instruction instruction); @@ -82,13 +85,15 @@ void mips_interpreter_j_jal(vmcb_p vcpu,mips_instruction instruction); // Miscellaneous void mips_interpreter_unhandled_instruction(vmcb_p vcpu,mips_instruction instruction); void mips_interpreter_r_format(vmcb_p vcpu,mips_instruction instruction); +void mips_interpreter_regimm_i_format(vmcb_p vcpu,mips_instruction instruction); void mips_interpreter_fpu(vmcb_p vcpu,mips_instruction instruction); +void mips_mars_syscall_handler(vmcb_p vcpu); #if defined(_mips_hvm) mips_interpreter_procedure cpu_interpreter_by_opcode[64]= { mips_interpreter_r_format, - mips_interpreter_unhandled_instruction, + mips_interpreter_regimm_i_format, mips_interpreter_j_j, mips_interpreter_j_jal, mips_interpreter_i_beq, @@ -221,5 +226,41 @@ mips_interpreter_procedure cpu_interpreter_r_funct[64]= mips_interpreter_unhandled_instruction }; +mips_interpreter_procedure cpu_interpreter_regimm_i_funct[32]= +{ + mips_interpreter_unhandled_instruction, + mips_interpreter_i_bgez, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction, + mips_interpreter_unhandled_instruction +}; + mips_interpreter_procedure fpu_interpreter[64]; #endif \ No newline at end of file diff --git a/src/include/vmcb.h b/src/include/vmcb.h index c484e97..837e104 100644 --- a/src/include/vmcb.h +++ b/src/include/vmcb.h @@ -14,6 +14,8 @@ #include "midef.h" +#define mipsivm_vcpu_flags_stop_interpretation 31 + // We use paging to virtualize memory. // In this way, we may virtualize memory with finest granularity of 4KiB. // Principle: Unreadable Page is Not Present. Page not-present grants NO-ACCESS. @@ -23,10 +25,10 @@ typedef union _l3p_address { struct { - u32 pdpte:2; - u32 pde:9; - u32 pte:9; u32 offset:12; + u32 pte:9; + u32 pde:9; + u32 pdpte:2; }; u32 value; }l3p_address,*l3p_address_p; @@ -85,9 +87,9 @@ typedef union _l2p_address { struct { - u32 pde:10; - u32 pte:10; u32 offset:12; + u32 pte:10; + u32 pde:10; }; u32 value; }l2p_address,*l2p_address_p; @@ -150,14 +152,34 @@ typedef struct _vmcb l2p_pde_p npt_base; // Points to 512 Entries of PDE #endif u64 tsc; // Time-Stamp Counter, aka TSC, Processor Ticks. + u64 eic; // Executed Instruction Counter. + u32 vm_type; }vmcb,*vmcb_p; -// Virtual Machine. -// This is abstraction of a machine -typedef struct _mips_vm +#define mars_data_start 0x10010000 +#define mars_text_start 0x00400000 +#define mars_stack_top 0x7ffff000 + +typedef struct _mips_memory_descriptor +{ + void* address; + u32 size; +}mips_memory_descriptor,*mips_memory_descriptor_p; + +// MARS Virtual Machine. +typedef struct _mips_mars_vm { vmcb vcpu; // We support one vCPU right now. - void* mem; // All memory. -}mips_vm,*mips_vm_p; + mips_memory_descriptor data; + mips_memory_descriptor text; + mips_memory_descriptor stack; +}mips_mars_vm,*mips_mars_vm_p; + +void* mips_ref_hmem(vmcb_p vcpu,u32 gpa,bool r,bool w,bool x); +bool mips_npt_edit_entry(vmcb_p vcpu,u32 gpa,void* hva,bool r,bool w,bool x); +void mips_vcpu_start_interpretation(vmcb_p vcpu); +void mips_vcpu_dump_state(vmcb_p vcpu); -void* mips_ref_hmem(vmcb_p vcpu,u32 gpa,bool r,bool w,bool x); \ No newline at end of file +#if defined(_mips_hvm_mars) +mips_mars_vm vm={0}; +#endif \ No newline at end of file diff --git a/src/mars.c b/src/mars.c new file mode 100644 index 0000000..78f86c1 --- /dev/null +++ b/src/mars.c @@ -0,0 +1,196 @@ +/* + mipsivm - MIPS Interpreting Virtual Machine + + Copyright 2018-2020, Yaotian "Zero" Tang. All rights reserved. + + This file defines the Runtime VM based on MARS. + + This program is distributed in the hope that it will be useful, but + without any warranty (no matter implied warranty or merchantability + or fitness for a particular purpose, etc.). + + File Location: /mars.c +*/ + +#include +#include +#include +#include +#include + +bool mips_init_mars_vm_npt() +{ +#if defined(_amd64) + l3p_address gds,gts,gsp; + gds.value=mars_data_start; + gts.value=mars_text_start; + gsp.value=mars_stack_top-vm.stack.size; + // For 64-bit simulator, NPT Base points to 4 PDPTEs. + // Each PDPTE supervises 1GiB (0x40000000 bytes) of memory. + vm.vcpu.npt_base=alloc_mem(32); + if(vm.vcpu.npt_base) + { + u32 i; + // Initialize .data section. + sim_printf("Initializing .data section...\n"); + for(i=0;i<(vm.data.size>>12);i++) + if(mips_npt_edit_entry(&vm.vcpu,mars_data_start+(i<<12),(void*)((u64)vm.data.address+(i<<12)),true,true,false)==false) + return false; + // Initialize .text section. + sim_printf("Initializing .text section...\n"); + for(i=0;i<(vm.text.size>>12);i++) + if(mips_npt_edit_entry(&vm.vcpu,mars_text_start+(i<<12),(void*)((u64)vm.text.address+(i<<12)),true,false,true)==false) + return false; + // Initialize Stack + sim_printf("Initializing stack...\n"); + for(i=(vm.stack.size>>12);i>0;i--) + if(mips_npt_edit_entry(&vm.vcpu,mars_stack_top-(i<<12),(void*)((u64)vm.stack.address+(i<<12)),true,true,false)==false) + return false; + } +#endif + return true; +} + +void mips_mars_syscall_handler(vmcb_p vcpu) +{ + u32 code=vcpu->gpr.ureg[mips_gpr_v0]; + switch(code) + { + case mips_mars_syscall_print_integer: + { + sim_printf("%d",vcpu->gpr.ireg[mips_gpr_a0]); + vcpu->tsc+=14; + break; + } + case mips_mars_syscall_print_float: + { + sim_printf("%f",vcpu->fpr[12]); + vcpu->tsc+=18; + break; + } + case mips_mars_syscall_print_double: + { + double tmp; + memcpy((void*)&tmp,(void*)&vcpu->fpr[12],sizeof(double)); + sim_printf("%f",vcpu->fpr[12]); + vcpu->tsc+=19; + break; + } + case mips_mars_syscall_print_string: + { + u32 string_gpa=vcpu->gpr.ureg[mips_gpr_a0]; + char* s=(char*)mips_ref_hmem(vcpu,string_gpa,true,false,false); + if(s) + sim_printf("%s",s); + else + sim_printf("Nested Page Fault is intercepted: Invalid String Address!\n"); + vcpu->tsc+=22; + break; + } + case mips_mars_syscall_read_integer: + { + vcpu->gpr.ireg[mips_gpr_v0]=sim_readint(); + break; + } + case mips_mars_syscall_read_float: + { + float tmp=sim_readfloat(); + memcpy((void*)&vcpu->fpr[0],(void*)&tmp,sizeof(float)); + break; + } + case mips_mars_syscall_read_double: + { + double tmp=sim_readdouble(); + memcpy((void*)&vcpu->fpr[0],(void*)&tmp,sizeof(double)); + break; + } + case mips_mars_syscall_read_string: + { + u32 string_gpa=vcpu->gpr.ureg[mips_gpr_a0]; + u32 string_lim=vcpu->gpr.ureg[mips_gpr_a1]; + char* s=(char*)mips_ref_hmem(vcpu,string_gpa,true,true,false); + if(s)sim_readstring(s,string_lim); + break; + } + case mips_mars_syscall_exit: + { + _bittestandset(&vcpu->flags,mipsivm_vcpu_flags_stop_interpretation); + vcpu->tsc+=2; + break; + } + case mips_mars_syscall_print_char: + { + u8 c=(u8)vcpu->gpr.ureg[mips_gpr_a0]; + sim_printf("%c",c); + break; + } + case mips_mars_syscall_read_char: + { + vcpu->gpr.ureg[mips_gpr_v0]=(u32)sim_readchar(); + break; + } + case mips_mars_syscall_print_hex: + { + sim_printf("0x%X",vcpu->gpr.ureg[mips_gpr_a0]); + break; + } + case mips_mars_syscall_print_unsigned: + { + sim_printf("%u",vcpu->gpr.ureg[mips_gpr_a0]); + break; + } + case mips_mars_syscall_set_seed: + { + sim_setseed(vcpu->gpr.ureg[mips_gpr_a1]); + break; + } + case mips_mars_syscall_rnd_int: + { + vcpu->gpr.ureg[mips_gpr_v0]=(u32)sim_getrand(); + break; + } + default: + { + sim_printf("Unimplemented system call function! Index=%d\n",code); + break; + } + } +} + +bool mips_init_mars_vm(void* ds,void* ts,u32 ds_size,u32 ts_size,u32 stack_size) +{ + vm.data.address=ds; + vm.data.size=ds_size; + vm.text.address=ts; + vm.text.size=ts_size; + vm.stack.address=alloc_page(stack_size); + vm.stack.size=stack_size; + if(vm.stack.address==null)return false; + return mips_init_mars_vm_npt(); +} + +void mips_run_mars_vm() +{ + u64 t1,t2,tsc_diff; + double cpi,ghr; + // Initialize vCPU Registers + vm.vcpu.gpr.pc=mars_text_start; + vm.vcpu.gpr.ureg[mips_gpr_zero]=0; + vm.vcpu.gpr.ureg[mips_gpr_sp]=mars_stack_top-4; + // Start Interpretation. + sim_printf("============Program Start============\n\n"); + t1=__rdtsc(); + mips_vcpu_start_interpretation(&vm.vcpu); + t2=__rdtsc(); + sim_printf("\n============Program Ended============\n"); + // Dump State when interpretation is over. + sim_printf("Instructions Executed: %lld\n",vm.vcpu.eic); + sim_printf("Guest Ticks Elapsed: %lld\n",vm.vcpu.tsc); + tsc_diff=t2-t1; + sim_printf("Host Ticks Elapsed: %lld\n",tsc_diff); + cpi=(double)vm.vcpu.tsc/(double)vm.vcpu.eic; + sim_printf("Guest Program CPI: %f (Higher CPI indicates less efficiency in program)\n",cpi); + ghr=(double)vm.vcpu.tsc/(double)tsc_diff; + sim_printf("Guest/Host TSC Rate: %f (Higher TSC Rate indicates better simulation performance)\n",ghr); + mips_vcpu_dump_state(&vm.vcpu); +} \ No newline at end of file diff --git a/src/sim-i.c b/src/sim-i.c index 752b6ac..22a34f0 100644 --- a/src/sim-i.c +++ b/src/sim-i.c @@ -16,56 +16,62 @@ #include #include +// Normal I-Format Instructions void mips_interpreter_i_beq(vmcb_p vcpu,mips_instruction instruction) { // Definition: Branch if Equal // Formula: if rs==rt then pc+=(imm<<2)+4 - const i32 imm=(i32)instruction.i.imm; + const i32 imm=(i32)((i16)instruction.i.imm); const u32 rs=instruction.i.rs,rt=instruction.i.rt; if(vcpu->gpr.ireg[rs]==vcpu->gpr.ireg[rt]) vcpu->gpr.pc+=(imm<<2); vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_i_bne(vmcb_p vcpu,mips_instruction instruction) { // Definition: Branch if Not Equal // Formula: if rs!=rt then pc+=(imm<<2)+4 - const i32 imm=(i32)instruction.i.imm; + const i32 imm=(i32)((i16)instruction.i.imm); const u32 rs=instruction.i.rs,rt=instruction.i.rt; if(vcpu->gpr.ireg[rs]!=vcpu->gpr.ireg[rt]) vcpu->gpr.pc+=(imm<<2); vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_i_blez(vmcb_p vcpu,mips_instruction instruction) { // Definition: Branch if Less than or Equal to Zero // Formula: if rs<=0 then pc+=(imm<<2)+4 - const i32 imm=(i32)instruction.i.imm; + const i32 imm=(i32)((i16)instruction.i.imm); const u32 rs=instruction.i.rs; if(vcpu->gpr.ireg[rs]<=0)vcpu->gpr.pc+=(imm<<2); vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_i_bgtz(vmcb_p vcpu,mips_instruction instruction) { // Definition: Branch if Greater Than Zero // Formula: if rs>0 then pc+=(imm<<2)+4 - const i32 imm=(i32)instruction.i.imm; + const i32 imm=(i32)((i16)instruction.i.imm); const u32 rs=instruction.i.rs; if(vcpu->gpr.ireg[rs]>0)vcpu->gpr.pc+=(imm<<2); vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_i_addi(vmcb_p vcpu,mips_instruction instruction) { // Definition: Add Immediate // Formula: rt=rs+imm - const i32 imm=(i32)instruction.i.imm; + const i32 imm=(i32)((i16)instruction.i.imm); const u32 rs=instruction.i.rs,rt=instruction.i.rt; vcpu->gpr.ireg[rt]=vcpu->gpr.ireg[rs]+imm; vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_i_addiu(vmcb_p vcpu,mips_instruction instruction) @@ -76,16 +82,18 @@ void mips_interpreter_i_addiu(vmcb_p vcpu,mips_instruction instruction) const u32 rs=instruction.i.rs,rt=instruction.i.rt; vcpu->gpr.ureg[rt]=vcpu->gpr.ureg[rs]+imm; vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_i_slti(vmcb_p vcpu,mips_instruction instruction) { // Definition: Set if Less Than Immediate // Formula: rt=(rsgpr.ireg[rt]=vcpu->gpr.ireg[rs]gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_i_sltiu(vmcb_p vcpu,mips_instruction instruction) @@ -96,6 +104,7 @@ void mips_interpreter_i_sltiu(vmcb_p vcpu,mips_instruction instruction) const u32 rs=instruction.i.rs,rt=instruction.i.rt; vcpu->gpr.ureg[rt]=vcpu->gpr.ureg[rs]gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_i_andi(vmcb_p vcpu,mips_instruction instruction) @@ -106,6 +115,7 @@ void mips_interpreter_i_andi(vmcb_p vcpu,mips_instruction instruction) const u32 rs=instruction.i.rs,rt=instruction.i.rt; vcpu->gpr.ureg[rt]=vcpu->gpr.ureg[rs]&imm; vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_i_ori(vmcb_p vcpu,mips_instruction instruction) @@ -116,6 +126,7 @@ void mips_interpreter_i_ori(vmcb_p vcpu,mips_instruction instruction) const u32 rs=instruction.i.rs,rt=instruction.i.rt; vcpu->gpr.ureg[rt]=vcpu->gpr.ureg[rs]|imm; vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_i_xori(vmcb_p vcpu,mips_instruction instruction) @@ -126,6 +137,7 @@ void mips_interpreter_i_xori(vmcb_p vcpu,mips_instruction instruction) const u32 rs=instruction.i.rs,rt=instruction.i.rt; vcpu->gpr.ureg[rt]=vcpu->gpr.ureg[rs]^imm; vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_i_lui(vmcb_p vcpu,mips_instruction instruction) @@ -136,25 +148,27 @@ void mips_interpreter_i_lui(vmcb_p vcpu,mips_instruction instruction) const u32 rt=instruction.i.rt; vcpu->gpr.ureg[rt]=imm<<16; vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_i_lb(vmcb_p vcpu,mips_instruction instruction) { // Definition: Load Byte Signed // Formula (x86 Asm): movsx rt,byte ptr[rs+imm] - const i32 imm=(i32)instruction.i.imm; + const i32 imm=(i32)((i16)instruction.i.imm); const u32 rs=instruction.i.rs,rt=instruction.i.rt; const u32 gpa=(u32)(vcpu->gpr.ureg[rs]+imm); i8* hva=(i8*)mips_ref_hmem(vcpu,gpa,true,false,false); if(hva)vcpu->gpr.ireg[rt]=(i32)(*hva); vcpu->gpr.pc+=4; + vcpu->tsc+=3; } void mips_interpreter_i_lh(vmcb_p vcpu,mips_instruction instruction) { // Definition: Load Halfword Signed // Formula (x86 Asm): movsx rt,word ptr[rs+imm] - const i32 imm=(i32)instruction.i.imm; + const i32 imm=(i32)((i16)instruction.i.imm); const u32 rs=instruction.i.rs,rt=instruction.i.rt; const u32 gpa=(u32)(vcpu->gpr.ureg[rs]+imm); if((gpa & 1)==0) // Alignment Check @@ -163,13 +177,14 @@ void mips_interpreter_i_lh(vmcb_p vcpu,mips_instruction instruction) if(hva)vcpu->gpr.ireg[rt]=(i32)(*hva); } vcpu->gpr.pc+=4; + vcpu->tsc+=3; } void mips_interpreter_i_lw(vmcb_p vcpu,mips_instruction instruction) { // Definition: Load Word // Formula (x86 Asm): mov rt,dword ptr[rs+imm] - const i32 imm=(i32)instruction.i.imm; + const i32 imm=(i32)((i16)instruction.i.imm); const u32 rs=instruction.i.rs,rt=instruction.i.rt; const u32 gpa=(u32)(vcpu->gpr.ureg[rs]+imm); if((gpa & 3)==0) // Alignment Check @@ -178,25 +193,27 @@ void mips_interpreter_i_lw(vmcb_p vcpu,mips_instruction instruction) if(hva)vcpu->gpr.ireg[rt]=*hva; } vcpu->gpr.pc+=4; + vcpu->tsc+=3; } void mips_interpreter_i_lbu(vmcb_p vcpu,mips_instruction instruction) { // Definition: Load Byte Unsigned // Formula (x86 Asm): movzx rt,byte ptr[rs+imm] - const i32 imm=(i32)instruction.i.imm; + const i32 imm=(i32)((i16)instruction.i.imm); const u32 rs=instruction.i.rs,rt=instruction.i.rt; const u32 gpa=(u32)(vcpu->gpr.ureg[rs]+imm); u8* hva=(u8*)mips_ref_hmem(vcpu,gpa,true,false,false); if(hva)vcpu->gpr.ureg[rt]=(u32)(*hva); vcpu->gpr.pc+=4; + vcpu->tsc+=3; } void mips_interpreter_i_lhu(vmcb_p vcpu,mips_instruction instruction) { // Definition: Load Halfword Unsigned // Formula (x86 Asm): movzx rt,word ptr[rs+imm] - const i32 imm=(i32)instruction.i.imm; + const i32 imm=(i32)((i16)instruction.i.imm); const u32 rs=instruction.i.rs,rt=instruction.i.rt; const u32 gpa=(u32)(vcpu->gpr.ureg[rs]+imm); if((gpa & 1)==0) // Alignment Check @@ -205,25 +222,27 @@ void mips_interpreter_i_lhu(vmcb_p vcpu,mips_instruction instruction) if(hva)vcpu->gpr.ureg[rt]=(u32)(*hva); } vcpu->gpr.pc+=4; + vcpu->tsc+=3; } void mips_interpreter_i_sb(vmcb_p vcpu,mips_instruction instruction) { // Definition: Store Byte // Formula (x86 Asm): mov byte ptr[rs+imm],rtb - const i32 imm=(i32)instruction.i.imm; + const i32 imm=(i32)((i16)instruction.i.imm); const u32 rs=instruction.i.rs,rt=instruction.i.rt; const u32 gpa=(u32)(vcpu->gpr.ureg[rs]+imm); u8* hva=(u8*)mips_ref_hmem(vcpu,gpa,true,true,false); if(hva)*hva=(u8)vcpu->gpr.ureg[rt]; vcpu->gpr.pc+=4; + vcpu->tsc+=3; } void mips_interpreter_i_sh(vmcb_p vcpu,mips_instruction instruction) { // Definition: Store Halfword // Formula (x86 Asm): mov word ptr[rs+imm],rtw - const i32 imm=(i32)instruction.i.imm; + const i32 imm=(i32)((i16)instruction.i.imm); const u32 rs=instruction.i.rs,rt=instruction.i.rt; const u32 gpa=(u32)(vcpu->gpr.ureg[rs]+imm); if((gpa & 1)==0) // Alignment Check @@ -232,13 +251,14 @@ void mips_interpreter_i_sh(vmcb_p vcpu,mips_instruction instruction) if(hva)*hva=(u16)vcpu->gpr.ureg[rt]; } vcpu->gpr.pc+=4; + vcpu->tsc+=3; } void mips_interpreter_i_sw(vmcb_p vcpu,mips_instruction instruction) { // Definition: Store Word // Formula (x86 Asm): mov dword ptr[rs+imm],rt - const i32 imm=(i32)instruction.i.imm; + const i32 imm=(i32)((i16)instruction.i.imm); const u32 rs=instruction.i.rs,rt=instruction.i.rt; const u32 gpa=(u32)(vcpu->gpr.ureg[rs]+imm); if((gpa & 3)==0) // Alignment Check @@ -247,4 +267,16 @@ void mips_interpreter_i_sw(vmcb_p vcpu,mips_instruction instruction) if(hva)*hva=vcpu->gpr.ureg[rt]; } vcpu->gpr.pc+=4; + vcpu->tsc+=3; +} + +// RegImm I-Format Instructions +void mips_interpreter_i_bgez(vmcb_p vcpu,mips_instruction instruction) +{ + // Definition: Branch if Greater than or Equal to Zero + // Formula: if rs>=0 then pc+=(imm<<2)+4 + const i32 imm=(i32)((i16)instruction.i.imm); + const u32 rs=instruction.i.rs; + if(vcpu->gpr.ireg[rs]>=0)vcpu->gpr.pc+=(imm<<2); + vcpu->gpr.pc+=4; } \ No newline at end of file diff --git a/src/sim-j.c b/src/sim-j.c index 8359525..4294585 100644 --- a/src/sim-j.c +++ b/src/sim-j.c @@ -23,6 +23,7 @@ void mips_interpreter_j_j(vmcb_p vcpu,mips_instruction instruction) const u32 offset=instruction.j.addr<<2; vcpu->gpr.pc&=0xf0000000; vcpu->gpr.pc|=offset; + vcpu->tsc+=1; } void mips_interpreter_j_jal(vmcb_p vcpu,mips_instruction instruction) @@ -33,4 +34,5 @@ void mips_interpreter_j_jal(vmcb_p vcpu,mips_instruction instruction) vcpu->gpr.ureg[31]=vcpu->gpr.pc+4; vcpu->gpr.pc&=0xf0000000; vcpu->gpr.pc|=offset; + vcpu->tsc+=1; } \ No newline at end of file diff --git a/src/sim-r.c b/src/sim-r.c index 93d6462..e52b733 100644 --- a/src/sim-r.c +++ b/src/sim-r.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include void mips_interpreter_r_sll(vmcb_p vcpu,mips_instruction instruction) { @@ -24,6 +26,7 @@ void mips_interpreter_r_sll(vmcb_p vcpu,mips_instruction instruction) const u32 shamt=instruction.r.shamt; vcpu->gpr.ureg[rd]=vcpu->gpr.ureg[rt]<gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_r_srl(vmcb_p vcpu,mips_instruction instruction) @@ -34,6 +37,7 @@ void mips_interpreter_r_srl(vmcb_p vcpu,mips_instruction instruction) const u32 shamt=instruction.r.shamt; vcpu->gpr.ureg[rd]=vcpu->gpr.ureg[rt]>>shamt; vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_r_sra(vmcb_p vcpu,mips_instruction instruction) @@ -44,6 +48,7 @@ void mips_interpreter_r_sra(vmcb_p vcpu,mips_instruction instruction) const u32 shamt=instruction.r.shamt; vcpu->gpr.ireg[rd]=vcpu->gpr.ireg[rt]>>shamt; vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_r_sllv(vmcb_p vcpu,mips_instruction instruction) @@ -54,6 +59,7 @@ void mips_interpreter_r_sllv(vmcb_p vcpu,mips_instruction instruction) const u32 shamt=instruction.r.shamt; vcpu->gpr.ureg[rd]=vcpu->gpr.ureg[rt]<gpr.ureg[rs]; vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_r_srlv(vmcb_p vcpu,mips_instruction instruction) @@ -64,6 +70,7 @@ void mips_interpreter_r_srlv(vmcb_p vcpu,mips_instruction instruction) const u32 shamt=instruction.r.shamt; vcpu->gpr.ureg[rd]=vcpu->gpr.ureg[rt]>>vcpu->gpr.ureg[rs]; vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_r_srav(vmcb_p vcpu,mips_instruction instruction) @@ -74,6 +81,7 @@ void mips_interpreter_r_srav(vmcb_p vcpu,mips_instruction instruction) const u32 shamt=instruction.r.shamt; vcpu->gpr.ireg[rd]=vcpu->gpr.ireg[rt]>>vcpu->gpr.ureg[rs]; vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_r_jr(vmcb_p vcpu,mips_instruction instruction) @@ -82,6 +90,7 @@ void mips_interpreter_r_jr(vmcb_p vcpu,mips_instruction instruction) // Formula: pc=rs const u32 rs=instruction.r.rs; vcpu->gpr.pc=vcpu->gpr.ureg[rs]; + vcpu->tsc+=1; } void mips_interpreter_r_jalr(vmcb_p vcpu,mips_instruction instruction) @@ -91,6 +100,7 @@ void mips_interpreter_r_jalr(vmcb_p vcpu,mips_instruction instruction) const u32 rd=instruction.r.rd,rs=instruction.r.rs; vcpu->gpr.ureg[rd]=vcpu->gpr.pc+4; vcpu->gpr.pc=vcpu->gpr.ureg[rs]; + vcpu->tsc+=1; } void mips_interpreter_r_movz(vmcb_p vcpu,mips_instruction instruction) @@ -101,6 +111,7 @@ void mips_interpreter_r_movz(vmcb_p vcpu,mips_instruction instruction) if(vcpu->gpr.ureg[rt]==0) vcpu->gpr.ureg[rd]=vcpu->gpr.ureg[rs]; vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_r_movn(vmcb_p vcpu,mips_instruction instruction) @@ -111,6 +122,7 @@ void mips_interpreter_r_movn(vmcb_p vcpu,mips_instruction instruction) if(vcpu->gpr.ureg[rt]) vcpu->gpr.ureg[rd]=vcpu->gpr.ureg[rs]; vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_r_syscall(vmcb_p vcpu,mips_instruction instruction) @@ -118,7 +130,12 @@ void mips_interpreter_r_syscall(vmcb_p vcpu,mips_instruction instruction) // Definition: Call to System // Formula: trap into syscall exception handler // FIXME: Complete Syscall Handler + if(vcpu->vm_type==0) + mips_mars_syscall_handler(vcpu); + else + sim_printf("syscall instruction is unimplemented!\n"); vcpu->gpr.pc+=4; + vcpu->tsc+=62; } void mips_interpreter_r_break(vmcb_p vcpu,mips_instruction instruction) @@ -144,6 +161,7 @@ void mips_interpreter_r_mfhi(vmcb_p vcpu,mips_instruction instruction) const u32 rd=instruction.r.rd; vcpu->gpr.ureg[rd]=vcpu->gpr.v.hi; vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_r_mthi(vmcb_p vcpu,mips_instruction instruction) @@ -153,6 +171,7 @@ void mips_interpreter_r_mthi(vmcb_p vcpu,mips_instruction instruction) const u32 rs=instruction.r.rs; vcpu->gpr.v.hi=vcpu->gpr.ureg[rs]; vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_r_mflo(vmcb_p vcpu,mips_instruction instruction) @@ -162,6 +181,7 @@ void mips_interpreter_r_mflo(vmcb_p vcpu,mips_instruction instruction) const u32 rd=instruction.r.rd; vcpu->gpr.ureg[rd]=vcpu->gpr.v.lo; vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_r_mtlo(vmcb_p vcpu,mips_instruction instruction) @@ -171,6 +191,7 @@ void mips_interpreter_r_mtlo(vmcb_p vcpu,mips_instruction instruction) const u32 rs=instruction.r.rs; vcpu->gpr.v.lo=vcpu->gpr.ureg[rs]; vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_r_mult(vmcb_p vcpu,mips_instruction instruction) @@ -180,6 +201,7 @@ void mips_interpreter_r_mult(vmcb_p vcpu,mips_instruction instruction) const u32 rs=instruction.r.rs,rt=instruction.r.rt; vcpu->gpr.v.value=__emul(vcpu->gpr.ireg[rs],vcpu->gpr.ireg[rt]); vcpu->gpr.pc+=4; + vcpu->tsc+=3; } void mips_interpreter_r_multu(vmcb_p vcpu,mips_instruction instruction) @@ -189,6 +211,7 @@ void mips_interpreter_r_multu(vmcb_p vcpu,mips_instruction instruction) const u32 rs=instruction.r.rs,rt=instruction.r.rt; vcpu->gpr.v.value=__emulu(vcpu->gpr.ureg[rs],vcpu->gpr.ureg[rt]); vcpu->gpr.pc+=4; + vcpu->tsc+=3; } void mips_interpreter_r_div(vmcb_p vcpu,mips_instruction instruction) @@ -199,6 +222,7 @@ void mips_interpreter_r_div(vmcb_p vcpu,mips_instruction instruction) vcpu->gpr.v.lo=(u32)(vcpu->gpr.ireg[rs]/vcpu->gpr.ireg[rt]); vcpu->gpr.v.hi=(u32)(vcpu->gpr.ireg[rs]%vcpu->gpr.ireg[rt]); vcpu->gpr.pc+=4; + vcpu->tsc+=42; } void mips_interpreter_r_divu(vmcb_p vcpu,mips_instruction instruction) @@ -209,6 +233,7 @@ void mips_interpreter_r_divu(vmcb_p vcpu,mips_instruction instruction) vcpu->gpr.v.lo=vcpu->gpr.ureg[rs]/vcpu->gpr.ureg[rt]; vcpu->gpr.v.hi=vcpu->gpr.ureg[rs]%vcpu->gpr.ureg[rt]; vcpu->gpr.pc+=4; + vcpu->tsc+=39; } void mips_interpreter_r_add(vmcb_p vcpu,mips_instruction instruction) @@ -218,6 +243,7 @@ void mips_interpreter_r_add(vmcb_p vcpu,mips_instruction instruction) const u32 rd=instruction.r.rd,rs=instruction.r.rs,rt=instruction.r.rt; vcpu->gpr.ireg[rd]=vcpu->gpr.ireg[rs]+vcpu->gpr.ireg[rt]; vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_r_addu(vmcb_p vcpu,mips_instruction instruction) @@ -227,6 +253,7 @@ void mips_interpreter_r_addu(vmcb_p vcpu,mips_instruction instruction) const u32 rd=instruction.r.rd,rs=instruction.r.rs,rt=instruction.r.rt; vcpu->gpr.ureg[rd]=vcpu->gpr.ureg[rs]+vcpu->gpr.ureg[rt]; vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_r_sub(vmcb_p vcpu,mips_instruction instruction) @@ -236,6 +263,7 @@ void mips_interpreter_r_sub(vmcb_p vcpu,mips_instruction instruction) const u32 rd=instruction.r.rd,rs=instruction.r.rs,rt=instruction.r.rt; vcpu->gpr.ireg[rd]=vcpu->gpr.ireg[rs]-vcpu->gpr.ireg[rt]; vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_r_subu(vmcb_p vcpu,mips_instruction instruction) @@ -245,6 +273,7 @@ void mips_interpreter_r_subu(vmcb_p vcpu,mips_instruction instruction) const u32 rd=instruction.r.rd,rs=instruction.r.rs,rt=instruction.r.rt; vcpu->gpr.ureg[rd]=vcpu->gpr.ureg[rs]-vcpu->gpr.ureg[rt]; vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_r_and(vmcb_p vcpu,mips_instruction instruction) @@ -254,6 +283,7 @@ void mips_interpreter_r_and(vmcb_p vcpu,mips_instruction instruction) const u32 rd=instruction.r.rd,rs=instruction.r.rs,rt=instruction.r.rt; vcpu->gpr.ureg[rd]=vcpu->gpr.ureg[rs]&vcpu->gpr.ureg[rt]; vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_r_or(vmcb_p vcpu,mips_instruction instruction) @@ -263,6 +293,7 @@ void mips_interpreter_r_or(vmcb_p vcpu,mips_instruction instruction) const u32 rd=instruction.r.rd,rs=instruction.r.rs,rt=instruction.r.rt; vcpu->gpr.ureg[rd]=vcpu->gpr.ureg[rs]|vcpu->gpr.ureg[rt]; vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_r_xor(vmcb_p vcpu,mips_instruction instruction) @@ -272,6 +303,7 @@ void mips_interpreter_r_xor(vmcb_p vcpu,mips_instruction instruction) const u32 rd=instruction.r.rd,rs=instruction.r.rs,rt=instruction.r.rt; vcpu->gpr.ureg[rd]=vcpu->gpr.ureg[rs]^vcpu->gpr.ureg[rt]; vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_r_nor(vmcb_p vcpu,mips_instruction instruction) @@ -281,6 +313,7 @@ void mips_interpreter_r_nor(vmcb_p vcpu,mips_instruction instruction) const u32 rd=instruction.r.rd,rs=instruction.r.rs,rt=instruction.r.rt; vcpu->gpr.ureg[rd]=~(vcpu->gpr.ureg[rs]|vcpu->gpr.ureg[rt]); vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_r_slt(vmcb_p vcpu,mips_instruction instruction) @@ -289,7 +322,8 @@ void mips_interpreter_r_slt(vmcb_p vcpu,mips_instruction instruction) // Formula: rd=(rsgpr.ireg[rd]=vcpu->gpr.ireg[rs]gpr.ireg[rt]?1:0; - vcpu->gpr.pc+=1; + vcpu->gpr.pc+=4; + vcpu->tsc+=1; } void mips_interpreter_r_sltu(vmcb_p vcpu,mips_instruction instruction) @@ -298,5 +332,6 @@ void mips_interpreter_r_sltu(vmcb_p vcpu,mips_instruction instruction) // Formula: rd=(rsgpr.ureg[rd]=vcpu->gpr.ureg[rs]gpr.ureg[rt]?1:0; - vcpu->gpr.pc+=1; + vcpu->gpr.pc+=4; + vcpu->tsc+=1; } \ No newline at end of file diff --git a/src/vcpu.c b/src/vcpu.c index 216e761..6de8684 100644 --- a/src/vcpu.c +++ b/src/vcpu.c @@ -16,6 +16,7 @@ #include #include #include +#include // Translates and References the Guest Physical Address to Host Virtual Address. void* mips_ref_hmem(vmcb_p vcpu,u32 gpa,bool r,bool w,bool x) @@ -26,10 +27,10 @@ void* mips_ref_hmem(vmcb_p vcpu,u32 gpa,bool r,bool w,bool x) addr.value=gpa; if(pdpteb[addr.pdpte].r>=r && pdpteb[addr.pdpte].w>=w && pdpteb[addr.pdpte].x>=x) { - l3p_pde_p pdeb=(l3p_pde_p)(pdpteb[addr.pde].pde_page<<12); + l3p_pde_p pdeb=(l3p_pde_p)(pdpteb[addr.pdpte].pde_page<<12); if(pdeb[addr.pde].r>=r && pdeb[addr.pde].w>=w && pdeb[addr.pde].x>=x) { - l3p_pte_p pteb=(l3p_pte_p)(pdeb[addr.pte].pte_page<<12); + l3p_pte_p pteb=(l3p_pte_p)(pdeb[addr.pde].pte_page<<12); if(pteb[addr.pte].r>=r && pteb[addr.pte].w>=w && pteb[addr.pte].x>=x) { u64 p=(pteb[addr.pte].page_base<<12)+addr.offset; @@ -44,9 +45,39 @@ void* mips_ref_hmem(vmcb_p vcpu,u32 gpa,bool r,bool w,bool x) return null; } +bool mips_npt_edit_entry(vmcb_p vcpu,u32 gpa,void* hva,bool r,bool w,bool x) +{ +#if defined(_amd64) + l3p_address ptr; + ptr.value=gpa; + vcpu->npt_base[ptr.pdpte].r=vcpu->npt_base[ptr.pdpte].w=vcpu->npt_base[ptr.pdpte].x=true; + if(vcpu->npt_base[ptr.pdpte].pde_page==0) + vcpu->npt_base[ptr.pdpte].pde_page=(u64)alloc_page(page_size)>>12; + if(vcpu->npt_base[ptr.pdpte].pde_page) + { + l3p_pde_p pdeb=(l3p_pde_p)(vcpu->npt_base[ptr.pdpte].pde_page<<12); + pdeb[ptr.pde].r=pdeb[ptr.pde].w=pdeb[ptr.pde].x=true; + if(pdeb[ptr.pde].pte_page==0) + pdeb[ptr.pde].pte_page=(u64)alloc_page(page_size)>>12; + if(pdeb[ptr.pde].pte_page) + { + l3p_pte_p pteb=(l3p_pte_p)(pdeb[ptr.pde].pte_page<<12); + pteb[ptr.pte].r=r; + pteb[ptr.pte].w=w; + pteb[ptr.pte].x=x; + pteb[ptr.pte].a=pteb[ptr.pte].d=false; + pteb[ptr.pte].page_base=(u64)hva>>12; + return true; + } + } + return false; +#endif +} + void mips_interpreter_unhandled_instruction(vmcb_p vcpu,mips_instruction instruction) { - ; + sim_printf("#UD Exception! (Unknown Instruction)\n"); + _bittestandset(&vcpu->flags,mipsivm_vcpu_flags_stop_interpretation); } void mips_interpreter_r_format(vmcb_p vcpu,mips_instruction instruction) @@ -54,7 +85,45 @@ void mips_interpreter_r_format(vmcb_p vcpu,mips_instruction instruction) cpu_interpreter_r_funct[instruction.r.funct](vcpu,instruction); } +void mips_interpreter_regimm_i_format(vmcb_p vcpu,mips_instruction instruction) +{ + cpu_interpreter_regimm_i_funct[instruction.i.rt](vcpu,instruction); +} + void mips_interpreter_fpu(vmcb_p vcpu,mips_instruction instruction) { ; +} + +void mips_vcpu_dump_state(vmcb_p vcpu) +{ + int i; + sim_printf("============Dumping General-Purpose Registers============\n"); + sim_printf("Register\tValue\n"); + for(i=0;i<32;i++) + sim_printf("%s\t\t0x%08X\n",mips_gpr_string[i],vcpu->gpr.ureg[i]); + sim_printf("hi\t\t0x%08X\n",vcpu->gpr.v.hi); + sim_printf("lo\t\t0x%08X\n",vcpu->gpr.v.lo); + sim_printf("pc\t\t0x%08X\n",vcpu->gpr.pc); + sim_printf("======================Dump Complete======================\n"); +} + +void mips_vcpu_start_interpretation(vmcb_p vcpu) +{ + while(!_bittest(&vcpu->flags,mipsivm_vcpu_flags_stop_interpretation)) + { + // Reference HVA by GPA. + u32* ip=(u32*)mips_ref_hmem(vcpu,vcpu->gpr.pc,true,false,true); + mips_instruction mi; + if(ip==null) // Either the page is not present, or page does not exist. + { + sim_printf("Nested Page Fault on Execution! pc=0x%08X\n",vcpu->gpr.pc); + break; + } + // Page is present and accessible. + mi.value=*ip; + cpu_interpreter_by_opcode[mi.r.op](vcpu,mi); + vcpu->gpr.ureg[0]=0; // "Hardwire" zero register to zero. + vcpu->eic++; // Increment Instruction Counter; + } } \ No newline at end of file diff --git a/src/xpf/windows/system.c b/src/xpf/windows/system.c new file mode 100644 index 0000000..e1475cd --- /dev/null +++ b/src/xpf/windows/system.c @@ -0,0 +1,69 @@ +/* + mipsivm - MIPS Interpreting Virtual Machine + + Copyright 2018-2020, Yaotian "Zero" Tang. All rights reserved. + + This file defines essential functions for mipsivm on Windows. + + This program is distributed in the hope that it will be useful, but + without any warranty (no matter implied warranty or merchantability + or fitness for a particular purpose, etc.). + + File Location: /xpf/windows/system.c +*/ + +#include + +PVOID load_section(IN PSTR FilePath,OUT PULONG Size) +{ + PVOID Buffer=NULL; + HANDLE hFile=CreateFileA(FilePath,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); + if(hFile!=INVALID_HANDLE_VALUE) + { + ULONG FileSize=GetFileSize(hFile,NULL); + if(FileSize!=INVALID_FILE_SIZE) + { + ULONG PageCount=FileSize>>12; + ULONG PageRemainder=FileSize&0xFFF; + if(PageRemainder)PageCount++; + *Size=PageCount<<12; + Buffer=VirtualAlloc(NULL,*Size,MEM_COMMIT,PAGE_READWRITE); + if(Buffer) + { + ULONG dwRead; + RtlZeroMemory(Buffer,*Size); + SetFilePointer(hFile,0,NULL,FILE_BEGIN); + ReadFile(hFile,Buffer,FileSize,&dwRead,NULL); + } + } + CloseHandle(hFile); + } + return Buffer; +} + +BOOL unload_section(IN PVOID SectionAddress) +{ + return VirtualFree(SectionAddress,0,MEM_RELEASE); +} + +PVOID alloc_page(IN ULONG Size) +{ + PVOID p=VirtualAlloc(NULL,Size,MEM_COMMIT,PAGE_READWRITE); + if(p)RtlZeroMemory(p,Size); + return p; +} + +BOOL free_page(IN PVOID Address) +{ + return VirtualFree(Address,0,MEM_RELEASE); +} + +PVOID alloc_mem(IN ULONG Size) +{ + return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,Size); +} + +BOOL free_mem(IN PVOID Address) +{ + return HeapFree(GetProcessHeap(),0,Address); +} \ No newline at end of file diff --git a/test/Mars.jar b/test/Mars.jar new file mode 100644 index 0000000..0021281 Binary files /dev/null and b/test/Mars.jar differ diff --git a/test/helloworld/build.bat b/test/helloworld/build.bat new file mode 100644 index 0000000..a8de583 --- /dev/null +++ b/test/helloworld/build.bat @@ -0,0 +1,7 @@ +@echo off + +echo Assembling... +java -jar ..\mars.jar nc a .\helloworld.asm dump .text Binary .\helloworld.text.bin dump .data Binary .\helloworld.data.bin +echo Completed! + +pause. \ No newline at end of file diff --git a/test/helloworld/helloworld.asm b/test/helloworld/helloworld.asm new file mode 100644 index 0000000..f04e46b --- /dev/null +++ b/test/helloworld/helloworld.asm @@ -0,0 +1,11 @@ +.data +text_be_printed: +.asciiz "Hello World!\n" + +.text +main: + addi $v0,$zero,4 + la $a0,text_be_printed + syscall + addi $v0,$zero,10 + syscall \ No newline at end of file diff --git a/test/readme.md b/test/readme.md new file mode 100644 index 0000000..d138729 --- /dev/null +++ b/test/readme.md @@ -0,0 +1,12 @@ +# mipsivm Test Cases +This directory will include a set of test cases. + +## Use of MARS +MARS, acronym that stands for MIPS Assembler and Runtime Simulator, is an IDE written in java. Hence, to run MARS, you will have to install Java SE.
+To test the functionality of mipsivm, we will edit Assembly code with MARS and assemble it. You have to dump the assembled code and data to file so that you can run it. To dump mipsivm, run the following command: +``` +java -jar mars.jar nc a dump .text Binary .text.bin dump .data Binary .data.bin +``` + +## Available Test Cases +- Hello World \ No newline at end of file