diff --git a/README.md b/README.md
index ae8c04b..08166d3 100644
--- a/README.md
+++ b/README.md
@@ -8,8 +8,10 @@ This is an educational project to learn more about the ELF file format and [Unic
 
 - Emulation of the [JNI Invocation API](https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/invocation.html) so `JNI_OnLoad` can be called properly.
 - Emulation of native memory for malloc / memcpy.
+- Emulation of syscalls (SVC #0) instruction.
 - Hooking through the symbol table.
 - All JavaVM, JNIEnv and hooked functions are handled by python.
+- Enable VFP support.
 
 > The first two are still being worked on, please contribute if you can! :)
 
@@ -30,3 +32,4 @@ All resources used while developing AndroidNativeEmu.
 
 ### Code sources
 - https://github.com/lunixbochs/usercorn
+- https://github.com/slick1015/pad_unpacker (SVC 0 instruction)
diff --git a/androidemu/config.py b/androidemu/config.py
index 9318aba..f23d3ce 100644
--- a/androidemu/config.py
+++ b/androidemu/config.py
@@ -5,6 +5,6 @@
 MEMORY_SIZE = 0x0200000  # 2 * 1024 * 1024 - 2MB
 
 MEMORY_DYN_BASE = 0x2000000
-MEMORY_DYN_SIZE = 0x0200000 # 2 * 1024 * 1024 - 2MB
+MEMORY_DYN_SIZE = 0x0200000  # 2 * 1024 * 1024 - 2MB
 
 BASE_ADDR = 0xCBBCB000
diff --git a/androidemu/const/__init__.py b/androidemu/const/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/androidemu/const/android.py b/androidemu/const/android.py
new file mode 100644
index 0000000..03eb0a6
--- /dev/null
+++ b/androidemu/const/android.py
@@ -0,0 +1 @@
+PR_SET_VMA = 0x53564d41
diff --git a/androidemu/const/linux.py b/androidemu/const/linux.py
new file mode 100644
index 0000000..f6ab697
--- /dev/null
+++ b/androidemu/const/linux.py
@@ -0,0 +1,10 @@
+CLOCK_REALTIME = 0
+CLOCK_MONOTONIC = 1
+CLOCK_PROCESS_CPUTIME_ID = 2
+CLOCK_THREAD_CPUTIME_ID = 3
+CLOCK_MONOTONIC_RAW = 4
+CLOCK_REALTIME_COARSE = 5
+CLOCK_MONOTONIC_COARSE = 6
+CLOCK_BOOTTIME = 7
+CLOCK_REALTIME_ALARM = 8
+CLOCK_BOOTTIME_ALARM = 9
diff --git a/androidemu/cpu/__init__.py b/androidemu/cpu/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/androidemu/cpu/interrupt_handler.py b/androidemu/cpu/interrupt_handler.py
new file mode 100644
index 0000000..2b707cf
--- /dev/null
+++ b/androidemu/cpu/interrupt_handler.py
@@ -0,0 +1,27 @@
+import logging
+
+from unicorn import *
+from unicorn.arm_const import *
+
+logger = logging.getLogger(__name__)
+
+
+class InterruptHandler:
+
+    """
+    :type mu Uc
+    """
+    def __init__(self, mu):
+        self._mu = mu
+        self._mu.hook_add(UC_HOOK_INTR, self._hook_interrupt)
+        self._handlers = dict()
+
+    def _hook_interrupt(self, uc, intno, data):
+        if intno in self._handlers:
+            self._handlers[intno](uc)
+        else:
+            logger.error("Unhandled interrupt %d at %x, stopping emulation" % (intno, self._mu.reg_read(UC_ARM_REG_PC)))
+            self._mu.emu_stop()
+
+    def set_handler(self, intno, handler):
+        self._handlers[intno] = handler
diff --git a/androidemu/cpu/syscall_handler.py b/androidemu/cpu/syscall_handler.py
new file mode 100644
index 0000000..db938ad
--- /dev/null
+++ b/androidemu/cpu/syscall_handler.py
@@ -0,0 +1,7 @@
+class SyscallHandler:
+
+    def __init__(self, idx, name, arg_count, callback):
+        self.idx = idx
+        self.name = name
+        self.arg_count = arg_count
+        self.callback = callback
diff --git a/androidemu/cpu/syscall_handlers.py b/androidemu/cpu/syscall_handlers.py
new file mode 100644
index 0000000..c6886f4
--- /dev/null
+++ b/androidemu/cpu/syscall_handlers.py
@@ -0,0 +1,46 @@
+import logging
+
+from unicorn import *
+from unicorn.arm_const import *
+
+from androidemu.cpu.interrupt_handler import InterruptHandler
+from androidemu.cpu.syscall_handler import SyscallHandler
+from androidemu.utils import memory_helpers
+
+logger = logging.getLogger(__name__)
+
+
+class SyscallHandlers:
+
+    """
+    :type interrupt_handler InterruptHandler
+    """
+    def __init__(self, interrupt_handler):
+        self._handlers = dict()
+        interrupt_handler.set_handler(2, self._handle_syscall)
+
+    def set_handler(self, idx, name, arg_count, callback):
+        self._handlers[idx] = SyscallHandler(idx, name, arg_count, callback)
+
+    def _handle_syscall(self, mu):
+        idx = mu.reg_read(UC_ARM_REG_R7)
+        args = [mu.reg_read(reg_idx) for reg_idx in range(UC_ARM_REG_R0, UC_ARM_REG_R6 + 1)]
+
+        if idx in self._handlers:
+            handler = self._handlers[idx]
+            args = args[:handler.arg_count]
+            args_formatted = ", ".join(["%08x" % arg for arg in args])
+            logger.info("Executing syscall %s(%s)" % (handler.name, args_formatted))
+
+            try:
+                result = handler.callback(mu, *args)
+            except:
+                logger.error("An error occured during in %x syscall hander, stopping emulation" % idx)
+                mu.emu_stop()
+                raise
+
+            if result is not None:
+                mu.reg_write(UC_ARM_REG_R0, result)
+        else:
+            logger.error("Unhandled syscall 0x%x at 0x%x, stopping emulation" % (idx, mu.reg_read(UC_ARM_REG_PC)))
+            mu.emu_stop()
diff --git a/androidemu/cpu/syscall_hooks.py b/androidemu/cpu/syscall_hooks.py
new file mode 100644
index 0000000..ced4b71
--- /dev/null
+++ b/androidemu/cpu/syscall_hooks.py
@@ -0,0 +1,54 @@
+from unicorn import Uc
+
+from androidemu.const.android import PR_SET_VMA
+from androidemu.const.linux import CLOCK_MONOTONIC_COARSE
+from androidemu.cpu.syscall_handlers import SyscallHandlers
+from androidemu.utils import memory_helpers
+
+
+class SyscallHooks:
+
+    """
+    :type mu Uc
+    :type syscall_handler SyscallHandlers
+    """
+    def __init__(self, mu, syscall_handler):
+        self._mu = mu
+        self._syscall_handler = syscall_handler
+        self._syscall_handler.set_handler(0xAC, "prctl", 5, self._handle_prctl)
+        self._syscall_handler.set_handler(0x107, "clock_gettime", 2, self._handle_clock_gettime)
+
+    def _handle_prctl(self, mu, option, arg2, arg3, arg4, arg5):
+        """
+        int prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5);
+        See:
+        - https://linux.die.net/man/2/prctl
+        - https://github.com/torvalds/linux/blob/master/include/uapi/linux/prctl.h
+
+        For PR_SET_VMA:
+        - https://android.googlesource.com/platform/bionic/+/263325d/libc/include/sys/prctl.h
+        - https://sourceforge.net/p/strace/mailman/message/34329772/
+        """
+
+        if option == PR_SET_VMA:
+            # arg5 contains ptr to a name.
+            return 0
+        else:
+            raise NotImplementedError("Unsupported prctl option %d (0x%x)" % (option, option))
+
+    def _handle_clock_gettime(self, mu, clk_id, tp_ptr):
+        """
+        The functions clock_gettime() retrieve the time of the specified clock clk_id.
+
+        The clk_id argument is the identifier of the particular clock on which to act. A clock may be system-wide and
+        hence visible for all processes, or per-process if it measures time only within a single process.
+
+        clock_gettime(), clock_settime() and clock_getres() return 0 for success, or -1 for failure (in which case
+        errno is set appropriately).
+        """
+
+        if clk_id == CLOCK_MONOTONIC_COARSE:
+            # TODO: Actually write time.
+            return 0
+        else:
+            raise NotImplementedError("Unsupported clk_id: %d (%x)" % (clk_id, clk_id))
diff --git a/androidemu/emulator.py b/androidemu/emulator.py
index b43fc78..705fa5e 100644
--- a/androidemu/emulator.py
+++ b/androidemu/emulator.py
@@ -2,12 +2,16 @@
 from unicorn.arm_const import UC_ARM_REG_SP
 
 from androidemu import config
+from androidemu.cpu.interrupt_handler import InterruptHandler
+from androidemu.cpu.syscall_handlers import SyscallHandlers
+from androidemu.cpu.syscall_hooks import SyscallHooks
 from androidemu.hooker import Hooker
 from androidemu.internal.memory import Memory
 from androidemu.internal.modules import Modules
 from androidemu.java.java_vm import JavaVM
 from androidemu.native.hooks import NativeHooks
 from androidemu.native.memory import NativeMemory
+from androidemu.vfs.file_system import VirtualFileSystem
 
 
 class Emulator:
@@ -17,10 +21,13 @@ class Emulator:
     :type modules Modules
     :type memory Memory
     """
-    def __init__(self):
+    def __init__(self, vfs_root=None, vfp_inst_set=False):
         # Unicorn.
         self.mu = Uc(UC_ARCH_ARM, UC_MODE_ARM)
 
+        if vfp_inst_set:
+            self._enable_vfp()
+
         # Stack.
         self.mu.mem_map(config.STACK_ADDR, config.STACK_SIZE)
         self.mu.reg_write(UC_ARM_REG_SP, config.STACK_ADDR + config.STACK_SIZE)
@@ -29,6 +36,17 @@ def __init__(self):
         self.modules = Modules(self)
         self.memory = Memory(self)
 
+        # CPU
+        self.interrupt_handler = InterruptHandler(self.mu)
+        self.syscall_handler = SyscallHandlers(self.interrupt_handler)
+        self.syscall_hooks = SyscallHooks(self.mu, self.syscall_handler)
+
+        # File System
+        if vfs_root is not None:
+            self.vfs = VirtualFileSystem(vfs_root, self.syscall_handler)
+        else:
+            self.vfs = None
+
         # Hooker
         self.mu.mem_map(config.MEMORY_BASE, config.MEMORY_SIZE)
         self.hooker = Hooker(self.mu, config.MEMORY_BASE, config.MEMORY_SIZE)
@@ -37,8 +55,40 @@ def __init__(self):
         self.java_vm = JavaVM(self.hooker)
 
         # Native
-        self.native_memory = NativeMemory(config.MEMORY_BASE, config.MEMORY_SIZE)
+        self.native_memory = NativeMemory(self.mu, config.MEMORY_DYN_BASE, config.MEMORY_DYN_SIZE, self.syscall_handler)
         self.native_hooks = NativeHooks(self.native_memory, self.modules, self.hooker)
 
+    # https://github.com/unicorn-engine/unicorn/blob/8c6cbe3f3cabed57b23b721c29f937dd5baafc90/tests/regress/arm_fp_vfp_disabled.py#L15
+    def _enable_vfp(self):
+        # MRC p15, #0, r1, c1, c0, #2
+        # ORR r1, r1, #(0xf << 20)
+        # MCR p15, #0, r1, c1, c0, #2
+        # MOV r1, #0
+        # MCR p15, #0, r1, c7, c5, #4
+        # MOV r0,#0x40000000
+        # FMXR FPEXC, r0
+        code = '11EE501F'
+        code += '41F47001'
+        code += '01EE501F'
+        code += '4FF00001'
+        code += '07EE951F'
+        code += '4FF08040'
+        code += 'E8EE100A'
+        # vpush {d8}
+        code += '2ded028b'
+
+        address = 0x1000
+        mem_size = 0x1000
+        code_bytes = bytes.fromhex(code)
+
+        try:
+            self.mu.mem_map(address, mem_size)
+            self.mu.mem_write(address, code_bytes)
+            self.mu.reg_write(UC_ARM_REG_SP, address + mem_size)
+
+            self.mu.emu_start(address | 1, address + len(code_bytes))
+        finally:
+            self.mu.mem_unmap(address, mem_size)
+
     def load_library(self, filename):
         return self.modules.load_module(filename)
diff --git a/androidemu/internal/memory.py b/androidemu/internal/memory.py
index cb350b6..fac39a8 100644
--- a/androidemu/internal/memory.py
+++ b/androidemu/internal/memory.py
@@ -32,3 +32,5 @@ def mem_map(self, address, size, prot):
 
     def mem_write(self, address, data):
         self.emu.mu.mem_write(address, data)
+
+
diff --git a/androidemu/java/jni_env.py b/androidemu/java/jni_env.py
index 757e6b6..335ac18 100644
--- a/androidemu/java/jni_env.py
+++ b/androidemu/java/jni_env.py
@@ -260,11 +260,10 @@ def find_class(self, mu, env, name_ptr):
         """
         Returns a class object from a fully-qualified name, or NULL if the class cannot be found.
         """
-
-        # TODO: Actually retrieve a class id from a class map.
         name = memory_helpers.read_utf8(mu, name_ptr)
-        logger.debug(name)
-        return 0xFF
+        logger.debug("JNIEnv->FindClass(%s) was called" % name)
+        # TODO: Actually retrieve a class id from a class map.
+        return 0xFA
 
     @native_method
     def from_reflected_method(self, mu, env):
@@ -323,20 +322,34 @@ def pop_local_frame(self, mu, env):
         raise NotImplementedError()
 
     @native_method
-    def new_global_ref(self, mu, env):
-        raise NotImplementedError()
+    def new_global_ref(self, mu, env, obj):
+        """
+        Creates a new global reference to the object referred to by the obj argument. The obj argument may be a
+        global or local reference. Global references must be explicitly disposed of by calling DeleteGlobalRef().
+        """
+        logger.debug("JNIEnv->NewGlobalRef(%d) was called" % obj)
+        # TODO: Implement
+        return obj + 1
 
     @native_method
     def delete_global_ref(self, mu, env):
         raise NotImplementedError()
 
     @native_method
-    def delete_local_ref(self, mu, env):
-        raise NotImplementedError()
+    def delete_local_ref(self, mu, env, local_ref):
+        """
+        Deletes the local reference pointed to by localRef.
+        """
+        logger.debug("JNIEnv->DeleteLocalRef(%d) was called" % local_ref)
+        # TODO: Implement
 
     @native_method
-    def is_same_object(self, mu, env):
-        raise NotImplementedError()
+    def is_same_object(self, mu, env, ref1, ref2):
+        """
+        Returns JNI_TRUE if ref1 and ref2 refer to the same Java object, or are both NULL; otherwise, returns JNI_FALSE.
+        """
+        logger.debug("JNIEnv->IsSameObject(%d, %d) was called" % (ref1, ref2))
+        return JNI_FALSE
 
     @native_method
     def new_local_ref(self, mu, env):
@@ -371,8 +384,16 @@ def is_instance_of(self, mu, env):
         raise NotImplementedError()
 
     @native_method
-    def get_method_id(self, mu, env):
-        raise NotImplementedError()
+    def get_method_id(self, mu, env, clazz, name_ptr, sig_ptr):
+        """
+        Returns the method ID for an instance (nonstatic) method of a class or interface. The method may be defined
+        in one of the clazz’s superclasses and inherited by clazz. The method is determined by its name and signature.
+        """
+        name = memory_helpers.read_utf8(mu, name_ptr)
+        sig = memory_helpers.read_utf8(mu, sig_ptr)
+        logger.debug("JNIEnv->GetMethodId(%d, %s, %s) was called" % (clazz, name, sig))
+        # TODO: Implement
+        return 0xFC
 
     @native_method
     def call_object_method(self, mu, env):
@@ -615,8 +636,17 @@ def call_nonvirtual_void_method_a(self, mu, env):
         raise NotImplementedError()
 
     @native_method
-    def get_field_id(self, mu, env):
-        raise NotImplementedError()
+    def get_field_id(self, mu, env, clazz, name_ptr, sig_ptr):
+        """
+        Returns the field ID for an instance (nonstatic) field of a class. The field is specified by its name and
+        signature. The Get<type>Field and Set<type>Field families of accessor functions use field IDs to retrieve
+        object fields.
+        """
+        name = memory_helpers.read_utf8(mu, name_ptr)
+        sig = memory_helpers.read_utf8(mu, sig_ptr)
+        logger.debug("JNIEnv->GetFieldId(%d, %s, %s) was called" % (clazz, name, sig))
+        # TODO: Implement
+        return 0xFD
 
     @native_method
     def get_object_field(self, mu, env):
@@ -691,8 +721,15 @@ def set_double_field(self, mu, env):
         raise NotImplementedError()
 
     @native_method
-    def get_static_method_id(self, mu, env):
-        raise NotImplementedError()
+    def get_static_method_id(self, mu, env, clazz, name_ptr, sig_ptr):
+        """
+        Returns the method ID for a static method of a class. The method is specified by its name and signature.
+        """
+        name = memory_helpers.read_utf8(mu, name_ptr)
+        sig = memory_helpers.read_utf8(mu, sig_ptr)
+        logger.debug("JNIEnv->GetStaticMethodId(%d, %s, %s) was called" % (clazz, name, sig))
+        # TODO: Implement
+        return 0xFB
 
     @native_method
     def call_static_object_method(self, mu, env):
@@ -815,8 +852,17 @@ def call_static_void_method_a(self, mu, env):
         raise NotImplementedError()
 
     @native_method
-    def get_static_field_id(self, mu, env):
-        raise NotImplementedError()
+    def get_static_field_id(self, mu, env, clazz, name_ptr, sig_ptr):
+        """
+        Returns the field ID for a static field of a class. The field is specified by its name and signature. The
+        GetStatic<type>Field and SetStatic<type>Field families of accessor functions use field IDs to retrieve static
+        fields.
+        """
+        name = memory_helpers.read_utf8(mu, name_ptr)
+        sig = memory_helpers.read_utf8(mu, sig_ptr)
+        logger.debug("JNIEnv->GetStaticFieldId(%d, %s, %s) was called" % (clazz, name, sig))
+        # TODO: Implement
+        return 0xFE
 
     @native_method
     def get_static_object_field(self, mu, env):
@@ -1164,7 +1210,13 @@ def delete_weak_global_ref(self, mu, env):
 
     @native_method
     def exception_check(self, mu, env):
-        raise NotImplementedError()
+        """
+        Returns JNI_TRUE when there is a pending exception; otherwise, returns JNI_FALSE.
+        """
+        logger.debug("JNIEnv->ExceptionCheck() was called")
+        # TODO: Implement
+
+        return JNI_FALSE
 
     @native_method
     def new_direct_byte_buffer(self, mu, env):
diff --git a/androidemu/native/hooks.py b/androidemu/native/hooks.py
index 37416be..87f3c31 100644
--- a/androidemu/native/hooks.py
+++ b/androidemu/native/hooks.py
@@ -18,17 +18,5 @@ class NativeHooks:
     def __init__(self, memory, modules, hooker):
         self._memory = memory
 
-        modules.add_symbol_hook('malloc', hooker.write_function(self.malloc) + 1)
-        modules.add_symbol_hook('memcpy', hooker.write_function(self.memcpy) + 1)
-
-    @native_method
-    def malloc(self, mu, size):
-        # TODO: Actually reserve memory with checks.
-        logger.warning("Application requested %d bytes." % size)
-        return 0x10
-
-    @native_method
-    def memcpy(self, mu, dst, src, count):
-        # TODO: Actually copy memory with checks.
-        logger.warning("Application copies %d bytes from 0x%x to 0x%x." % (count, src, dst))
-        return 0x10
+        # modules.add_symbol_hook('malloc', hooker.write_function(self.malloc) + 1)
+        # modules.add_symbol_hook('memcpy', hooker.write_function(self.memcpy) + 1)
diff --git a/androidemu/native/memory.py b/androidemu/native/memory.py
index 35d901b..1d7636a 100644
--- a/androidemu/native/memory.py
+++ b/androidemu/native/memory.py
@@ -1,5 +1,44 @@
+from unicorn import Uc
+from androidemu.cpu.syscall_handlers import SyscallHandlers
+
+
 class NativeMemory:
 
-    def __init__(self, memory_base, memory_size):
+    """
+    :type mu Uc
+    :type syscall_handler SyscallHandlers
+    """
+    def __init__(self, mu, memory_base, memory_size, syscall_handler):
+        self._mu = mu
         self._memory_base = memory_base
+        self._memory_current = memory_base
         self._memory_size = memory_size
+        self._syscall_handler = syscall_handler
+        self._syscall_handler.set_handler(0xC0, "mmap2", 6, self._handle_mmap2)
+        self._syscall_handler.set_handler(0xDC, "madvise", 3, self._handle_madvise)
+
+    def allocate(self, length, prot=7):
+        alloc_base = self._memory_current
+
+        if alloc_base + length > self._memory_base + self._memory_size:
+            raise OverflowError("Our native memory is overflowing..")
+
+        self._mu.mem_map(alloc_base, length, perms=prot)
+        self._memory_current += length
+
+        return alloc_base
+
+    def _handle_mmap2(self, mu, addr, length, prot, flags, fd, offset):
+        """
+        void *mmap2(void *addr, size_t length, int prot, int flags, int fd, off_t pgoffset);
+        """
+        return self.allocate(length, prot=prot)
+
+    def _handle_madvise(self, mu, start, len_in, behavior):
+        """
+        int madvise(void *addr, size_t length, int advice);
+        The kernel is free to ignore the advice.
+        On success madvise() returns zero. On error, it returns -1 and errno is set appropriately.
+        """
+        # We don't need your advise.
+        return 0
diff --git a/androidemu/vfs/__init__.py b/androidemu/vfs/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/androidemu/vfs/file_system.py b/androidemu/vfs/file_system.py
new file mode 100644
index 0000000..401ef0f
--- /dev/null
+++ b/androidemu/vfs/file_system.py
@@ -0,0 +1,94 @@
+import logging
+import os
+import posixpath
+
+from androidemu.cpu.syscall_handlers import SyscallHandlers
+from androidemu.utils import memory_helpers
+
+logger = logging.getLogger(__name__)
+
+
+class VirtualFileSystem:
+
+    """
+    :type syscall_handler SyscallHandlers
+    """
+    def __init__(self, root_path, syscall_handler):
+        self._root_path = root_path
+        self._file_descriptors = [0, 1, 2]
+        syscall_handler.set_handler(0x3, "read", 3, self._handle_read)
+        syscall_handler.set_handler(0x6, "close", 1, self._handle_close)
+        syscall_handler.set_handler(0x142, "openat", 4, self._handle_openat)
+
+    def _handle_read(self, mu, fd, buf_addr, count):
+        """
+        ssize_t read(int fd, void *buf, size_t count);
+
+        On files that support seeking, the read operation commences at the current file offset, and the file offset
+        is incremented by the number of bytes read. If the current file offset is at or past the end of file,
+        no bytes are read, and read() returns zero.
+
+        If count is zero, read() may detect the errors described below. In the absence of any errors, or if read()
+        does not check for errors, a read() with a count of 0 returns zero and has no other effects.
+
+        If count is greater than SSIZE_MAX, the result is unspecified.
+        """
+        if fd <= 2:
+            raise NotImplementedError("Unsupported read operation for file descriptor %d." % fd)
+
+        if fd not in self._file_descriptors:
+            # TODO: Return valid error.
+            raise NotImplementedError()
+
+        file_handle = self._file_descriptors[fd]
+        buf = os.read(file_handle, count)
+        result = len(buf)
+        mu.mem_write(buf_addr, buf)
+        return result
+
+    def _handle_close(self, mu, fd):
+        """
+        int close(int fd);
+
+        close() closes a file descriptor, so that it no longer refers to any file and may be reused. Any record locks
+        (see fcntl(2)) held on the file it was associated with, and owned by the process, are removed (regardless of
+        the file descriptor that was used to obtain the lock).
+
+        close() returns zero on success. On error, -1 is returned, and errno is set appropriately.
+        """
+        if fd not in self._file_descriptors:
+            return 0
+
+        os.close(self._file_descriptors[fd])
+        return 0
+
+    def _handle_openat(self, mu, dfd, filename_ptr, flags, mode):
+        """
+        int openat(int dirfd, const char *pathname, int flags, mode_t mode);
+
+        On success, openat() returns a new file descriptor.
+        On error, -1 is returned and errno is set to indicate the error.
+
+        EBADF
+            dirfd is not a valid file descriptor.
+        ENOTDIR
+            pathname is relative and dirfd is a file descriptor referring to a file other than a directory.
+        """
+        filename = memory_helpers.read_utf8(mu, filename_ptr)
+
+        if filename.startswith("/"):
+            filename = filename[1:]
+
+        file_path = posixpath.join(self._root_path, filename)
+        file_path = posixpath.normpath(file_path)
+
+        if posixpath.commonpath([file_path, self._root_path]) != self._root_path:
+            raise RuntimeError("Emulated binary tried to escape vfs jail.")
+
+        if os.path.isfile(file_path):
+            logger.info("File opened '%s'" % filename)
+            self._file_descriptors.append(os.open(file_path, flags=os.O_RDWR | os.O_BINARY))
+            return len(self._file_descriptors) - 1
+        else:
+            logger.info("File does not exist %s" % file_path)
+            return -1
diff --git a/debug_utils.py b/debug_utils.py
index 462307a..c20acfb 100644
--- a/debug_utils.py
+++ b/debug_utils.py
@@ -33,3 +33,8 @@ def hook_mem_write(uc, access, address, size, value, user_data):
 def hook_mem_read(uc, access, address, size, value, user_data):
     pc = uc.reg_read(UC_ARM_REG_PC)
     logger.debug(">>> Memory READ at 0x%x, data size = %u, pc: %x" % (address, size, pc))
+
+
+def hook_interrupt(uc, intno, data):
+    logger.debug(">>> Triggering interrupt %d" % intno)
+    return
diff --git a/example_jni.py b/example_jni.py
index 9b5ac32..eb82b1c 100644
--- a/example_jni.py
+++ b/example_jni.py
@@ -1,6 +1,9 @@
 import logging
+import os
 import sys
+import posixpath
 
+from unicorn import UC_HOOK_CODE, UcError
 from unicorn.arm_const import *
 
 import debug_utils
@@ -16,7 +19,10 @@
 logger = logging.getLogger(__name__)
 
 # Initialize emulator
-emulator = Emulator()
+emulator = Emulator(
+    vfp_inst_set=True,
+    vfs_root=posixpath.join(posixpath.dirname(__file__), "vfs")
+)
 
 # Load all libraries.
 emulator.load_library("example_binaries/libdl.so")
@@ -42,6 +48,10 @@
 emulator.mu.reg_write(UC_ARM_REG_R1, 0x00)  # void* reserved
 
 # Run JNI_OnLoad.
-emulator.mu.emu_start(base_address + 0x7DEC + 1, base_address + 0x7EEA)
+try:
+    emulator.mu.emu_start(base_address + 0x7DEC + 1, base_address + 0x7EEA)
+except UcError as e:
+    print("Exit at %x" % emulator.mu.reg_read(UC_ARM_REG_PC))
+    raise
 
 logger.info("Exited EMU.")
diff --git a/vfs/proc/sys/vm/overcommit_memory b/vfs/proc/sys/vm/overcommit_memory
new file mode 100644
index 0000000..c227083
--- /dev/null
+++ b/vfs/proc/sys/vm/overcommit_memory
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/vfs/sys/devices/system/cpu/online b/vfs/sys/devices/system/cpu/online
new file mode 100644
index 0000000..8b0ad1b
--- /dev/null
+++ b/vfs/sys/devices/system/cpu/online
@@ -0,0 +1 @@
+0-3
\ No newline at end of file