From 4692e9b2674da255a72348e3b32ec3c91cf327e7 Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jackpot51@gmail.com>
Date: Sat, 10 Sep 2016 19:42:26 -0600
Subject: [PATCH] Load init from initfs

---
 lib.rs           | 29 +++++++++++++-------
 scheme/initfs.rs | 70 ++++++++++++++++++++++++++++++++++++++++++++++++
 scheme/mod.rs    |  5 ++++
 3 files changed, 94 insertions(+), 10 deletions(-)
 create mode 100644 scheme/initfs.rs

diff --git a/lib.rs b/lib.rs
index 08c99441..836aa19a 100644
--- a/lib.rs
+++ b/lib.rs
@@ -133,11 +133,23 @@ pub extern fn kmain() {
     let pid = syscall::getpid();
     println!("BSP: {:?}", pid);
 
-    assert_eq!(syscall::open("debug:".as_bytes(), 0), Ok(0));
-    assert_eq!(syscall::open("debug:".as_bytes(), 0), Ok(1));
-    assert_eq!(syscall::open("debug:".as_bytes(), 0), Ok(2));
+    assert_eq!(syscall::open(b"debug:", 0), Ok(0));
+    assert_eq!(syscall::open(b"debug:", 0), Ok(1));
+    assert_eq!(syscall::open(b"debug:", 0), Ok(2));
 
-    let elf = elf::Elf::from(include_bytes!("../build/userspace/init")).expect("could not load elf");
+    let init_file = syscall::open(b"initfs:init", 0).expect("failed to open initfs:init");
+    let mut init_data = collections::Vec::new();
+    loop {
+        let mut buf = [0; 65536];
+        let count = syscall::read(init_file, &mut buf).expect("failed to read initfs:init");
+        if count > 0 {
+            init_data.extend_from_slice(&buf[..count]);
+        } else {
+            break;
+        }
+    }
+
+    let elf = elf::Elf::from(&init_data).expect("could not load elf");
     elf.run();
 
     /*
@@ -163,12 +175,9 @@ pub extern fn kmain_ap(id: usize) {
     let pid = syscall::getpid();
     println!("AP {}: {:?}", id, pid);
 
-    assert_eq!(syscall::open("debug:".as_bytes(), 0), Ok(0));
-    assert_eq!(syscall::open("debug:".as_bytes(), 0), Ok(1));
-    assert_eq!(syscall::open("debug:".as_bytes(), 0), Ok(2));
-
-    let elf = elf::Elf::from(include_bytes!("../build/userspace/init")).expect("could not load elf");
-    elf.run();
+    assert_eq!(syscall::open(b"debug:", 0), Ok(0));
+    assert_eq!(syscall::open(b"debug:", 0), Ok(1));
+    assert_eq!(syscall::open(b"debug:", 0), Ok(2));
 
     loop {
         unsafe { interrupt::enable_and_halt() }
diff --git a/scheme/initfs.rs b/scheme/initfs.rs
new file mode 100644
index 00000000..145f7f69
--- /dev/null
+++ b/scheme/initfs.rs
@@ -0,0 +1,70 @@
+use collections::BTreeMap;
+
+use syscall::{Error, Result};
+use super::Scheme;
+
+struct Handle {
+    data: &'static [u8],
+    seek: usize
+}
+
+pub struct InitFsScheme {
+    next_id: usize,
+    files: BTreeMap<&'static [u8], &'static [u8]>,
+    handles: BTreeMap<usize, Handle>
+}
+
+impl InitFsScheme {
+    pub fn new() -> InitFsScheme {
+        let mut files: BTreeMap<&'static [u8], &'static [u8]> = BTreeMap::new();
+
+        files.insert(b"init", include_bytes!("../../build/userspace/init"));
+
+        InitFsScheme {
+            next_id: 0,
+            files: files,
+            handles: BTreeMap::new()
+        }
+    }
+}
+
+impl Scheme for InitFsScheme {
+    fn open(&mut self, path: &[u8], _flags: usize) -> Result<usize> {
+        let data = self.files.get(path).ok_or(Error::NoEntry)?;
+        let id = self.next_id;
+        self.next_id += 1;
+        self.handles.insert(id, Handle {
+            data: data,
+            seek: 0
+        });
+        Ok(id)
+    }
+
+    /// Read the file `number` into the `buffer`
+    ///
+    /// Returns the number of bytes read
+    fn read(&mut self, file: usize, buffer: &mut [u8]) -> Result<usize> {
+        let mut handle = self.handles.get_mut(&file).ok_or(Error::BadFile)?;
+
+        let mut i = 0;
+        while i < buffer.len() && handle.seek < handle.data.len() {
+            buffer[i] = handle.data[handle.seek];
+            i += 1;
+            handle.seek += 1;
+        }
+
+        Ok(i)
+    }
+
+    /// Write the `buffer` to the `file`
+    ///
+    /// Returns the number of bytes written
+    fn write(&mut self, _file: usize, _buffer: &[u8]) -> Result<usize> {
+        Err(Error::NotPermitted)
+    }
+
+    /// Close the file `number`
+    fn close(&mut self, file: usize) -> Result<()> {
+        self.handles.remove(&file).ok_or(Error::BadFile).and(Ok(()))
+    }
+}
diff --git a/scheme/mod.rs b/scheme/mod.rs
index 99a50a10..ef86570f 100644
--- a/scheme/mod.rs
+++ b/scheme/mod.rs
@@ -16,10 +16,14 @@ use spin::{Once, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};
 use syscall::{Error, Result};
 
 use self::debug::DebugScheme;
+use self::initfs::InitFsScheme;
 
 /// Debug scheme
 pub mod debug;
 
+/// InitFS scheme
+pub mod initfs;
+
 /// Limit on number of schemes
 pub const SCHEME_MAX_SCHEMES: usize = 65536;
 
@@ -88,6 +92,7 @@ static SCHEMES: Once<RwLock<SchemeList>> = Once::new();
 fn init_schemes() -> RwLock<SchemeList> {
     let mut list: SchemeList = SchemeList::new();
     list.insert(Box::new(*b"debug"), Arc::new(Mutex::new(Box::new(DebugScheme)))).expect("failed to insert debug: scheme");
+    list.insert(Box::new(*b"initfs"), Arc::new(Mutex::new(Box::new(InitFsScheme::new())))).expect("failed to insert initfs: scheme");
     RwLock::new(list)
 }
 
-- 
GitLab