diff --git a/Cargo.toml b/Cargo.toml
index 08191d48d5f7eb4b32e60e36ad58280421aef196..5ac75deda3310c0b557488e9f7c0d3605c0eb09a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -26,7 +26,8 @@ version = "0.7"
 default-features = false
 
 [features]
-default = []
+default = ["pti"]
 doc = []
 live = []
 multi_core = []
+pti = []
diff --git a/src/arch/x86_64/interrupt/syscall.rs b/src/arch/x86_64/interrupt/syscall.rs
index bc4ea434ea40aebbf234e45b4dab0b2b2f0fc4d8..26da847da3dd59948800dc0f36ae9d79108521ff 100644
--- a/src/arch/x86_64/interrupt/syscall.rs
+++ b/src/arch/x86_64/interrupt/syscall.rs
@@ -1,20 +1,23 @@
+use arch::x86_64::pti;
+use syscall;
+
 #[naked]
 pub unsafe extern fn syscall() {
     #[inline(never)]
     unsafe fn inner(stack: &mut SyscallStack) {
-        extern {
-            fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, rbp: usize, stack: &mut SyscallStack) -> usize;
-        }
-
         let mut a;
-        {
-            let b;
-            let rbp;
-            asm!("" : "={rax}"(a), "={rbx}"(b), "={rbp}"(rbp)
+        let b;
+        let rbp;
+        asm!("" : "={rax}"(a), "={rbx}"(b), "={rbp}"(rbp)
                 : : : "intel", "volatile");
 
-            a = syscall(a, b, stack.rcx, stack.rdx, stack.rsi, stack.rdi, rbp, stack);
-        }
+        // Map kernel
+        pti::map();
+
+        a = syscall::syscall(a, b, stack.rcx, stack.rdx, stack.rsi, stack.rdi, rbp, stack);
+
+        // Unmap kernel
+        pti::unmap();
 
         asm!("" : : "{rax}"(a) : : "intel", "volatile");
     }
diff --git a/src/arch/x86_64/macros.rs b/src/arch/x86_64/macros.rs
index 4fa7fe45a375ab1f9fd5e334ea2f57c45a1814a7..c336dae76f4a7c4067d55cffbcabad60cde8b5d3 100644
--- a/src/arch/x86_64/macros.rs
+++ b/src/arch/x86_64/macros.rs
@@ -166,7 +166,13 @@ macro_rules! interrupt {
         pub unsafe extern fn $name () {
             #[inline(never)]
             unsafe fn inner() {
+                // Map kernel
+                $crate::arch::x86_64::pti::map();
+
                 $func
+
+                // Unmap kernel
+                $crate::arch::x86_64::pti::unmap();
             }
 
             // Push scratch registers
@@ -207,7 +213,13 @@ macro_rules! interrupt_stack {
         pub unsafe extern fn $name () {
             #[inline(never)]
             unsafe fn inner($stack: &mut $crate::arch::x86_64::macros::InterruptStack) {
+                // Map kernel
+                $crate::arch::x86_64::pti::map();
+
                 $func
+
+                // Unmap kernel
+                $crate::arch::x86_64::pti::unmap();
             }
 
             // Push scratch registers
@@ -254,7 +266,13 @@ macro_rules! interrupt_error {
         pub unsafe extern fn $name () {
             #[inline(never)]
             unsafe fn inner($stack: &$crate::arch::x86_64::macros::InterruptErrorStack) {
+                // Map kernel
+                $crate::arch::x86_64::pti::map();
+
                 $func
+
+                // Unmap kernel
+                $crate::arch::x86_64::pti::unmap();
             }
 
             // Push scratch registers
@@ -302,7 +320,13 @@ macro_rules! interrupt_stack_p {
         pub unsafe extern fn $name () {
             #[inline(never)]
             unsafe fn inner($stack: &mut $crate::arch::x86_64::macros::InterruptStackP) {
+                // Map kernel
+                $crate::arch::x86_64::pti::map();
+
                 $func
+
+                // Unmap kernel
+                $crate::arch::x86_64::pti::unmap();
             }
 
             // Push scratch registers
@@ -353,7 +377,13 @@ macro_rules! interrupt_error_p {
         pub unsafe extern fn $name () {
             #[inline(never)]
             unsafe fn inner($stack: &$crate::arch::x86_64::macros::InterruptErrorStackP) {
+                // Map kernel
+                $crate::arch::x86_64::pti::map();
+
                 $func
+
+                // Unmap kernel
+                $crate::arch::x86_64::pti::unmap();
             }
 
             // Push scratch registers
diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs
index 7ae1a8e2ea4db31786849dbd48121029401ddde0..ffa90a968d2940e24272c0a34008ad02f9e96099 100644
--- a/src/arch/x86_64/mod.rs
+++ b/src/arch/x86_64/mod.rs
@@ -16,8 +16,11 @@ pub mod interrupt;
 /// Paging
 pub mod paging;
 
+/// Page table isolation
+pub mod pti;
+
 /// Initialization and start function
 pub mod start;
 
 /// Stop function
-pub mod stop;
\ No newline at end of file
+pub mod stop;
diff --git a/src/arch/x86_64/pti.rs b/src/arch/x86_64/pti.rs
new file mode 100644
index 0000000000000000000000000000000000000000..bee8b3d1ee5a715e4ebb2bbd85228b8cfd2c7511
--- /dev/null
+++ b/src/arch/x86_64/pti.rs
@@ -0,0 +1,25 @@
+#[cfg(feature = "pti")]
+#[inline(always)]
+pub unsafe fn map() {
+    let _cr3: usize;
+    asm!("mov $0, cr3
+          mov cr3, $0"
+          : "=r"(_cr3) : : "memory" : "intel", "volatile");
+}
+
+#[cfg(feature = "pti")]
+#[inline(always)]
+pub unsafe fn unmap() {
+    let _cr3: usize;
+    asm!("mov $0, cr3
+          mov cr3, $0"
+          : "=r"(_cr3) : : "memory" : "intel", "volatile");
+}
+
+#[cfg(not(feature = "pti"))]
+#[inline(always)]
+pub unsafe fn map() {}
+
+#[cfg(not(feature = "pti"))]
+#[inline(always)]
+pub unsafe fn unmap() {}
diff --git a/src/arch/x86_64/start.rs b/src/arch/x86_64/start.rs
index 97735958c68cef615d6c40309bc996fa569974ba..ddc7b61de95b3445da574d0b2acf723afe62bc56 100644
--- a/src/arch/x86_64/start.rs
+++ b/src/arch/x86_64/start.rs
@@ -8,6 +8,7 @@ use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, AtomicUsize, ATOMIC_USIZE
 
 use acpi;
 use allocator;
+use arch::x86_64::pti;
 use device;
 use gdt;
 use idt;
@@ -190,6 +191,9 @@ pub unsafe extern fn kstart_ap(args_ptr: *const KernelArgsAp) -> ! {
 }
 
 pub unsafe fn usermode(ip: usize, sp: usize, arg: usize) -> ! {
+    // Unmap kernel
+    pti::unmap();
+
     // Go to usermode
     asm!("mov ds, r10d
         mov es, r10d
diff --git a/src/consts.rs b/src/consts.rs
index 5129460769acf89e1f999a7fe7c8fb66706b4304..309c4935343601f11a821651750f942fe8fc7be9 100644
--- a/src/consts.rs
+++ b/src/consts.rs
@@ -16,7 +16,8 @@
     pub const KERNEL_PML4: usize = (KERNEL_OFFSET & PML4_MASK)/PML4_SIZE;
 
     /// Offset to kernel heap
-    pub const KERNEL_HEAP_OFFSET: usize = KERNEL_OFFSET + PML4_SIZE/2;
+    pub const KERNEL_HEAP_OFFSET: usize = KERNEL_OFFSET - PML4_SIZE;
+    pub const KERNEL_HEAP_PML4: usize = (KERNEL_HEAP_OFFSET & PML4_MASK)/PML4_SIZE;
     /// Size of kernel heap
     pub const KERNEL_HEAP_SIZE: usize = 256 * 1024 * 1024; // 256 MB
 
diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs
index d0ff5f32ec1058aaaec69c7e7960a7f67baf4c75..e65d2a2216741150c2dac38f489d0702f2e5a9e7 100644
--- a/src/syscall/mod.rs
+++ b/src/syscall/mod.rs
@@ -44,12 +44,7 @@ pub mod time;
 /// Validate input
 pub mod validate;
 
-//mod print_call;
-//use self::print_call::print_call;
-
-
-#[no_mangle]
-pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: usize, stack: &mut SyscallStack) -> usize {
+pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: usize, stack: &mut SyscallStack) -> usize {
     #[inline(always)]
     fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: usize, stack: &mut SyscallStack) -> Result<usize> {
         match a & SYS_CLASS {
diff --git a/src/syscall/process.rs b/src/syscall/process.rs
index d3f72abfb33d037957b827b15b82a1f603d3333a..1b0bb2dd117dce1061e6d59c7fc7d102197bdb5a 100644
--- a/src/syscall/process.rs
+++ b/src/syscall/process.rs
@@ -355,15 +355,24 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
 
             context.arch.set_page_table(unsafe { new_table.address() });
 
-            // Copy kernel mapping
+            // Copy kernel image mapping
             {
-                let frame = active_table.p4()[::KERNEL_PML4].pointed_frame().expect("kernel table not mapped");
+                let frame = active_table.p4()[::KERNEL_PML4].pointed_frame().expect("kernel image not mapped");
                 let flags = active_table.p4()[::KERNEL_PML4].flags();
                 active_table.with(&mut new_table, &mut temporary_page, |mapper| {
                     mapper.p4_mut()[::KERNEL_PML4].set(frame, flags);
                 });
             }
 
+            // Copy kernel heap mapping
+            {
+                let frame = active_table.p4()[::KERNEL_HEAP_PML4].pointed_frame().expect("kernel heap not mapped");
+                let flags = active_table.p4()[::KERNEL_HEAP_PML4].flags();
+                active_table.with(&mut new_table, &mut temporary_page, |mapper| {
+                    mapper.p4_mut()[::KERNEL_HEAP_PML4].set(frame, flags);
+                });
+            }
+
             if let Some(fx) = kfx_option.take() {
                 context.arch.set_fx(fx.as_ptr() as usize);
                 context.kfx = Some(fx);