diff --git a/api/src/info.rs b/api/src/info.rs
index cdb48722..965fcf40 100644
--- a/api/src/info.rs
+++ b/api/src/info.rs
@@ -56,6 +56,12 @@ pub struct BootInfo {
     pub ramdisk_addr: Optional<u64>,
     /// Ramdisk image size, set to 0 if addr is None
     pub ramdisk_len: u64,
+    /// Physical address of the kernel ELF in memory.
+    pub kernel_addr: u64,
+    /// Size of the kernel ELF in memory.
+    pub kernel_len: u64,
+    /// Virtual address of the loaded kernel image.
+    pub kernel_image_offset: u64,
 
     #[doc(hidden)]
     pub _test_sentinel: u64,
@@ -76,6 +82,9 @@ impl BootInfo {
             tls_template: Optional::None,
             ramdisk_addr: Optional::None,
             ramdisk_len: 0,
+            kernel_addr: 0,
+            kernel_len: 0,
+            kernel_image_offset: 0,
             _test_sentinel: 0,
         }
     }
diff --git a/common/src/legacy_memory_region.rs b/common/src/legacy_memory_region.rs
index bf804e9c..6f4b1741 100644
--- a/common/src/legacy_memory_region.rs
+++ b/common/src/legacy_memory_region.rs
@@ -110,10 +110,11 @@ where
     pub fn construct_memory_map(
         self,
         regions: &mut [MaybeUninit<MemoryRegion>],
-        kernel_slice_start: u64,
+        kernel_slice_start: PhysAddr,
         kernel_slice_len: u64,
     ) -> &mut [MemoryRegion] {
         let mut next_index = 0;
+        let kernel_slice_start = kernel_slice_start.as_u64();
 
         for descriptor in self.original {
             let mut start = descriptor.start();
diff --git a/common/src/lib.rs b/common/src/lib.rs
index ecd0d9cc..3c407644 100644
--- a/common/src/lib.rs
+++ b/common/src/lib.rs
@@ -39,7 +39,7 @@ pub mod serial;
 
 const PAGE_SIZE: u64 = 4096;
 
-/// Initialize a text-based logger using the given pixel-based framebuffer as output.  
+/// Initialize a text-based logger using the given pixel-based framebuffer as output.
 pub fn init_logger(
     framebuffer: &'static mut [u8],
     info: FrameBufferInfo,
@@ -195,10 +195,10 @@ where
     enable_write_protect_bit();
 
     let config = kernel.config;
-    let kernel_slice_start = kernel.start_address as u64;
+    let kernel_slice_start = PhysAddr::new(kernel.start_address as _);
     let kernel_slice_len = u64::try_from(kernel.len).unwrap();
 
-    let (entry_point, tls_template) = load_kernel::load_kernel(
+    let (kernel_image_offset, entry_point, tls_template) = load_kernel::load_kernel(
         kernel,
         kernel_page_table,
         frame_allocator,
@@ -402,6 +402,8 @@ where
 
         kernel_slice_start,
         kernel_slice_len,
+        kernel_image_offset,
+
         ramdisk_slice_start,
         ramdisk_slice_len,
     }
@@ -426,9 +428,11 @@ pub struct Mappings {
     pub tls_template: Option<TlsTemplate>,
 
     /// Start address of the kernel slice allocation in memory.
-    pub kernel_slice_start: u64,
+    pub kernel_slice_start: PhysAddr,
     /// Size of the kernel slice allocation in memory.
     pub kernel_slice_len: u64,
+    /// Relocation offset of the kernel image in virtual memory.
+    pub kernel_image_offset: VirtAddr,
     pub ramdisk_slice_start: Option<VirtAddr>,
     pub ramdisk_slice_len: u64,
 }
@@ -543,6 +547,9 @@ where
             .map(|addr| addr.as_u64())
             .into();
         info.ramdisk_len = mappings.ramdisk_slice_len;
+        info.kernel_addr = mappings.kernel_slice_start.as_u64();
+        info.kernel_len = mappings.kernel_slice_len as _;
+        info.kernel_image_offset = mappings.kernel_image_offset.as_u64();
         info._test_sentinel = boot_config._test_sentinel;
         info
     });
@@ -587,7 +594,7 @@ pub struct PageTables {
     ///
     /// Must be the page table that the `kernel` field of this struct refers to.
     ///
-    /// This frame is loaded into the `CR3` register on the final context switch to the kernel.  
+    /// This frame is loaded into the `CR3` register on the final context switch to the kernel.
     pub kernel_level_4_frame: PhysFrame,
 }
 
@@ -595,7 +602,13 @@ pub struct PageTables {
 unsafe fn context_switch(addresses: Addresses) -> ! {
     unsafe {
         asm!(
-            "mov cr3, {}; mov rsp, {}; push 0; jmp {}",
+            r#"
+            xor rbp, rbp
+            mov cr3, {}
+            mov rsp, {}
+            push 0
+            jmp {}
+            "#,
             in(reg) addresses.page_table.start_address().as_u64(),
             in(reg) addresses.stack_top.as_u64(),
             in(reg) addresses.entry_point.as_u64(),
diff --git a/common/src/load_kernel.rs b/common/src/load_kernel.rs
index a79a404a..68ad9778 100644
--- a/common/src/load_kernel.rs
+++ b/common/src/load_kernel.rs
@@ -721,11 +721,15 @@ pub fn load_kernel(
     page_table: &mut (impl MapperAllSizes + Translate),
     frame_allocator: &mut impl FrameAllocator<Size4KiB>,
     used_entries: &mut UsedLevel4Entries,
-) -> Result<(VirtAddr, Option<TlsTemplate>), &'static str> {
+) -> Result<(VirtAddr, VirtAddr, Option<TlsTemplate>), &'static str> {
     let mut loader = Loader::new(kernel, page_table, frame_allocator, used_entries)?;
     let tls_template = loader.load_segments()?;
 
-    Ok((loader.entry_point(), tls_template))
+    Ok((
+        VirtAddr::new(loader.inner.virtual_address_offset.virtual_address_offset() as u64),
+        loader.entry_point(),
+        tls_template,
+    ))
 }
 
 /// A helper type used to offset virtual addresses for position independent