A new virtual machine that attempts to solve many of the problems/nuisances of other VMs such as Java

Similar projects worth following
Modern VMs have a lot of problems that cause frustration to programmers, especially ones who are used to native features such as system calls, interrupts, etc. In addition, VMs such as java are rather bulky, especially for embedded environments. And it's annoyingly complicated to tie together native and VM code. The instruction sets used by VMs (or regular CPU architectures for that matter) are aimed toward optimizing higher level languages and can be difficult to learn or use, and just aren't very fun to write. FelinityVM attempts to solve all of these problems and more by providing a simple yet powerful instruction set and register configuration, several abstraction mechanisms which allow for the implentation of secure hypervisors and operating systems, providing primitives for accessing the native environment outside of the VM, and behaving like a native executable to the system.

FelinityVM is a new virtual machine designed with the following goals:
-Simple to implement

Simplicity can be a vague concept to specify, so to clarify what that means for this project: someone familiar with computer architectures should be able to code at least a rudimentary implementation inside of a week. Of course more advanced optimizations may take longer to research and implement, but from an operational standpoint, it should be that easy to create a new VM according to this specification from scratch. This helps not only to propogate the usage of the VM to embedded developers who are under tight time restrictions, but also helps prevent the many problems that come from the same code base being ported over and over. If the VM is simple enough to rewrite from scratch in a way that is integrated into your project and system design, why wouldn't you do that instead of taking a machine that was meant for another system and cramming it onto a new one, adding band-aid after band-aid until it finally works. Now there will be good implementations available for most major systems so reimplementing from scratch will not be the norm for most application developers, but having that as an option frees programmers from worrying about a particular implementation restricting what they can do with their application.

-Well documented

A lot of VMs or software in general these days is "code first document later," this project is more about creating a specification that can be easily implemented on any system than about a specific implementation. Although several reference implementations will be available along with implementations for most major architectures including X86_64, ARM, etc.

-Powerful yet small instruction set

The CISC instruction set used for this VM gives power back to the programmer making assembly writing intuitive and fun by having only a small number of instructions that can do more than most large instruction sets. I don't know how many people still write assembly for modern architectures, I'm sure there are quite a few, but personally I find it to be a rather tedius experience, and I'm sure I am not the only one. The reason for this is that people are not meant to write assembly most of the time, the architectures today are bloated full of niche operations and complex operand formats that are supposed to be optimization tools for the way that higher level languages need to generate assembly. But assembly can be made much easier and far more entertaining if the instruction sets are not geared toward compilers. Thats not to say that the FelinityVM instruction set does not take into account the work that compilers need to do or that compilers should not be written for the VM, but merely that it is designed so that those optimization tools are elegant features; core to the design rather than side features tacked on after-the-fact that add convolution to the rest of the architecture.

-Doesn't take away from native features

Most VMs like to abstract you from your native environment which is good because you want code to be portable, however sometimes you want to take control of specific elements of a native environment. The solution in other VMs such as Java is to write native code for that system, then write some more native code to act as an interface between the VM and the native code you just wrote thus creating messy layers of calls to do what you want. FelinityVM allows access to native memory, system calls, and even native processor registers all from within the VM. Furthermore, since these types of accesses are all primitives within the vm they are easily disabled when a sandboxed environment is needed. This gives FelinityVM the flexibility to behave as a sandboxed machine when running untrusted applications, as a microcontroller VM allowing the same code to run across all sorts of uController manufacturers with only minimal changes to runtime selection of registers, and as a full fledged bare-metal VM capable of implementing...

Read more »

  • Native access controls defined

    aaron03/07/2015 at 11:31 0 comments

    One of the most important features for the vm is the way that native code can be accessed. After playing around with several ideas and methods, I found it was best just to keep it simple. Two registers control reading and writing to native memory, one controls the address of native memory being affected, the other is a pseudoregister which when written to/read from performs the read/write on the corresponding address in native memory. Use of these registers with the standard set of instructions, allows easy direct manipulation of native memory with little overhead. In addition, there are several instructions which serve to aid in handling native code. One instruction - ASSIGN_NATIVE_INTERRUPT - allows the programmer to assign a vm function as a native interrupt handler without writing any native code (though some native code will be generated by the VM to permit this functionality). Similiarly - UNASSIGN_NATIVE_INTERRUPT - allows the programmer to remove a VM interrupt handler that was previously assigned. Both of these operations come with an error code that indicates whether the interrupt was successfully assigned, or if restrictions by the underlying operating system prevent doing so. Jumping to native code is a task which can get complicated easily, so to keep things simple, the VM provides an instruction, - EXECUTE_NATIVE - which simply takes a native address as an argument and jumps to that address. At this point you are probably thinking "How do you prepare arguments for a native function call? How does a native function access values in the VM, and how does it ultimately return control back to the VM?" All of these issues are difficult to work around with a framework that is supposedly "simple," so to solve this problem, we need a few other features. First of all, there are native functions that are part of the VM specification which permit returning back to the VM, as well as reading/writing VM memory. The native addresses of these functions is given in a pseudoregister that can be accessed at any time in the VM. In addition there is an instruction which allows native memory to be allocated for use by the VM for any combination of reading/writing/executing. Once allocated for execution, the allocated segment can be written with native opcodes that perform the necessary VM accesses to read arguments, initialize a call stack, and any other tasks needed before calling a native library function. Thus for any setup which cannot be done simply by writing values to native memory, native instructions can act as a mapping layer between the VM and the native code. So at this point, you may be wondering "Why not just allocate a small chunk of native memory for a stack, use the native registers to write your arguments to it then jump to some native code?" Well the answer to that question is that the way in which systems implement function calls and stacks can vary widely. Even 2 operating systems such as Linux and Windows running on the same hardware may use different calling conventions when calling native functions, in fact there is not even a guarentee that the native code you want to execute obeys a strict calling convention anyways, especially if it was written in assembly. Often as an optimization, certain arguments will be passed to a function in native registers. For such functions VM code cannot exist for passing arguments as the VM itself may make use of those regisers for other purposes. As another example, the MOS-6502 processor (famously used in the NES and APPLE II) has a stack pointer register as well as several instructions for pushing and pulling registers off the stack, the RTS instruction "returns" from a function by popping the program counter and status register off the stack. In this case it would be impossible for the VM running on a 6502 to directly manipulate the stack since it would have to read the stack pointer, a value which would change after reading since the VM's intrnal operations may very well change...

    Read more »

  • Specification Started

    aaron02/26/2015 at 08:54 0 comments

    So far on this project, I have started writing the specification for how this virtual processor should behave in a plain text file. I have the registers, pseudoregisters, and instructions defined with full details about what registers are affected by each operation and how they are affected. I wrote some test programs in C and Java to try out ideas about how certain aspects of the VM should behave. Mostly the things I wrote were simulations for things like how a borrow flag is carried through an arbitrary length subtraction. In this way I was able to confirm the arithmetic definitions for the instructions in the VM. Currently I am working on a few instruction definitions that relate to native code behavior, and defining the constraints on certain native subroutines which will be needed as a return address from native calls to allow the native code to jump back into the vm, and have the VM pick up where it left off.

View all 2 project logs

Enjoy this project?



Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates