2004-08-23 00:15:46 +00:00
/*************************************************************************
* * QVM
* * Copyright ( C ) 2003 by DarkOne
* *
* * 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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * Quake3 compatible virtual machine
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
spike ' s changes .
masks are now done by modulus rather than and
VM_POINTER contains a mask check .
ds_mask is set to the mem allocated for stack and data .
builtins range check written to buffers .
QVM_Step placed in QVM_Exec for efficiency .
an invalid statement was added at the end of the statements to prevent the qvm walking off .
stack pops / pushes are all tested . An extra stack entry was faked to prevent stack checks on double - stack operators from overwriting .
Fixme : there is always the possibility that I missed a potential virus loophole . .
Also , can efficiency be improved much ?
*/
# include "quakedef.h"
# ifdef VM_ANY
2005-01-04 08:07:47 +00:00
# ifdef _MSC_VER //fix this please
2007-10-04 20:29:05 +00:00
# define inline __forceinline
2004-08-23 00:15:46 +00:00
# endif
2007-09-03 22:37:13 +00:00
# define RETURNOFFSETMARKER NULL
2004-08-23 00:15:46 +00:00
typedef enum vm_type_e
{
VM_NONE ,
VM_NATIVE ,
VM_BYTECODE
} vm_type_t ;
struct vm_s {
// common
vm_type_t type ;
char name [ MAX_QPATH ] ;
2005-09-08 01:55:56 +00:00
sys_calldll_t syscalldll ;
sys_callqvm_t syscallqvm ;
2004-08-23 00:15:46 +00:00
// shared
void * hInst ;
// native
2009-07-14 23:42:54 +00:00
qintptr_t ( EXPORT_FN * vmMain ) ( qintptr_t command , qintptr_t arg0 , qintptr_t arg1 , qintptr_t arg2 , qintptr_t arg3 , qintptr_t arg4 , qintptr_t arg5 , qintptr_t arg6 ) ;
2004-08-23 00:15:46 +00:00
} ;
2013-05-11 14:02:55 +00:00
//this is a bit weird. qvm plugins always come from $basedir/$mod/plugins/$foo.qvm
//but native plugins never come from $basedir/$mod/ - too many other engines blindly allow dll downloads etc. Its simply far too insecure if people use other engines.
//q3 gamecode allows it however. yes you could probably get fte to connect via q3 instead and get such a dll.
2013-05-03 04:28:08 +00:00
dllhandle_t * QVM_LoadDLL ( const char * name , qboolean binroot , void * * vmMain , sys_calldll_t syscall )
2004-09-26 04:03:45 +00:00
{
2009-07-18 20:22:32 +00:00
void ( EXPORT_FN * dllEntry ) ( sys_calldll_t syscall ) ;
2009-11-15 03:13:48 +00:00
char dllname_arch [ MAX_OSPATH ] ; //id compatible
char dllname_anycpu [ MAX_OSPATH ] ; //simple
2009-03-03 01:52:30 +00:00
dllhandle_t * hVM ;
dllfunction_t funcs [ ] =
{
{ ( void * ) & dllEntry , " dllEntry " } ,
{ ( void * ) vmMain , " vmMain " } ,
{ NULL , NULL } ,
} ;
2005-12-15 19:15:39 +00:00
2013-05-03 04:28:08 +00:00
snprintf ( dllname_arch , sizeof ( dllname_arch ) , " %s " ARCH_CPU_POSTFIX ARCH_DL_POSTFIX , name ) ;
snprintf ( dllname_anycpu , sizeof ( dllname_anycpu ) , " %s " ARCH_DL_POSTFIX , name ) ;
2004-09-26 04:03:45 +00:00
hVM = NULL ;
{
2009-07-14 23:42:54 +00:00
char fname [ MAX_OSPATH ] ;
2004-09-26 04:03:45 +00:00
char * gpath ;
2009-07-14 23:42:54 +00:00
2013-05-03 04:28:08 +00:00
if ( binroot )
{
if ( ! hVM & & FS_NativePath ( dllname_arch , FS_BINARYPATH , fname , sizeof ( fname ) ) )
hVM = Sys_LoadLibrary ( fname , funcs ) ;
if ( ! hVM & & FS_NativePath ( dllname_anycpu , FS_BINARYPATH , fname , sizeof ( fname ) ) )
hVM = Sys_LoadLibrary ( fname , funcs ) ;
}
else
{
// run through the search paths
gpath = NULL ;
while ( ! hVM )
2004-09-26 04:03:45 +00:00
{
2013-05-03 04:28:08 +00:00
gpath = COM_NextPath ( gpath ) ;
if ( ! gpath )
break ; // couldn't find one anywhere
if ( ! hVM )
{
snprintf ( fname , sizeof ( fname ) , " %s/%s " , gpath , dllname_arch ) ;
Con_DPrintf ( " Loading native: %s \n " , fname ) ;
hVM = Sys_LoadLibrary ( fname , funcs ) ;
}
if ( ! hVM )
{
snprintf ( fname , sizeof ( fname ) , " %s/%s " , gpath , dllname_anycpu ) ;
Con_DPrintf ( " Loading native: %s \n " , fname ) ;
hVM = Sys_LoadLibrary ( fname , funcs ) ;
}
2004-09-26 04:03:45 +00:00
}
}
}
if ( ! hVM ) return NULL ;
2005-01-28 04:26:36 +00:00
( * dllEntry ) ( syscall ) ;
2004-09-26 04:03:45 +00:00
return hVM ;
}
2004-08-23 00:15:46 +00:00
2004-09-26 04:03:45 +00:00
/*
* * Sys_UnloadDLL
*/
2009-03-03 01:52:30 +00:00
void QVM_UnloadDLL ( dllhandle_t * handle )
2004-09-26 04:03:45 +00:00
{
if ( handle )
{
2009-03-03 01:52:30 +00:00
Sys_CloseLibrary ( handle ) ;
2004-09-26 04:03:45 +00:00
}
}
2004-08-23 00:15:46 +00:00
// ------------------------- * QVM files * -------------------------
# define VM_MAGIC 0x12721444
2008-11-09 22:29:28 +00:00
# define VM_MAGIC2 0x12721445
2004-08-23 00:15:46 +00:00
# pragma pack(push,1)
typedef struct vmHeader_s
{
int vmMagic ;
int instructionCount ;
int codeOffset ;
int codeLength ;
int dataOffset ;
int dataLength ; // should be byteswapped on load
int litLength ; // copy as is
int bssLength ; // zero filled memory appended to datalength
2008-11-09 22:29:28 +00:00
//valid only in V2.
int jtrgLength ; // number of jump table targets
2004-08-23 00:15:46 +00:00
} vmHeader_t ;
# pragma pack(pop)
// ------------------------- * in memory representation * -------------------------
typedef struct qvm_s
{
// segments
2007-09-03 22:37:13 +00:00
unsigned int * cs ; // code segment, each instruction is 2 ints
2005-08-07 13:21:48 +00:00
qbyte * ds ; // data segment, partially filled on load (data, lit, bss)
qbyte * ss ; // stack segment, (follows immediatly after ds, corrupting data before vm)
2004-08-23 00:15:46 +00:00
// pointer registers
2007-09-03 22:37:13 +00:00
unsigned int * pc ; // program counter, points to cs, goes up
unsigned int * sp ; // stack pointer, initially points to end of ss, goes down
unsigned int bp ; // base pointer, initially len_ds+len_ss/2
2004-08-23 00:15:46 +00:00
2007-09-03 22:37:13 +00:00
unsigned int * min_sp ;
unsigned int * max_sp ;
unsigned int min_bp ;
unsigned int max_bp ;
2005-08-21 04:50:16 +00:00
2004-08-23 00:15:46 +00:00
// status
unsigned int len_cs ; // size of cs
unsigned int len_ds ; // size of ds
unsigned int len_ss ; // size of ss
2007-09-03 22:37:13 +00:00
unsigned int ds_mask ; // ds mask (ds+ss)
2004-08-23 00:15:46 +00:00
// memory
unsigned int mem_size ;
qbyte * mem_ptr ;
2005-08-21 04:50:16 +00:00
// unsigned int cycles; // command cicles executed
2005-09-08 01:55:56 +00:00
sys_callqvm_t syscall ;
2004-08-23 00:15:46 +00:00
} qvm_t ;
2009-03-03 01:52:30 +00:00
qvm_t * QVM_LoadVM ( const char * name , sys_callqvm_t syscall ) ;
void QVM_UnLoadVM ( qvm_t * qvm ) ;
int QVM_ExecVM ( qvm_t * qvm , int command , int arg0 , int arg1 , int arg2 , int arg3 , int arg4 , int arg5 , int arg6 , int arg7 ) ;
2004-08-23 00:15:46 +00:00
// ------------------------- * OP.CODES * -------------------------
typedef enum qvm_op_e
{
OP_UNDEF ,
OP_NOP ,
OP_BREAK ,
OP_ENTER , // b32
OP_LEAVE , // b32
OP_CALL ,
OP_PUSH ,
OP_POP ,
OP_CONST , // b32
OP_LOCAL , // b32
OP_JUMP ,
// -------------------
OP_EQ , // b32
OP_NE , // b32
OP_LTI , // b32
OP_LEI , // b32
OP_GTI , // b32
OP_GEI , // b32
OP_LTU , // b32
OP_LEU , // b32
OP_GTU , // b32
OP_GEU , // b32
OP_EQF , // b32
OP_NEF , // b32
OP_LTF , // b32
OP_LEF , // b32
OP_GTF , // b32
OP_GEF , // b32
// -------------------
OP_LOAD1 ,
OP_LOAD2 ,
OP_LOAD4 ,
OP_STORE1 ,
OP_STORE2 ,
OP_STORE4 ,
OP_ARG , // b8
OP_BLOCK_COPY , // b32
//-------------------
OP_SEX8 ,
OP_SEX16 ,
OP_NEGI ,
OP_ADD ,
OP_SUB ,
OP_DIVI ,
OP_DIVU ,
OP_MODI ,
OP_MODU ,
OP_MULI ,
OP_MULU ,
OP_BAND ,
OP_BOR ,
OP_BXOR ,
OP_BCOM ,
OP_LSH ,
OP_RSHI ,
OP_RSHU ,
OP_NEGF ,
OP_ADDF ,
OP_SUBF ,
OP_DIVF ,
OP_MULF ,
OP_CVIF ,
OP_CVFI
} qvm_op_t ;
// ------------------------- * Init & ShutDown * -------------------------
/*
* * QVM_Load
*/
2009-03-03 01:52:30 +00:00
qvm_t * QVM_LoadVM ( const char * name , sys_callqvm_t syscall )
2004-08-23 00:15:46 +00:00
{
char path [ MAX_QPATH ] ;
2009-05-24 10:11:17 +00:00
vmHeader_t header , * srcheader ;
2004-08-23 00:15:46 +00:00
qvm_t * qvm ;
qbyte * raw ;
int n ;
2010-11-02 23:17:25 +00:00
unsigned int i ;
2004-08-23 00:15:46 +00:00
2011-07-22 15:11:35 +00:00
Q_snprintfz ( path , sizeof ( path ) , " %s.qvm " , name ) ;
2011-05-19 13:34:07 +00:00
FS_LoadFile ( path , ( void * * ) & raw ) ;
2004-08-23 00:15:46 +00:00
// file not found
if ( ! raw ) return NULL ;
2009-05-24 10:11:17 +00:00
srcheader = ( vmHeader_t * ) raw ;
header . vmMagic = LittleLong ( srcheader - > vmMagic ) ;
header . instructionCount = LittleLong ( srcheader - > instructionCount ) ;
header . codeOffset = LittleLong ( srcheader - > codeOffset ) ;
header . codeLength = LittleLong ( srcheader - > codeLength ) ;
header . dataOffset = LittleLong ( srcheader - > dataOffset ) ;
header . dataLength = LittleLong ( srcheader - > dataLength ) ;
header . litLength = LittleLong ( srcheader - > litLength ) ;
header . bssLength = LittleLong ( srcheader - > bssLength ) ;
if ( header . vmMagic = = VM_MAGIC2 )
2008-11-09 22:29:28 +00:00
{ //version2 cotains a jump table of sorts
//it is redundant information and can be ignored
//its also more useful for jit rather than bytecode
2009-05-24 10:11:17 +00:00
header . jtrgLength = LittleLong ( srcheader - > jtrgLength ) ;
2008-11-09 22:29:28 +00:00
}
2004-08-23 00:15:46 +00:00
// check file
2011-06-02 05:16:44 +00:00
if ( ( header . vmMagic ! = VM_MAGIC & & header . vmMagic ! = VM_MAGIC2 ) | | header . instructionCount < = 0 | | header . codeLength < = 0 )
2004-08-23 00:15:46 +00:00
{
2008-05-25 22:23:43 +00:00
Con_Printf ( " %s: invalid qvm file \n " , name ) ;
2009-05-24 10:11:17 +00:00
FS_FreeFile ( raw ) ;
2004-08-23 00:15:46 +00:00
return NULL ;
}
// create vitrual machine
qvm = Z_Malloc ( sizeof ( qvm_t ) ) ;
2009-05-24 10:11:17 +00:00
qvm - > len_cs = header . instructionCount + 1 ; //bad opcode padding.
qvm - > len_ds = header . dataLength + header . litLength + header . bssLength ;
2004-08-23 00:15:46 +00:00
qvm - > len_ss = 256 * 1024 ; // 256KB stack space
// memory
2005-08-21 04:50:16 +00:00
qvm - > ds_mask = qvm - > len_ds * sizeof ( qbyte ) + ( qvm - > len_ss + 16 * 4 ) * sizeof ( qbyte ) ; //+4 for a stack check decrease
2007-09-03 22:37:13 +00:00
for ( i = 0 ; i < sizeof ( qvm - > ds_mask ) * 8 - 1 ; i + + )
2004-08-23 00:15:46 +00:00
{
2010-11-02 23:17:25 +00:00
if ( ( 1 < < i ) > = qvm - > ds_mask ) //is this bit greater than our minimum?
2004-08-23 00:15:46 +00:00
break ;
}
2012-04-24 07:59:11 +00:00
qvm - > len_ss = ( 1 < < i ) - qvm - > len_ds * ( int ) sizeof ( qbyte ) - 4 ; //expand the stack space to fill it.
2004-08-23 00:15:46 +00:00
qvm - > ds_mask = qvm - > len_ds * sizeof ( qbyte ) + ( qvm - > len_ss + 4 ) * sizeof ( qbyte ) ;
2005-08-07 13:21:48 +00:00
qvm - > len_ss - = qvm - > len_ss & 7 ;
2004-08-23 00:15:46 +00:00
2007-09-03 22:37:13 +00:00
qvm - > mem_size = qvm - > len_cs * sizeof ( int ) * 2 + qvm - > ds_mask ;
2004-08-23 00:15:46 +00:00
qvm - > mem_ptr = Z_Malloc ( qvm - > mem_size ) ;
// set pointers
2007-09-03 22:37:13 +00:00
qvm - > cs = ( unsigned int * ) qvm - > mem_ptr ;
qvm - > ds = ( qbyte * ) ( qvm - > mem_ptr + qvm - > len_cs * sizeof ( int ) * 2 ) ;
2004-08-23 00:15:46 +00:00
qvm - > ss = ( qbyte * ) ( ( qbyte * ) qvm - > ds + qvm - > len_ds * sizeof ( qbyte ) ) ;
//waste 32 bits here.
//As the opcodes often check stack 0 and 1, with a backwards stack, 1 can leave the stack area. This is where we compensate for it.
// setup registers
qvm - > pc = qvm - > cs ;
2007-09-03 22:37:13 +00:00
qvm - > sp = ( unsigned int * ) ( qvm - > ss + qvm - > len_ss ) ;
2004-08-23 00:15:46 +00:00
qvm - > bp = qvm - > len_ds + qvm - > len_ss / 2 ;
2005-08-21 04:50:16 +00:00
// qvm->cycles=0;
2004-08-23 00:15:46 +00:00
qvm - > syscall = syscall ;
2005-08-07 13:21:48 +00:00
qvm - > ds_mask - - ;
2007-09-03 22:37:13 +00:00
qvm - > min_sp = ( unsigned int * ) ( qvm - > ds + qvm - > len_ds + qvm - > len_ss / 2 ) ;
qvm - > max_sp = ( unsigned int * ) ( qvm - > ds + qvm - > len_ds + qvm - > len_ss ) ;
2005-08-21 04:50:16 +00:00
qvm - > min_bp = qvm - > len_ds ;
qvm - > max_bp = qvm - > len_ds + qvm - > len_ss / 2 ;
qvm - > bp = qvm - > max_bp ;
2004-08-23 00:15:46 +00:00
// load instructions
{
2009-05-24 10:11:17 +00:00
qbyte * src = raw + header . codeOffset ;
2007-09-03 22:37:13 +00:00
int * dst = ( int * ) qvm - > cs ;
2009-05-24 10:11:17 +00:00
int total = header . instructionCount ;
2004-08-23 00:15:46 +00:00
qvm_op_t op ;
for ( n = 0 ; n < total ; n + + )
{
op = * src + + ;
2007-09-03 22:37:13 +00:00
* dst + + = ( int ) op ;
2004-08-23 00:15:46 +00:00
switch ( op )
{
case OP_ENTER :
case OP_LEAVE :
case OP_CONST :
case OP_LOCAL :
case OP_EQ :
case OP_NE :
case OP_LTI :
case OP_LEI :
case OP_GTI :
case OP_GEI :
case OP_LTU :
case OP_LEU :
case OP_GTU :
case OP_GEU :
case OP_EQF :
case OP_NEF :
case OP_LTF :
case OP_LEF :
case OP_GTF :
case OP_GEF :
case OP_BLOCK_COPY :
2007-09-03 22:37:13 +00:00
* dst + + = LittleLong ( * ( int * ) src ) ;
2004-08-23 00:15:46 +00:00
src + = 4 ;
break ;
case OP_ARG :
2007-09-03 22:37:13 +00:00
* dst + + = ( int ) * src + + ;
2004-08-23 00:15:46 +00:00
break ;
default :
* dst + + = 0 ;
break ;
}
}
* dst + + = OP_BREAK ; //in case someone 'forgot' the return on the last function.
* dst + + = 0 ;
}
// load data segment
{
2009-05-24 10:11:17 +00:00
int * src = ( int * ) ( raw + header . dataOffset ) ;
2007-09-03 22:37:13 +00:00
int * dst = ( int * ) qvm - > ds ;
2009-05-24 10:11:17 +00:00
int total = header . dataLength / 4 ;
2004-08-23 00:15:46 +00:00
for ( n = 0 ; n < total ; n + + )
* dst + + = LittleLong ( * src + + ) ;
2009-05-24 10:11:17 +00:00
memcpy ( dst , src , header . litLength ) ;
2004-08-23 00:15:46 +00:00
}
2009-05-24 10:11:17 +00:00
FS_FreeFile ( raw ) ;
2004-08-23 00:15:46 +00:00
return qvm ;
}
/*
* * QVM_UnLoad
*/
2009-03-03 01:52:30 +00:00
void QVM_UnLoadVM ( qvm_t * qvm )
2004-08-23 00:15:46 +00:00
{
Z_Free ( qvm - > mem_ptr ) ;
2005-12-15 19:15:39 +00:00
Z_Free ( qvm ) ;
2004-08-23 00:15:46 +00:00
}
// ------------------------- * private execution stuff * -------------------------
/*
* * QVM_Goto
2009-07-11 18:25:41 +00:00
( inlined this the old fashioned way )
2004-08-23 00:15:46 +00:00
*/
2009-07-11 18:25:41 +00:00
# define QVM_Goto(vm,addr) \
do { \
if ( addr < 0 | | addr > vm - > len_cs ) \
Sys_Error ( " VM run time error: program jumped off to hyperspace \n " ) ; \
vm - > pc = vm - > cs + addr * 2 ; \
} while ( 0 )
//static void inline QVM_Goto(qvm_t *vm, int addr)
//{
// if(addr<0 || addr>vm->len_cs)
// Sys_Error("VM run time error: program jumped off to hyperspace\n");
// vm->pc=vm->cs+addr*2;
//}
2004-08-23 00:15:46 +00:00
/*
* * QVM_Call
* *
* * calls function
*/
static void inline QVM_Call ( qvm_t * vm , int addr )
{
2004-09-24 02:37:25 +00:00
vm - > sp - - ;
2005-08-21 04:50:16 +00:00
if ( vm - > sp < vm - > min_sp ) Sys_Error ( " QVM Stack underflow " ) ;
2004-09-24 02:37:25 +00:00
2004-08-23 00:15:46 +00:00
if ( addr < 0 )
{
// system trap function
{
2007-09-03 22:37:13 +00:00
int * fp ;
2004-08-23 00:15:46 +00:00
2007-09-03 22:37:13 +00:00
fp = ( int * ) ( vm - > ds + vm - > bp ) + 2 ;
2004-08-23 00:15:46 +00:00
vm - > sp [ 0 ] = vm - > syscall ( vm - > ds , vm - > ds_mask , - addr - 1 , fp ) ;
return ;
}
}
2005-08-21 04:50:16 +00:00
if ( addr > = vm - > len_cs )
2004-08-23 00:15:46 +00:00
Sys_Error ( " VM run time error: program jumped off to hyperspace \n " ) ;
2007-09-03 22:37:13 +00:00
vm - > sp [ 0 ] = ( vm - > pc - vm - > cs ) ; // push pc /return address/
2004-08-23 00:15:46 +00:00
vm - > pc = vm - > cs + addr * 2 ;
2004-12-21 04:38:53 +00:00
if ( ! vm - > pc )
Sys_Error ( " VM run time error: program called the void \n " ) ;
2004-08-23 00:15:46 +00:00
}
/*
* * QVM_Enter
* *
* * [ oPC ] [ 0 ] [ . . . . . . . ] | < - oldBP
* * ^ BP
*/
2007-09-03 22:37:13 +00:00
static void inline QVM_Enter ( qvm_t * vm , int size )
2004-08-23 00:15:46 +00:00
{
2007-09-03 22:37:13 +00:00
int * fp ;
2004-08-23 00:15:46 +00:00
vm - > bp - = size ;
2005-08-21 04:50:16 +00:00
if ( vm - > bp < vm - > min_bp )
2004-08-23 00:15:46 +00:00
Sys_Error ( " VM run time error: out of stack \n " ) ;
2007-09-03 22:37:13 +00:00
fp = ( int * ) ( vm - > ds + vm - > bp ) ;
2005-08-21 04:50:16 +00:00
fp [ 0 ] = vm - > sp - vm - > max_sp ; // unknown /maybe size/
2004-08-23 00:15:46 +00:00
fp [ 1 ] = * vm - > sp + + ; // saved PC
2005-08-21 04:50:16 +00:00
if ( vm - > sp > vm - > max_sp ) Sys_Error ( " QVM Stack overflow " ) ;
2004-08-23 00:15:46 +00:00
}
/*
* * QVM_Return
*/
2007-09-03 22:37:13 +00:00
static void inline QVM_Return ( qvm_t * vm , int size )
2004-08-23 00:15:46 +00:00
{
2007-09-03 22:37:13 +00:00
int * fp ;
2004-08-23 00:15:46 +00:00
2007-09-03 22:37:13 +00:00
fp = ( int * ) ( vm - > ds + vm - > bp ) ;
2004-08-23 00:15:46 +00:00
vm - > bp + = size ;
2005-08-21 04:50:16 +00:00
if ( vm - > bp > vm - > max_bp )
2004-09-24 02:37:25 +00:00
Sys_Error ( " VM run time error: freed too much stack \n " ) ;
2004-12-05 08:18:14 +00:00
if ( fp [ 1 ] > = vm - > len_cs * 2 )
2011-01-29 21:01:40 +00:00
if ( ( size_t ) ( vm - > cs + fp [ 1 ] ) ! = ( size_t ) RETURNOFFSETMARKER ) //this being false causes the program to quit.
2013-03-12 22:47:42 +00:00
Sys_Error ( " VM run time error: program returned to hyperspace (%p, %#x) \n " , ( char * ) vm - > cs , fp [ 1 ] ) ;
2004-09-24 02:37:25 +00:00
if ( fp [ 1 ] < 0 )
2011-01-29 21:01:40 +00:00
if ( ( size_t ) ( vm - > cs + fp [ 1 ] ) ! = ( size_t ) RETURNOFFSETMARKER )
2004-09-26 06:26:50 +00:00
Sys_Error ( " VM run time error: program returned to negative hyperspace \n " ) ;
2004-09-24 02:37:25 +00:00
2005-08-21 04:50:16 +00:00
if ( vm - > sp - vm - > max_sp ! = fp [ 0 ] )
Sys_Error ( " VM run time error: stack push/pop mismatch \n " ) ;
2004-08-23 00:15:46 +00:00
vm - > pc = vm - > cs + fp [ 1 ] ; // restore PC
}
// ------------------------- * execution * -------------------------
/*
* * VM_Exec
*/
2009-03-03 01:52:30 +00:00
int QVM_ExecVM ( register qvm_t * qvm , int command , int arg0 , int arg1 , int arg2 , int arg3 , int arg4 , int arg5 , int arg6 , int arg7 )
2004-08-23 00:15:46 +00:00
{
//remember that the stack is backwards. push takes 1.
2005-08-21 04:50:16 +00:00
//FIXME: does it matter that our stack pointer (qvm->sp) is backwards compared to q3?
//We are more consistant of course, but this simply isn't what q3 does.
2004-08-23 00:15:46 +00:00
//all stack shifts in this function are referenced through these 2 macros.
2005-08-21 04:50:16 +00:00
# define POP(t) qvm->sp+=t;if (qvm->sp > qvm->max_sp) Sys_Error("QVM Stack underflow");
# define PUSH(v) qvm->sp--;if (qvm->sp < qvm->min_sp) Sys_Error("QVM Stack overflow");*qvm->sp=v
2005-08-07 18:08:13 +00:00
qvm_op_t op = - 1 ;
2007-09-03 22:37:13 +00:00
unsigned int param ;
2004-08-23 00:15:46 +00:00
2007-09-03 22:37:13 +00:00
int * fp ;
unsigned int * oldpc ;
2004-08-23 00:15:46 +00:00
2005-08-21 04:50:16 +00:00
oldpc = qvm - > pc ;
2004-08-23 00:15:46 +00:00
// setup execution environment
2007-09-03 22:37:13 +00:00
qvm - > pc = RETURNOFFSETMARKER ;
2005-08-21 04:50:16 +00:00
// qvm->cycles=0;
2004-08-23 00:15:46 +00:00
// prepare local stack
2005-08-21 04:50:16 +00:00
qvm - > bp - = 15 * 4 ; //we have to do this each call for the sake of (reliable) recursion.
2007-09-03 22:37:13 +00:00
fp = ( int * ) ( qvm - > ds + qvm - > bp ) ;
2004-08-23 00:15:46 +00:00
// push all params
fp [ 0 ] = 0 ;
fp [ 1 ] = 0 ;
fp [ 2 ] = command ;
fp [ 3 ] = arg0 ;
fp [ 4 ] = arg1 ;
fp [ 5 ] = arg2 ;
fp [ 6 ] = arg3 ;
fp [ 7 ] = arg4 ;
fp [ 8 ] = arg5 ;
fp [ 9 ] = arg6 ;
fp [ 10 ] = arg7 ; // arg7;
fp [ 11 ] = 0 ; // arg8;
fp [ 12 ] = 0 ; // arg9;
fp [ 13 ] = 0 ; // arg10;
fp [ 14 ] = 0 ; // arg11;
QVM_Call ( qvm , 0 ) ;
2004-09-24 02:37:25 +00:00
for ( ; ; )
2004-08-23 00:15:46 +00:00
{
// fetch next command
2004-09-24 02:37:25 +00:00
op = * qvm - > pc + + ;
2004-08-23 00:15:46 +00:00
param = * qvm - > pc + + ;
2005-08-21 04:50:16 +00:00
// qvm->cycles++;
2004-08-23 00:15:46 +00:00
switch ( op )
{
// aux
case OP_UNDEF :
case OP_NOP :
break ;
2005-08-21 04:50:16 +00:00
default :
2004-08-23 00:15:46 +00:00
case OP_BREAK : // break to debugger
2013-05-11 05:03:07 +00:00
Sys_Error ( " VM hit an OP_BREAK opcode " ) ;
2004-08-23 00:15:46 +00:00
break ;
// subroutines
case OP_ENTER :
QVM_Enter ( qvm , param ) ;
break ;
case OP_LEAVE :
QVM_Return ( qvm , param ) ;
2004-09-24 02:37:25 +00:00
2011-01-29 21:01:40 +00:00
if ( ( size_t ) qvm - > pc = = ( size_t ) RETURNOFFSETMARKER )
2004-09-24 02:37:25 +00:00
{
// pick return value from stack
2005-08-21 04:50:16 +00:00
qvm - > pc = oldpc ;
qvm - > bp + = 15 * 4 ;
2005-08-26 22:56:51 +00:00
// if(qvm->bp!=qvm->max_bp)
// Sys_Error("VM run time error: freed too much stack\n");
2005-08-21 04:50:16 +00:00
param = qvm - > sp [ 0 ] ;
POP ( 1 ) ;
return param ;
2004-09-24 02:37:25 +00:00
}
2004-08-23 00:15:46 +00:00
break ;
case OP_CALL :
param = * qvm - > sp ;
POP ( 1 ) ;
QVM_Call ( qvm , param ) ;
break ;
// stack
case OP_PUSH :
2005-08-21 04:50:16 +00:00
PUSH ( * qvm - > sp ) ;
2004-08-23 00:15:46 +00:00
break ;
case OP_POP :
POP ( 1 ) ;
break ;
case OP_CONST :
PUSH ( param ) ;
break ;
case OP_LOCAL :
PUSH ( param + qvm - > bp ) ;
break ;
// branching
case OP_JUMP :
param = * qvm - > sp ;
POP ( 1 ) ;
QVM_Goto ( qvm , param ) ;
break ;
case OP_EQ :
if ( qvm - > sp [ 1 ] = = qvm - > sp [ 0 ] ) QVM_Goto ( qvm , param ) ;
POP ( 2 ) ;
break ;
case OP_NE :
if ( qvm - > sp [ 1 ] ! = qvm - > sp [ 0 ] ) QVM_Goto ( qvm , param ) ;
POP ( 2 ) ;
break ;
case OP_LTI :
2007-09-03 22:37:13 +00:00
if ( * ( signed int * ) & qvm - > sp [ 1 ] < * ( signed int * ) & qvm - > sp [ 0 ] ) QVM_Goto ( qvm , param ) ;
2004-08-23 00:15:46 +00:00
POP ( 2 ) ;
break ;
case OP_LEI :
2007-09-03 22:37:13 +00:00
if ( * ( signed int * ) & qvm - > sp [ 1 ] < = * ( signed int * ) & qvm - > sp [ 0 ] ) QVM_Goto ( qvm , param ) ;
2004-08-23 00:15:46 +00:00
POP ( 2 ) ;
break ;
case OP_GTI :
2007-09-03 22:37:13 +00:00
if ( * ( signed int * ) & qvm - > sp [ 1 ] > * ( signed int * ) & qvm - > sp [ 0 ] ) QVM_Goto ( qvm , param ) ;
2004-08-23 00:15:46 +00:00
POP ( 2 ) ;
break ;
case OP_GEI :
2007-09-03 22:37:13 +00:00
if ( * ( signed int * ) & qvm - > sp [ 1 ] > = * ( signed int * ) & qvm - > sp [ 0 ] ) QVM_Goto ( qvm , param ) ;
2004-08-23 00:15:46 +00:00
POP ( 2 ) ;
break ;
case OP_LTU :
2007-09-03 22:37:13 +00:00
if ( * ( unsigned int * ) & qvm - > sp [ 1 ] < * ( unsigned int * ) & qvm - > sp [ 0 ] ) QVM_Goto ( qvm , param ) ;
2004-08-23 00:15:46 +00:00
POP ( 2 ) ;
break ;
case OP_LEU :
2007-09-03 22:37:13 +00:00
if ( * ( unsigned int * ) & qvm - > sp [ 1 ] < = * ( unsigned int * ) & qvm - > sp [ 0 ] ) QVM_Goto ( qvm , param ) ;
2004-08-23 00:15:46 +00:00
POP ( 2 ) ;
break ;
case OP_GTU :
2007-09-03 22:37:13 +00:00
if ( * ( unsigned int * ) & qvm - > sp [ 1 ] > * ( unsigned int * ) & qvm - > sp [ 0 ] ) QVM_Goto ( qvm , param ) ;
2004-08-23 00:15:46 +00:00
POP ( 2 ) ;
break ;
case OP_GEU :
2007-09-03 22:37:13 +00:00
if ( * ( unsigned int * ) & qvm - > sp [ 1 ] > = * ( unsigned int * ) & qvm - > sp [ 0 ] ) QVM_Goto ( qvm , param ) ;
2004-08-23 00:15:46 +00:00
POP ( 2 ) ;
break ;
case OP_EQF :
if ( * ( float * ) & qvm - > sp [ 1 ] = = * ( float * ) & qvm - > sp [ 0 ] ) QVM_Goto ( qvm , param ) ;
POP ( 2 ) ;
break ;
case OP_NEF :
if ( * ( float * ) & qvm - > sp [ 1 ] ! = * ( float * ) & qvm - > sp [ 0 ] ) QVM_Goto ( qvm , param ) ;
POP ( 2 ) ;
break ;
case OP_LTF :
if ( * ( float * ) & qvm - > sp [ 1 ] < * ( float * ) & qvm - > sp [ 0 ] ) QVM_Goto ( qvm , param ) ;
POP ( 2 ) ;
break ;
case OP_LEF :
if ( * ( float * ) & qvm - > sp [ 1 ] < = * ( float * ) & qvm - > sp [ 0 ] ) QVM_Goto ( qvm , param ) ;
POP ( 2 ) ;
break ;
case OP_GTF :
if ( * ( float * ) & qvm - > sp [ 1 ] > * ( float * ) & qvm - > sp [ 0 ] ) QVM_Goto ( qvm , param ) ;
POP ( 2 ) ;
break ;
case OP_GEF :
if ( * ( float * ) & qvm - > sp [ 1 ] > = * ( float * ) & qvm - > sp [ 0 ] ) QVM_Goto ( qvm , param ) ;
POP ( 2 ) ;
break ;
// memory I/O: masks protect main memory
case OP_LOAD1 :
2007-09-03 22:37:13 +00:00
* ( unsigned int * ) & qvm - > sp [ 0 ] = * ( unsigned char * ) & qvm - > ds [ qvm - > sp [ 0 ] & qvm - > ds_mask ] ;
2004-08-23 00:15:46 +00:00
break ;
case OP_LOAD2 :
2007-09-03 22:37:13 +00:00
* ( unsigned int * ) & qvm - > sp [ 0 ] = * ( unsigned short * ) & qvm - > ds [ qvm - > sp [ 0 ] & qvm - > ds_mask ] ;
2004-08-23 00:15:46 +00:00
break ;
case OP_LOAD4 :
2007-09-03 22:37:13 +00:00
* ( unsigned int * ) & qvm - > sp [ 0 ] = * ( unsigned int * ) & qvm - > ds [ qvm - > sp [ 0 ] & qvm - > ds_mask ] ;
2004-08-23 00:15:46 +00:00
break ;
case OP_STORE1 :
2005-08-21 04:50:16 +00:00
* ( qbyte * ) & qvm - > ds [ qvm - > sp [ 1 ] & qvm - > ds_mask ] = ( qbyte ) ( qvm - > sp [ 0 ] & 0xFF ) ;
2004-08-23 00:15:46 +00:00
POP ( 2 ) ;
break ;
case OP_STORE2 :
2005-08-21 04:50:16 +00:00
* ( unsigned short * ) & qvm - > ds [ qvm - > sp [ 1 ] & qvm - > ds_mask ] = ( unsigned short ) ( qvm - > sp [ 0 ] & 0xFFFF ) ;
2004-08-23 00:15:46 +00:00
POP ( 2 ) ;
break ;
case OP_STORE4 :
2007-09-03 22:37:13 +00:00
* ( unsigned int * ) & qvm - > ds [ qvm - > sp [ 1 ] & qvm - > ds_mask ] = * ( unsigned int * ) & qvm - > sp [ 0 ] ;
2004-08-23 00:15:46 +00:00
POP ( 2 ) ;
break ;
case OP_ARG :
2007-09-03 22:37:13 +00:00
* ( unsigned int * ) & qvm - > ds [ ( param + qvm - > bp ) & qvm - > ds_mask ] = * ( unsigned int * ) & qvm - > sp [ 0 ] ;
2004-08-23 00:15:46 +00:00
POP ( 1 ) ;
break ;
case OP_BLOCK_COPY :
if ( qvm - > sp [ 1 ] + param < qvm - > ds_mask & & qvm - > sp [ 0 ] + param < qvm - > ds_mask )
2005-08-21 04:50:16 +00:00
{
2004-08-23 00:15:46 +00:00
memmove ( qvm - > ds + ( qvm - > sp [ 1 ] & qvm - > ds_mask ) , qvm - > ds + ( qvm - > sp [ 0 ] & qvm - > ds_mask ) , param ) ;
2005-08-21 04:50:16 +00:00
}
2004-08-23 00:15:46 +00:00
POP ( 2 ) ;
break ;
// integer arithmetic
case OP_SEX8 :
2007-09-03 22:37:13 +00:00
if ( * ( signed int * ) & qvm - > sp [ 0 ] & 0x80 ) * ( signed int * ) & qvm - > sp [ 0 ] | = 0xFFFFFF00 ;
2004-08-23 00:15:46 +00:00
break ;
case OP_SEX16 :
2007-09-03 22:37:13 +00:00
if ( * ( signed int * ) & qvm - > sp [ 0 ] & 0x8000 ) * ( signed int * ) & qvm - > sp [ 0 ] | = 0xFFFF0000 ;
2004-08-23 00:15:46 +00:00
break ;
case OP_NEGI :
2007-09-03 22:37:13 +00:00
* ( signed int * ) & qvm - > sp [ 0 ] = - * ( signed int * ) & qvm - > sp [ 0 ] ;
2004-08-23 00:15:46 +00:00
break ;
case OP_ADD :
2007-09-03 22:37:13 +00:00
* ( signed int * ) & qvm - > sp [ 1 ] + = * ( signed int * ) & qvm - > sp [ 0 ] ;
2004-08-23 00:15:46 +00:00
POP ( 1 ) ;
break ;
case OP_SUB :
2007-09-03 22:37:13 +00:00
* ( signed int * ) & qvm - > sp [ 1 ] - = * ( signed int * ) & qvm - > sp [ 0 ] ;
2004-08-23 00:15:46 +00:00
POP ( 1 ) ;
break ;
case OP_DIVI :
2007-09-03 22:37:13 +00:00
* ( signed int * ) & qvm - > sp [ 1 ] / = * ( signed int * ) & qvm - > sp [ 0 ] ;
2004-08-23 00:15:46 +00:00
POP ( 1 ) ;
break ;
case OP_DIVU :
2007-09-03 22:37:13 +00:00
* ( unsigned int * ) & qvm - > sp [ 1 ] / = ( * ( unsigned int * ) & qvm - > sp [ 0 ] ) ;
2004-08-23 00:15:46 +00:00
POP ( 1 ) ;
break ;
case OP_MODI :
2007-09-03 22:37:13 +00:00
* ( signed int * ) & qvm - > sp [ 1 ] % = * ( signed int * ) & qvm - > sp [ 0 ] ;
2004-08-23 00:15:46 +00:00
POP ( 1 ) ;
break ;
case OP_MODU :
2007-09-03 22:37:13 +00:00
* ( unsigned int * ) & qvm - > sp [ 1 ] % = ( * ( unsigned int * ) & qvm - > sp [ 0 ] ) ;
2005-08-21 04:50:16 +00:00
POP ( 1 ) ;
2004-08-23 00:15:46 +00:00
break ;
case OP_MULI :
2007-09-03 22:37:13 +00:00
* ( signed int * ) & qvm - > sp [ 1 ] * = * ( signed int * ) & qvm - > sp [ 0 ] ;
2004-08-23 00:15:46 +00:00
POP ( 1 ) ;
break ;
case OP_MULU :
2007-09-03 22:37:13 +00:00
* ( unsigned int * ) & qvm - > sp [ 1 ] * = ( * ( unsigned int * ) & qvm - > sp [ 0 ] ) ;
2004-08-23 00:15:46 +00:00
POP ( 1 ) ;
break ;
// logic
case OP_BAND :
2007-09-03 22:37:13 +00:00
* ( unsigned int * ) & qvm - > sp [ 1 ] & = * ( unsigned int * ) & qvm - > sp [ 0 ] ;
2004-08-23 00:15:46 +00:00
POP ( 1 ) ;
break ;
case OP_BOR :
2007-09-03 22:37:13 +00:00
* ( unsigned int * ) & qvm - > sp [ 1 ] | = * ( unsigned int * ) & qvm - > sp [ 0 ] ;
2004-08-23 00:15:46 +00:00
POP ( 1 ) ;
break ;
case OP_BXOR :
2007-09-03 22:37:13 +00:00
* ( unsigned int * ) & qvm - > sp [ 1 ] ^ = * ( unsigned int * ) & qvm - > sp [ 0 ] ;
2004-08-23 00:15:46 +00:00
POP ( 1 ) ;
break ;
case OP_BCOM :
2007-09-03 22:37:13 +00:00
* ( unsigned int * ) & qvm - > sp [ 0 ] = ~ * ( unsigned int * ) & qvm - > sp [ 0 ] ;
2004-08-23 00:15:46 +00:00
break ;
case OP_LSH :
2007-09-03 22:37:13 +00:00
* ( unsigned int * ) & qvm - > sp [ 1 ] < < = * ( unsigned int * ) & qvm - > sp [ 0 ] ;
2004-08-23 00:15:46 +00:00
POP ( 1 ) ;
break ;
case OP_RSHI :
2007-09-03 22:37:13 +00:00
* ( signed int * ) & qvm - > sp [ 1 ] > > = * ( signed int * ) & qvm - > sp [ 0 ] ;
2004-08-23 00:15:46 +00:00
POP ( 1 ) ;
break ;
case OP_RSHU :
2007-09-03 22:37:13 +00:00
* ( unsigned int * ) & qvm - > sp [ 1 ] > > = * ( unsigned int * ) & qvm - > sp [ 0 ] ;
2004-08-23 00:15:46 +00:00
POP ( 1 ) ;
break ;
// floating point arithmetic
case OP_NEGF :
* ( float * ) & qvm - > sp [ 0 ] = - * ( float * ) & qvm - > sp [ 0 ] ;
break ;
case OP_ADDF :
* ( float * ) & qvm - > sp [ 1 ] + = * ( float * ) & qvm - > sp [ 0 ] ;
POP ( 1 ) ;
break ;
case OP_SUBF :
* ( float * ) & qvm - > sp [ 1 ] - = * ( float * ) & qvm - > sp [ 0 ] ;
POP ( 1 ) ;
break ;
case OP_DIVF :
* ( float * ) & qvm - > sp [ 1 ] / = * ( float * ) & qvm - > sp [ 0 ] ;
POP ( 1 ) ;
break ;
case OP_MULF :
* ( float * ) & qvm - > sp [ 1 ] * = * ( float * ) & qvm - > sp [ 0 ] ;
POP ( 1 ) ;
break ;
// format conversion
case OP_CVIF :
2007-09-03 22:37:13 +00:00
* ( float * ) & qvm - > sp [ 0 ] = ( float ) ( signed int ) qvm - > sp [ 0 ] ;
2004-08-23 00:15:46 +00:00
break ;
case OP_CVFI :
2007-09-03 22:37:13 +00:00
* ( signed int * ) & qvm - > sp [ 0 ] = ( signed int ) ( * ( float * ) & qvm - > sp [ 0 ] ) ;
2004-08-23 00:15:46 +00:00
break ;
}
2004-09-24 02:37:25 +00:00
}
2004-08-23 00:15:46 +00:00
}
// ------------------------- * interface * -------------------------
/*
* * VM_PrintInfo
*/
void VM_PrintInfo ( vm_t * vm )
{
qvm_t * qvm ;
2007-09-03 22:37:13 +00:00
Con_Printf ( " %s (%p): " , vm - > name , vm - > hInst ) ;
2004-08-23 00:15:46 +00:00
switch ( vm - > type )
{
case VM_NATIVE :
Con_Printf ( " native \n " ) ;
break ;
2004-09-26 04:03:45 +00:00
2004-08-23 00:15:46 +00:00
case VM_BYTECODE :
Con_Printf ( " interpreted \n " ) ;
if ( ( qvm = vm - > hInst ) )
{
Con_Printf ( " code length: %d \n " , qvm - > len_cs ) ;
Con_Printf ( " data length: %d \n " , qvm - > len_ds ) ;
Con_Printf ( " stack length: %d \n " , qvm - > len_ss ) ;
}
break ;
2004-09-26 04:03:45 +00:00
2004-08-23 00:15:46 +00:00
default :
Con_Printf ( " unknown \n " ) ;
break ;
}
}
/*
* * VM_Create
*/
2013-05-11 14:02:55 +00:00
vm_t * VM_Create ( const char * name , sys_calldll_t syscalldll , sys_callqvm_t syscallqvm )
2004-08-23 00:15:46 +00:00
{
2013-05-11 14:02:55 +00:00
vm_t * vm ;
2005-09-08 01:55:56 +00:00
if ( ! name | | ! * name )
2004-08-23 00:15:46 +00:00
Sys_Error ( " VM_Create: bad parms " ) ;
2013-05-11 14:02:55 +00:00
vm = Z_Malloc ( sizeof ( vm_t ) ) ;
2004-08-23 00:15:46 +00:00
// prepare vm struct
memset ( vm , 0 , sizeof ( vm_t ) ) ;
Q_strncpyz ( vm - > name , name , sizeof ( vm - > name ) ) ;
2005-09-08 01:55:56 +00:00
vm - > syscalldll = syscalldll ;
vm - > syscallqvm = syscallqvm ;
2004-08-23 00:15:46 +00:00
2004-09-26 04:03:45 +00:00
2005-09-08 01:55:56 +00:00
if ( syscalldll )
2004-08-23 00:15:46 +00:00
{
2005-09-08 01:55:56 +00:00
if ( ! COM_CheckParm ( " -nodlls " ) & & ! COM_CheckParm ( " -nosos " ) ) //:)
2004-08-23 00:15:46 +00:00
{
2013-05-03 04:28:08 +00:00
if ( ( vm - > hInst = QVM_LoadDLL ( name , ! syscallqvm , ( void * * ) & vm - > vmMain , syscalldll ) ) )
2005-09-08 01:55:56 +00:00
{
Con_DPrintf ( " Creating native machine \" %s \" \n " , name ) ;
vm - > type = VM_NATIVE ;
return vm ;
}
2004-08-23 00:15:46 +00:00
}
}
2004-09-26 04:03:45 +00:00
2004-08-23 00:15:46 +00:00
2005-09-08 01:55:56 +00:00
if ( syscallqvm )
2004-08-23 00:15:46 +00:00
{
2009-03-03 01:52:30 +00:00
if ( ( vm - > hInst = QVM_LoadVM ( name , syscallqvm ) ) )
2005-09-08 01:55:56 +00:00
{
Con_DPrintf ( " Creating virtual machine \" %s \" \n " , name ) ;
vm - > type = VM_BYTECODE ;
return vm ;
}
2004-08-23 00:15:46 +00:00
}
Z_Free ( vm ) ;
return NULL ;
}
/*
* * VM_Destroy
*/
void VM_Destroy ( vm_t * vm )
{
if ( ! vm ) return ;
switch ( vm - > type )
{
case VM_NATIVE :
2009-03-03 01:52:30 +00:00
if ( vm - > hInst ) QVM_UnloadDLL ( vm - > hInst ) ;
2004-08-23 00:15:46 +00:00
break ;
2004-09-26 04:03:45 +00:00
2004-08-23 00:15:46 +00:00
case VM_BYTECODE :
2009-03-03 01:52:30 +00:00
if ( vm - > hInst ) QVM_UnLoadVM ( vm - > hInst ) ;
2004-08-23 00:15:46 +00:00
break ;
2004-09-26 04:03:45 +00:00
2004-08-23 00:15:46 +00:00
case VM_NONE :
break ;
}
Z_Free ( vm ) ;
}
/*
* * VM_Restart
*/
2013-05-11 14:02:55 +00:00
/*qboolean VM_Restart(vm_t *vm)
2004-08-23 00:15:46 +00:00
{
char name [ MAX_QPATH ] ;
2005-09-08 01:55:56 +00:00
sys_calldll_t syscalldll ;
sys_callqvm_t syscallqvm ;
2004-08-23 00:15:46 +00:00
if ( ! vm ) return false ;
// save params
2005-12-15 19:15:39 +00:00
Q_strncpyz ( name , vm - > name , sizeof ( name ) ) ;
2005-09-08 01:55:56 +00:00
syscalldll = vm - > syscalldll ;
syscallqvm = vm - > syscallqvm ;
2004-08-23 00:15:46 +00:00
// restart
switch ( vm - > type )
{
case VM_NATIVE :
2009-03-03 01:52:30 +00:00
if ( vm - > hInst ) QVM_UnloadDLL ( vm - > hInst ) ;
2004-08-23 00:15:46 +00:00
break ;
2004-09-26 04:03:45 +00:00
2004-08-23 00:15:46 +00:00
case VM_BYTECODE :
2009-03-03 01:52:30 +00:00
if ( vm - > hInst ) QVM_UnLoadVM ( vm - > hInst ) ;
2004-08-23 00:15:46 +00:00
break ;
2004-09-26 04:03:45 +00:00
2004-08-23 00:15:46 +00:00
case VM_NONE :
break ;
}
2005-09-08 01:55:56 +00:00
return VM_Create ( vm , name , syscalldll , syscallqvm ) ! = NULL ;
2013-05-11 14:02:55 +00:00
} */
2004-08-23 00:15:46 +00:00
2005-03-07 08:58:26 +00:00
void * VM_MemoryBase ( vm_t * vm )
{
switch ( vm - > type )
{
case VM_NATIVE :
return NULL ;
case VM_BYTECODE :
return ( ( qvm_t * ) vm - > hInst ) - > ds ;
2005-03-10 03:55:18 +00:00
default :
return NULL ;
2005-03-07 08:58:26 +00:00
}
}
2011-07-30 14:14:56 +00:00
quintptr_t VM_MemoryMask ( vm_t * vm )
{
switch ( vm - > type )
{
case VM_BYTECODE :
return ( ( qvm_t * ) vm - > hInst ) - > ds_mask ;
default :
return ~ ( quintptr_t ) 0 ;
}
}
2005-03-07 08:58:26 +00:00
2009-07-14 23:42:54 +00:00
/*returns true if we're running a 32bit vm on a 64bit host (in case we need workarounds)*/
qboolean VM_NonNative ( vm_t * vm )
{
switch ( vm - > type )
{
case VM_BYTECODE :
return sizeof ( int ) ! = sizeof ( void * ) ;
case VM_NATIVE :
return false ;
default :
return false ;
}
}
2004-08-23 00:15:46 +00:00
/*
* * VM_Call
*/
2009-07-14 23:42:54 +00:00
qintptr_t VARGS VM_Call ( vm_t * vm , qintptr_t instruction , . . . )
2004-08-23 00:15:46 +00:00
{
va_list argptr ;
2009-07-14 23:42:54 +00:00
qintptr_t arg0 , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 , arg7 ;
2004-08-23 00:15:46 +00:00
if ( ! vm ) Sys_Error ( " VM_Call with NULL vm " ) ;
va_start ( argptr , instruction ) ;
2009-07-14 23:42:54 +00:00
arg0 = va_arg ( argptr , qintptr_t ) ;
arg1 = va_arg ( argptr , qintptr_t ) ;
arg2 = va_arg ( argptr , qintptr_t ) ;
arg3 = va_arg ( argptr , qintptr_t ) ;
arg4 = va_arg ( argptr , qintptr_t ) ;
arg5 = va_arg ( argptr , qintptr_t ) ;
arg6 = va_arg ( argptr , qintptr_t ) ;
arg7 = va_arg ( argptr , qintptr_t ) ;
2004-08-23 00:15:46 +00:00
va_end ( argptr ) ;
switch ( vm - > type )
{
case VM_NATIVE :
return vm - > vmMain ( instruction , arg0 , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 ) ;
2004-09-26 04:03:45 +00:00
2004-08-23 00:15:46 +00:00
case VM_BYTECODE :
2009-03-03 01:52:30 +00:00
return QVM_ExecVM ( vm - > hInst , instruction , arg0 , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 , arg7 ) ;
2004-09-26 04:03:45 +00:00
2004-08-23 00:15:46 +00:00
case VM_NONE :
return 0 ;
}
return 0 ;
}
2004-09-13 04:16:52 +00:00
# endif