From f1aa2c2c5261ff28252e06cd52faae91c8d8ccda Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jackpot51@gmail.com>
Date: Mon, 22 Aug 2022 12:37:07 -0600
Subject: [PATCH] Optimization for reading boot files from live disk

---
 src/main.rs         | 75 ++++++++++++++++++++++++++-------------------
 src/os/bios/disk.rs | 12 ++++++++
 src/os/uefi/disk.rs | 12 ++++++++
 3 files changed, 67 insertions(+), 32 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index 963823f..01d1fb6 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -48,6 +48,8 @@ pub static mut AREAS: [OsMemoryEntry; 512] = [OsMemoryEntry {
 
 pub static mut KERNEL_64BIT: bool = false;
 
+pub static mut LIVE_OPT: Option<(u64, &'static [u8])> = None;
+
 struct SliceWriter<'a> {
     slice: &'a mut [u8],
     i: usize,
@@ -383,38 +385,6 @@ fn main<
         panic!("Failed to allocate memory for stack");
     }
 
-    let (kernel, kernel_entry) = {
-        let kernel = load_to_memory(os, &mut fs, "boot", "kernel", Filetype::Elf);
-        let (kernel_entry, kernel_64bit) = elf_entry(kernel);
-        unsafe { KERNEL_64BIT = kernel_64bit; }
-        (kernel, kernel_entry)
-    };
-
-    let (bootstrap_size, bootstrap_base, bootstrap_entry, initfs_offset, initfs_len) = {
-        let initfs_slice = load_to_memory(os, &mut fs, "boot", "initfs", Filetype::Other);
-        let bootstrap_slice = load_to_memory(os, &mut fs, "boot", "bootstrap", Filetype::Elf);
-        let bootstrap_len = (bootstrap_slice.len()+4095)/4096*4096;
-        let initfs_len = (initfs_slice.len()+4095)/4096*4096;
-        let (bootstrap_entry, bootstrap_64bit) = elf_entry(bootstrap_slice);
-        unsafe { assert_eq!(KERNEL_64BIT, bootstrap_64bit); }
-
-        let memory = unsafe {
-            let total_size = initfs_len + bootstrap_len;
-            let ptr = os.alloc_zeroed_page_aligned(total_size);
-            assert!(!ptr.is_null(), "failed to allocate bootstrap+initfs memory");
-            core::slice::from_raw_parts_mut(ptr, total_size)
-        };
-        memory[..bootstrap_slice.len()].copy_from_slice(bootstrap_slice);
-        memory[bootstrap_len..bootstrap_len + initfs_slice.len()].copy_from_slice(initfs_slice);
-
-        (memory.len() as u64, memory.as_mut_ptr() as u64, bootstrap_entry, bootstrap_len, initfs_len)
-    };
-
-    let page_phys = unsafe {
-        paging_create(os, kernel.as_ptr() as u64, kernel.len() as u64)
-    }.expect("Failed to set up paging");
-    //TODO: properly reserve page table allocations so kernel does not re-use them
-
     let live_opt = if cfg!(feature = "live") {
         let size = fs.header.size();
 
@@ -439,12 +409,53 @@ fn main<
         }
         println!("\rlive: {}/{} MiB", i / MIBI as u64, size / MIBI as u64);
 
+        println!("Switching to live disk");
+        unsafe {
+            LIVE_OPT = Some((
+                fs.block,
+                slice::from_raw_parts_mut(ptr, size as usize)
+            ));
+        }
+
         Some(live)
     } else {
         None
     };
     //TODO: properly reserve live disk so kernel does not re-use it
 
+    let (kernel, kernel_entry) = {
+        let kernel = load_to_memory(os, &mut fs, "boot", "kernel", Filetype::Elf);
+        let (kernel_entry, kernel_64bit) = elf_entry(kernel);
+        unsafe { KERNEL_64BIT = kernel_64bit; }
+        (kernel, kernel_entry)
+    };
+
+    let (bootstrap_size, bootstrap_base, bootstrap_entry, initfs_offset, initfs_len) = {
+        let bootstrap_slice = load_to_memory(os, &mut fs, "boot", "bootstrap", Filetype::Elf);
+        let bootstrap_len = (bootstrap_slice.len()+4095)/4096*4096;
+        let (bootstrap_entry, bootstrap_64bit) = elf_entry(bootstrap_slice);
+        unsafe { assert_eq!(KERNEL_64BIT, bootstrap_64bit); }
+
+        let initfs_slice = load_to_memory(os, &mut fs, "boot", "initfs", Filetype::Other);
+        let initfs_len = (initfs_slice.len()+4095)/4096*4096;
+
+        let memory = unsafe {
+            let total_size = initfs_len + bootstrap_len;
+            let ptr = os.alloc_zeroed_page_aligned(total_size);
+            assert!(!ptr.is_null(), "failed to allocate bootstrap+initfs memory");
+            core::slice::from_raw_parts_mut(ptr, total_size)
+        };
+        memory[..bootstrap_slice.len()].copy_from_slice(bootstrap_slice);
+        memory[bootstrap_len..bootstrap_len + initfs_slice.len()].copy_from_slice(initfs_slice);
+
+        (memory.len() as u64, memory.as_mut_ptr() as u64, bootstrap_entry, bootstrap_len, initfs_len)
+    };
+
+    let page_phys = unsafe {
+        paging_create(os, kernel.as_ptr() as u64, kernel.len() as u64)
+    }.expect("Failed to set up paging");
+    //TODO: properly reserve page table allocations so kernel does not re-use them
+
     let mut env_size = 4 * KIBI;
     let env_base = os.alloc_zeroed_page_aligned(env_size);
     if env_base.is_null() {
diff --git a/src/os/bios/disk.rs b/src/os/bios/disk.rs
index 1eb4c96..0551ef1 100644
--- a/src/os/bios/disk.rs
+++ b/src/os/bios/disk.rs
@@ -52,6 +52,18 @@ impl DiskBios {
 
 impl Disk for DiskBios {
     unsafe fn read_at(&mut self, block: u64, buffer: &mut [u8]) -> Result<usize> {
+        // Optimization for live disks
+        if let Some(live) = crate::LIVE_OPT {
+            if block >= live.0 {
+                let start = ((block - live.0) * BLOCK_SIZE) as usize;
+                let end = start + buffer.len();
+                if end <= live.1.len() {
+                    buffer.copy_from_slice(&live.1[start..end]);
+                    return Ok(buffer.len());
+                }
+            }
+        }
+
         for (i, chunk) in buffer.chunks_mut((MAX_BLOCKS * BLOCK_SIZE) as usize).enumerate() {
             let mut dap = DiskAddressPacket::from_block(
                 block + i as u64 * MAX_BLOCKS,
diff --git a/src/os/uefi/disk.rs b/src/os/uefi/disk.rs
index 5a52355..25b9aa0 100644
--- a/src/os/uefi/disk.rs
+++ b/src/os/uefi/disk.rs
@@ -19,6 +19,18 @@ impl Protocol<UefiBlockIo> for DiskEfi {
 
 impl Disk for DiskEfi {
     unsafe fn read_at(&mut self, block: u64, buffer: &mut [u8]) -> Result<usize> {
+        // Optimization for live disks
+        if let Some(live) = crate::LIVE_OPT {
+            if block >= live.0 {
+                let start = ((block - live.0) * BLOCK_SIZE) as usize;
+                let end = start + buffer.len();
+                if end <= live.1.len() {
+                    buffer.copy_from_slice(&live.1[start..end]);
+                    return Ok(buffer.len());
+                }
+            }
+        }
+
         let block_size = self.0.Media.BlockSize as u64;
 
         let lba = block * BLOCK_SIZE / block_size;
-- 
GitLab