Explaining the Quake III Virtual Machine - SUSElnussel/talks/fosdem_talk_2013_q3...Explaining the...

20
Explaining the Quake III Virtual Machine Ludwig Nussel SUSE Linux Products GmbH openSUSE Team [email protected] FOSDEM 2013

Transcript of Explaining the Quake III Virtual Machine - SUSElnussel/talks/fosdem_talk_2013_q3...Explaining the...

Page 1: Explaining the Quake III Virtual Machine - SUSElnussel/talks/fosdem_talk_2013_q3...Explaining the Quake III Virtual Machine Ludwig Nussel SUSE Linux Products GmbH openSUSE Team ludwig.nussel@suse.de

Explaining the Quake III Virtual Machine

Ludwig Nussel

SUSE Linux Products GmbHopenSUSE Team

[email protected]

FOSDEM 2013

Page 2: Explaining the Quake III Virtual Machine - SUSElnussel/talks/fosdem_talk_2013_q3...Explaining the Quake III Virtual Machine Ludwig Nussel SUSE Linux Products GmbH openSUSE Team ludwig.nussel@suse.de

Outline

IntroductionAbout Quake III ArenaAbout ioquake3ArchitectureWays to Extend a Program and how Q3 does it

Virtual MachineArchitectureCalling Conventions & Memory LayoutVM Calls and SyscallsVM Interpreter

Summary

2 / 20

Page 3: Explaining the Quake III Virtual Machine - SUSElnussel/talks/fosdem_talk_2013_q3...Explaining the Quake III Virtual Machine Ludwig Nussel SUSE Linux Products GmbH openSUSE Team ludwig.nussel@suse.de

About Quake III Arena

� multiplayer first-person shooter

� developed by id Software

� released in December 1999 forLinux, Windows and Mac

� platform independent Mods

� source released under GPLv2 inAugust 2005

3 / 20

Page 4: Explaining the Quake III Virtual Machine - SUSElnussel/talks/fosdem_talk_2013_q3...Explaining the Quake III Virtual Machine Ludwig Nussel SUSE Linux Products GmbH openSUSE Team ludwig.nussel@suse.de

About ioquake3

� based on id’s source release

� compatible to original game

� bug and security fixes

� enhanced portability64bit, BSD, Solaris ...

� tons of new featuresIPv6, OpenAL surround sound, VoIP,stereo rendering, png image loader ...

4 / 20

Page 5: Explaining the Quake III Virtual Machine - SUSElnussel/talks/fosdem_talk_2013_q3...Explaining the Quake III Virtual Machine Ludwig Nussel SUSE Linux Products GmbH openSUSE Team ludwig.nussel@suse.de

Quake III Architecture Overview

EngineKeyboard, Mouse

Network

Sound

Graphics

Event Processing game

cgame

ui

Networking

Rendering

Botlib

Server

ClientSound

5 / 20

Page 6: Explaining the Quake III Virtual Machine - SUSElnussel/talks/fosdem_talk_2013_q3...Explaining the Quake III Virtual Machine Ludwig Nussel SUSE Linux Products GmbH openSUSE Team ludwig.nussel@suse.de

Quake III Architecture: the Game Modules

� Game� run on server side� maintain game state� compute bots� move objects

� CGame� run on client side� predict player states� tell sound and gfx renderers

what to show

� UI� run on client side� show menus

6 / 20

Page 7: Explaining the Quake III Virtual Machine - SUSElnussel/talks/fosdem_talk_2013_q3...Explaining the Quake III Virtual Machine Ludwig Nussel SUSE Linux Products GmbH openSUSE Team ludwig.nussel@suse.de

Typical Ways to Extend a Program

� Native� write plugins in C� compile as shared library� fast� no sandbox� no memory limit� can crash the whole program

� Interpreted� use some scripting language� slow� can be sandboxed� can be memory limited� main program can catch

exceptions

7 / 20

Page 8: Explaining the Quake III Virtual Machine - SUSElnussel/talks/fosdem_talk_2013_q3...Explaining the Quake III Virtual Machine Ludwig Nussel SUSE Linux Products GmbH openSUSE Team ludwig.nussel@suse.de

The Quake III Way for Extensions

Allow both, with same code!

Bytecode

� compiled by special compiler (lcc)

� byte code interpreted by a virtualmachine

� strict sandbox

� strict memory limit

� main program can catch exceptionsand unload VM

Native

� compiled by system Ccompiler as shared library

� must restrict toembedded libc subset

� must not call malloc()

� must not use externallibs

8 / 20

Page 9: Explaining the Quake III Virtual Machine - SUSElnussel/talks/fosdem_talk_2013_q3...Explaining the Quake III Virtual Machine Ludwig Nussel SUSE Linux Products GmbH openSUSE Team ludwig.nussel@suse.de

The Virtual Machine ArchitectureOverview

� 32bit addressing, little endian

� 32bit floats

� about 60 instructions

� separate memory addressing for code and data

� no dynamic memory allocations

� no GP registers, load/store on ’opstack’

9 / 20

Page 10: Explaining the Quake III Virtual Machine - SUSElnussel/talks/fosdem_talk_2013_q3...Explaining the Quake III Virtual Machine Ludwig Nussel SUSE Linux Products GmbH openSUSE Team ludwig.nussel@suse.de

opStack vs Program Stack

� Program stack� local variables� function parameters� saved program counter

� opStack� arguments for instructions, results

OP CONST 3OP CONST 4OP ADD

� function return values

10 / 20

Page 11: Explaining the Quake III Virtual Machine - SUSElnussel/talks/fosdem_talk_2013_q3...Explaining the Quake III Virtual Machine Ludwig Nussel SUSE Linux Products GmbH openSUSE Team ludwig.nussel@suse.de

Calling Convention

� similar to x86

� parameters and program counter pushed to stack

� callee responsible for new stack frame

� negative address means syscall

� return value on opstack

11 / 20

Page 12: Explaining the Quake III Virtual Machine - SUSElnussel/talks/fosdem_talk_2013_q3...Explaining the Quake III Virtual Machine Ludwig Nussel SUSE Linux Products GmbH openSUSE Team ludwig.nussel@suse.de

VM Memory Layout

Data Stack

vm->dataBase

0

vm->programStack

p = vm->dataBase + (offset & vm->dataMask)

� vm memory allocated as one block

� 64k stack at end of image

� code and opstack separate� memory size rounded to power of two

� simple access violation checks via mask

� cannot address memory outside thatblock� can’t pass pointers

12 / 20

Page 13: Explaining the Quake III Virtual Machine - SUSElnussel/talks/fosdem_talk_2013_q3...Explaining the Quake III Virtual Machine Ludwig Nussel SUSE Linux Products GmbH openSUSE Team ludwig.nussel@suse.de

Calling into the VM

� code is one big block

� no symbols

� can only pass int parameters� start of code has to be

dispatcher function� first parameter is a command� called vmMain() for dlopen()

i n t p t r t vmMain ( i n t command ,i n t arg0 , i n t arg1 ,

. . . , i n t arg11 ) {sw i tch ( command) {

case GAME INIT :G In i tGame ( arg0 , arg1 , a rg2 ) ;r e t u r n 0 ;

case GAME SHUTDOWN:G ShutdownGame ( arg0 ) ;r e t u r n 0 ;

. . .

13 / 20

Page 14: Explaining the Quake III Virtual Machine - SUSElnussel/talks/fosdem_talk_2013_q3...Explaining the Quake III Virtual Machine Ludwig Nussel SUSE Linux Products GmbH openSUSE Team ludwig.nussel@suse.de

Calling into the Engine

� requests into engine� print something� open a file� play a sound

� expensive operations� sinus, cosinus, vector

operations� memset, memcpy

� pass pointers but notreturn!

� VM side, C implemenation

typede f enum { CG PRINT , . . . } ;vo id t r a p P r i n t ( const char ∗ fmt ) {

s y s c a l l (CG PRINT , fmt ) ;}

� host side

i n t p t r tCL CgameSystemCal ls ( i n t p t r t ∗ a r g s ) {

sw i tch ( a r g s [ 0 ] ) {case CG PRINT :Com Pr int f ( ”%s ” , ( char ∗)VMA( 1 ) ) ;r e t u r n 0 ;

. . .

14 / 20

Page 15: Explaining the Quake III Virtual Machine - SUSElnussel/talks/fosdem_talk_2013_q3...Explaining the Quake III Virtual Machine Ludwig Nussel SUSE Linux Products GmbH openSUSE Team ludwig.nussel@suse.de

How the Interpreter WorksExample

wh i l e (1 ) {

r0 = opStack [ opStackOfs ] ;r1 = opStack [ ( u i n t 8 t ) ( opStackOfs − 1 ) ] ;

n e x t I n s t r u c t i o n 2 :opcode = codeImage [ programCounter++ ] ;

sw i tch ( opcode ) {

case OP LOAD4 :r0 = opStack [ opStackOfs ] =

∗( i n t ∗) &image [ r0 & dataMask & ˜3 ] ;goto n e x t I n s t r u c t i o n 2 ;

15 / 20

Page 16: Explaining the Quake III Virtual Machine - SUSElnussel/talks/fosdem_talk_2013_q3...Explaining the Quake III Virtual Machine Ludwig Nussel SUSE Linux Products GmbH openSUSE Team ludwig.nussel@suse.de

More Speed With Native Code

� Byte code interpreter too slow for complex mods

� Translate byte code to native instructions on load� CPU/OS specific compilers needed

� currently: x86, x86 64, ppc{,64}, sparc{,64}� hard to maintain

� Multiple passes to calculate offsets

� Needs extra memory as native code is bigger

� Need to be careful when optimizing jump targets

16 / 20

Page 17: Explaining the Quake III Virtual Machine - SUSElnussel/talks/fosdem_talk_2013_q3...Explaining the Quake III Virtual Machine Ludwig Nussel SUSE Linux Products GmbH openSUSE Team ludwig.nussel@suse.de

VM JIT CompilerExample

case OP DIVU :// mov eax , dword p t r −4[ e d i + ebx ∗ 4 ]Emi tS t r i ng ( ”8B 44 9F FC” ) ;// xor edx , edxEmi tS t r i ng ( ”33 D2” ) ;// d i v dword p t r [ e d i + ebx ∗ 4 ]Emi tS t r i ng ( ”F7 34 9F” ) ;// mov dword p t r −4[ e d i + ebx ∗ 4 ] , eaxEmi tS t r i ng ( ”89 44 9F FC” ) ;// sub bl , 1EmitCommand(LAST COMMAND SUB BL 1 ) ;

17 / 20

Page 18: Explaining the Quake III Virtual Machine - SUSElnussel/talks/fosdem_talk_2013_q3...Explaining the Quake III Virtual Machine Ludwig Nussel SUSE Linux Products GmbH openSUSE Team ludwig.nussel@suse.de

Future Work

� replace x87 ops with SSE2 in vm x86.c

� write compiler for ARM

� create gcc backend to replace lcc

� use LLVM

18 / 20

Page 19: Explaining the Quake III Virtual Machine - SUSElnussel/talks/fosdem_talk_2013_q3...Explaining the Quake III Virtual Machine Ludwig Nussel SUSE Linux Products GmbH openSUSE Team ludwig.nussel@suse.de

Summary

� Quake 3 allows mods as shared library or bytecode

� Bytecode is platform independent

� Game architecture requires strict separation between engine andmod

� CPU/OS specific compilers are a maintenance burden

� VM is simple enough to study and play with it

19 / 20

Page 20: Explaining the Quake III Virtual Machine - SUSElnussel/talks/fosdem_talk_2013_q3...Explaining the Quake III Virtual Machine Ludwig Nussel SUSE Linux Products GmbH openSUSE Team ludwig.nussel@suse.de

Links

� http://ioquake3.org/

� http://www.idsoftware.com/

� http://fabiensanglard.net/quake3/

� http://www.icculus.org/~phaethon/q3mc/q3vm_specs.html

20 / 20