From f54573ae15f8294275ea0188eb2ad93509bd7b66 Mon Sep 17 00:00:00 2001
From: Yifan Wu <shinbokuow@163.com>
Date: Mon, 7 Dec 2020 18:07:19 +0800
Subject: [PATCH] Fetch buffer in user space as a Vec.

---
 os/src/mm/memory_set.rs |  2 +-
 os/src/mm/mod.rs        |  2 +-
 os/src/mm/page_table.rs | 35 ++++++++++++++++++++++++++++++++---
 os/src/syscall/fs.rs    | 11 ++++++++---
 os/src/syscall/mod.rs   |  2 +-
 os/src/trap/mod.rs      | 12 ++++++------
 6 files changed, 49 insertions(+), 15 deletions(-)

diff --git a/os/src/mm/memory_set.rs b/os/src/mm/memory_set.rs
index dc9c57d7..580451b2 100644
--- a/os/src/mm/memory_set.rs
+++ b/os/src/mm/memory_set.rs
@@ -260,7 +260,7 @@ impl MapArea {
             self.unmap_one(page_table, vpn);
         }
     }
-    /// data: start-aligned but maybe with shorted length
+    /// data: start-aligned but maybe with shorter length
     /// assume that all frames were cleared before
     pub fn copy_data(&mut self, page_table: &mut PageTable, data: &[u8]) {
         assert_eq!(self.map_type, MapType::Framed);
diff --git a/os/src/mm/mod.rs b/os/src/mm/mod.rs
index 8c07c4d8..0118b194 100644
--- a/os/src/mm/mod.rs
+++ b/os/src/mm/mod.rs
@@ -8,7 +8,7 @@ use page_table::{PageTable, PTEFlags};
 use address::{VPNRange, StepByOne};
 pub use address::{PhysAddr, VirtAddr, PhysPageNum, VirtPageNum};
 pub use frame_allocator::{FrameTracker, frame_alloc};
-pub use page_table::{PageTableEntry};
+pub use page_table::{PageTableEntry, translated_byte_buffer};
 pub use memory_set::{MemorySet, KERNEL_SPACE, MapPermission};
 pub use memory_set::remap_test;
 
diff --git a/os/src/mm/page_table.rs b/os/src/mm/page_table.rs
index fa6b5cc5..86ba8d8d 100644
--- a/os/src/mm/page_table.rs
+++ b/os/src/mm/page_table.rs
@@ -1,4 +1,4 @@
-use super::{frame_alloc, PhysPageNum, FrameTracker, VirtPageNum};
+use super::{frame_alloc, PhysPageNum, FrameTracker, VirtPageNum, VirtAddr, StepByOne};
 use alloc::vec::Vec;
 use alloc::vec;
 use bitflags::*;
@@ -69,9 +69,9 @@ impl PageTable {
         }
     }
     /// Temporarily used to get arguments from user space.
-    pub fn from_root_ppn(root_ppn: PhysPageNum) -> Self {
+    pub fn from_token(satp: usize) -> Self {
         Self {
-            root_ppn,
+            root_ppn: PhysPageNum::from(satp & ((1usize << 44) - 1)),
             frames: Vec::new(),
         }
     }
@@ -95,6 +95,8 @@ impl PageTable {
         result
     }
     fn find_pte(&self, vpn: VirtPageNum) -> Option<&PageTableEntry> {
+        //println!("into find_pte");
+        //println!("root_ppn = {:?}", self.root_ppn);
         let idxs = vpn.indexes();
         let mut ppn = self.root_ppn;
         let mut result: Option<&PageTableEntry> = None;
@@ -123,10 +125,37 @@ impl PageTable {
         *pte = PageTableEntry::empty();
     }
     pub fn translate(&self, vpn: VirtPageNum) -> Option<PageTableEntry> {
+        //println!("into PageTable::translate");
         self.find_pte(vpn)
             .map(|pte| {pte.clone()})
     }
     pub fn token(&self) -> usize {
         8usize << 60 | self.root_ppn.0
     }
+}
+
+pub fn translated_byte_buffer(token: usize, ptr: *const u8, len: usize) -> Vec<&'static [u8]> {
+    //println!("into translated_byte_buffer!");
+    let page_table = PageTable::from_token(token);
+    let mut start = ptr as usize;
+    let end = start + len;
+    //println!("start={:#x},end={:#x}", start, end);
+    let mut v = Vec::new();
+    while start < end {
+        //println!("start={:#x}", start);
+        let start_va = VirtAddr::from(start);
+        let mut vpn = start_va.floor();
+        //println!("vpn={:?}", vpn);
+        let ppn = page_table
+            .translate(vpn)
+            .unwrap()
+            .ppn();
+        //println!("ppn={:?}", ppn);
+        vpn.step();
+        let mut end_va: VirtAddr = vpn.into();
+        end_va = end_va.min(VirtAddr::from(end));
+        v.push(&ppn.get_bytes_array()[start_va.page_offset()..end_va.page_offset()]);
+        start = end_va.into();
+    }
+    v
 }
\ No newline at end of file
diff --git a/os/src/syscall/fs.rs b/os/src/syscall/fs.rs
index b8c46591..c431dfc9 100644
--- a/os/src/syscall/fs.rs
+++ b/os/src/syscall/fs.rs
@@ -1,11 +1,16 @@
+use crate::mm::translated_byte_buffer;
+use crate::task::current_user_token;
+
 const FD_STDOUT: usize = 1;
 
 pub fn sys_write(fd: usize, buf: *const u8, len: usize) -> isize {
+    //println!("into sys_write!");
     match fd {
         FD_STDOUT => {
-            let slice = unsafe { core::slice::from_raw_parts(buf, len) };
-            let str = core::str::from_utf8(slice).unwrap();
-            print!("{}", str);
+            let buffers = translated_byte_buffer(current_user_token(), buf, len);
+            for buffer in buffers {
+                print!("{}", core::str::from_utf8(buffer).unwrap());
+            }
             len as isize
         },
         _ => {
diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs
index ee0d0fc9..fc5254d0 100644
--- a/os/src/syscall/mod.rs
+++ b/os/src/syscall/mod.rs
@@ -10,7 +10,7 @@ use fs::*;
 use process::*;
 
 pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
-    println!("into syscall!");
+    //println!("into syscall!");
     match syscall_id {
         SYSCALL_WRITE => sys_write(args[0], args[1] as *const u8, args[2]),
         SYSCALL_EXIT => sys_exit(args[0] as i32),
diff --git a/os/src/trap/mod.rs b/os/src/trap/mod.rs
index 026e1b36..f11106d9 100644
--- a/os/src/trap/mod.rs
+++ b/os/src/trap/mod.rs
@@ -41,13 +41,13 @@ pub fn enable_timer_interrupt() {
 
 #[no_mangle]
 pub fn trap_handler() -> ! {
-    println!("into trap_handler!");
+    //println!("into trap_handler!");
     let cx = current_trap_cx();
     let scause = scause::read();
     let stval = stval::read();
     match scause.cause() {
         Trap::Exception(Exception::UserEnvCall) => {
-            println!("found UserEnvCall!");
+            //println!("found UserEnvCall!");
             cx.sepc += 4;
             cx.x[10] = syscall(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]) as usize;
         }
@@ -73,17 +73,17 @@ pub fn trap_handler() -> ! {
 
 #[no_mangle]
 pub fn trap_return() -> ! {
-    println!("into trap_return");
+    //println!("into trap_return");
     let trap_cx_ptr = TRAP_CONTEXT;
     let user_satp = current_user_token();
-    println!("trap_cx_ptr={:#x}, user_satp={:#x}", trap_cx_ptr, user_satp);
+    //println!("trap_cx_ptr={:#x}, user_satp={:#x}", trap_cx_ptr, user_satp);
     extern "C" {
         fn __alltraps();
         fn __restore();
     }
     let restore_va = __restore as usize - __alltraps as usize + TRAMPOLINE;
-    println!("__alltraps={:#x},__restore={:#x}", __alltraps as usize, __restore as usize);
-    println!("restore_va={:#x}", restore_va);
+    //println!("__alltraps={:#x},__restore={:#x}", __alltraps as usize, __restore as usize);
+    //println!("restore_va={:#x}", restore_va);
     unsafe {
         llvm_asm!("jr $0" :: "r"(restore_va), "{a0}"(trap_cx_ptr), "{a1}"(user_satp) :: "volatile");
     }