vm_t *VM_Create( vmSlots_t vmSlot ) { vm_t *vm = NULL; // see if we already have the VM if ( vmTable[vmSlot] ) return vmTable[vmSlot]; // find a free vm vmTable[vmSlot] = (vm_t *)Z_Malloc( sizeof( *vm ), TAG_VM, qtrue ); vm = vmTable[vmSlot]; // initialise it vm->slot = vmSlot; Q_strncpyz( vm->name, vmNames[vmSlot], sizeof( vm->name ) ); // find the module api FS_FindPureDLL( vm->name ); Com_Printf( "VM_Create: %s"ARCH_STRING DLL_EXT, vm->name ); vm->dllHandle = Sys_LoadGameDll( vm->name, &vm->GetModuleAPI ); if ( vm->dllHandle ) { if ( com_developer->integer ) Com_Printf( " succeeded [0x%X+0x%X]\n", vm->dllHandle, (intptr_t)vm->GetModuleAPI - (intptr_t)vm->dllHandle ); else Com_Printf( " succeeded\n" ); return vm; } VM_Free( vm ); Com_Printf( " failed!\n" ); return NULL; }
vm_t *VM_Create(const char *module, intptr_t (*systemCalls)(intptr_t *), vmInterpret_t interpret) { vm_t *vm; int i; if (!module || !module[0] || !systemCalls) { Com_Error(ERR_FATAL, "VM_Create: bad parms"); } // see if we already have the VM for (i = 0; i < MAX_VM; i++) { if (!Q_stricmp(vmTable[i].name, module)) { vm = &vmTable[i]; return vm; } } // find a free vm for (i = 0; i < MAX_VM; i++) { if (!vmTable[i].name[0]) { break; } } if (i == MAX_VM) { Com_Error(ERR_FATAL, "VM_Create: no free vm_t"); } vm = &vmTable[i]; Q_strncpyz(vm->name, module, sizeof(vm->name)); vm->systemCall = systemCalls; if (interpret == VMI_NATIVE) { // try to load as a system dll vm->dllHandle = Sys_LoadGameDll(module, &vm->entryPoint, VM_DllSyscall); // never try qvm if (vm->dllHandle) { return vm; } return NULL; } #if 0 // load the image Com_sprintf(filename, sizeof(filename), "vm/%s.qvm", vm->name); Com_Printf("Loading vm file %s.\n", filename); length = FS_ReadFile(filename, (void **)&header); if (!header) { Com_Printf("Failed.\n"); VM_Free(vm); return NULL; } // byte swap the header for (i = 0; i < sizeof(*header) / 4; i++) { ((int *)header)[i] = LittleLong(((int *)header)[i]); } // validate if (header->vmMagic != VM_MAGIC || header->bssLength < 0 || header->dataLength < 0 || header->litLength < 0 || header->codeLength <= 0) { VM_Free(vm); Com_Error(ERR_FATAL, "%s has bad header", filename); } // round up to next power of 2 so all data operations can // be mask protected dataLength = header->dataLength + header->litLength + header->bssLength; for (i = 0; dataLength > (1 << i); i++) { } dataLength = 1 << i; // allocate zero filled space for initialized and uninitialized data vm->dataBase = Hunk_Alloc(dataLength, h_high); vm->dataMask = dataLength - 1; // copy the intialized data Com_Memcpy(vm->dataBase, (byte *) header + header->dataOffset, header->dataLength + header->litLength); // byte swap the longs for (i = 0; i < header->dataLength; i += 4) { *(int *)(vm->dataBase + i) = LittleLong(*(int *)(vm->dataBase + i)); } // allocate space for the jump targets, which will be filled in by the compile/prep functions vm->instructionPointersLength = header->instructionCount * 4; vm->instructionPointers = Hunk_Alloc(vm->instructionPointersLength, h_high); // copy or compile the instructions vm->codeLength = header->codeLength; if (interpret >= VMI_COMPILED) { vm->compiled = qtrue; VM_Compile(vm, header); } else { vm->compiled = qfalse; VM_PrepareInterpreter(vm, header); } // free the original file FS_FreeFile(header); // load the map file VM_LoadSymbols(vm); // the stack is implicitly at the end of the image vm->programStack = vm->dataMask + 1; vm->stackBottom = vm->programStack - STACK_SIZE; Com_Printf("%s loaded in %d bytes on the hunk\n", module, remaining - Hunk_MemoryRemaining()); return vm; #else return NULL; #endif }