diff --git a/vm/src/app_ui/mod.rs b/vm/src/app_ui/mod.rs new file mode 100644 index 0000000..915a9fa --- /dev/null +++ b/vm/src/app_ui/mod.rs @@ -0,0 +1 @@ +pub mod menu; \ No newline at end of file diff --git a/vm/src/handlers/lib/mod.rs b/vm/src/handlers/lib/mod.rs new file mode 100644 index 0000000..9b969cf --- /dev/null +++ b/vm/src/handlers/lib/mod.rs @@ -0,0 +1 @@ +pub mod outsourced_mem; \ No newline at end of file diff --git a/vm/src/handlers/lib/outsourced_mem.rs b/vm/src/handlers/lib/outsourced_mem.rs new file mode 100644 index 0000000..64fc46f --- /dev/null +++ b/vm/src/handlers/lib/outsourced_mem.rs @@ -0,0 +1,108 @@ +use core::cell::RefCell; + +use alloc::rc::Rc; +use common::vm::{Page, PagedMemory}; +use ledger_device_sdk::io; + +use common::constants::PAGE_SIZE; +use common::client_commands::ClientCommandCode; + +use crate::{AppSW, Instruction}; + + +// TODO: temporary implementation that stores a single page, and without page integrity checks +pub struct OutsourcedMemory<'c> { + comm: Rc>, + idx: Option, + page: Page, + is_readonly: bool +} + +impl<'c> OutsourcedMemory<'c> { + pub fn new(comm: Rc>, is_readonly: bool) -> Self { + Self { + comm, + idx: None, + page: Page { data: [0; PAGE_SIZE] }, + is_readonly + } + } + + fn commit_page(&mut self) -> Result<(), &'static str> { + let Some(idx) = self.idx else { + panic!("No page to commit"); + }; + + let mut comm = self.comm.borrow_mut(); + + // First message: communicate the page to commit + // TODO: should add a byte to identify in which segment does the page belong + comm.append(&[ClientCommandCode::CommitPage as u8]); + comm.append(&idx.to_be_bytes()); + comm.reply(AppSW::InterruptedExecution); + + let Instruction::Continue(p1, p2) = comm.next_command() else { + return Err("INS not supported"); // expected "Continue" + }; + + if (p1, p2) != (0, 0) { + return Err("Wrong P1/P2"); + } + + // Second message message: communicate the page content + comm.append(&[ClientCommandCode::CommitPageContent as u8]); + comm.append(&self.page.data); + + let Instruction::Continue(p1, p2) = comm.next_command() else { + return Err("INS not supported"); // expected "Continue" + }; + + if (p1, p2) != (0, 0) { + return Err("Wrong P1/P2"); + } + + Ok(()) + } +} + +impl<'c> PagedMemory for OutsourcedMemory<'c> { + type PageRef<'a> = &'a mut Page where Self: 'a; + + fn get_page<'a>(&'a mut self, page_index: u32) -> Result, &'static str> { + if let Some(idx) = &mut self.idx { + if *idx == page_index { + return Ok(&mut self.page); + } else { + if !self.is_readonly { + self.commit_page()?; + } + } + } + + let mut comm = self.comm.borrow_mut(); + comm.append(&[ClientCommandCode::GetPage as u8]); + comm.append(&page_index.to_be_bytes()); + comm.reply(AppSW::InterruptedExecution); + + let Instruction::Continue(p1, p2) = comm.next_command() else { + return Err("INS not supported"); // expected "Continue" + }; + + if p2 != 0 { + return Err("Wrong P2"); + } + + let fetched_data = comm.get_data().map_err(|_| "Wrong APDU length")?; + if fetched_data.len() != PAGE_SIZE - 1 { + return Err("Wrong APDU length"); + } + // overwrite page content + self.page.data[0..PAGE_SIZE - 1].copy_from_slice(fetched_data); + self.page.data[PAGE_SIZE - 1] = p1; + + // update index + self.idx = Some(page_index); + + Ok(&mut self.page) + } +} diff --git a/vm/src/handlers/mod.rs b/vm/src/handlers/mod.rs new file mode 100644 index 0000000..3653295 --- /dev/null +++ b/vm/src/handlers/mod.rs @@ -0,0 +1,5 @@ +pub mod get_version; +pub mod register_vapp; +pub mod start_vapp; + +mod lib; \ No newline at end of file diff --git a/vm/src/handlers/start_vapp.rs b/vm/src/handlers/start_vapp.rs index 6e1973f..39631db 100644 --- a/vm/src/handlers/start_vapp.rs +++ b/vm/src/handlers/start_vapp.rs @@ -1,112 +1,14 @@ use core::cell::RefCell; -use common::vm::{Cpu, MemorySegment, Page, PagedMemory}; -use crate::{println, AppSW, Instruction}; - use alloc::rc::Rc; use ledger_device_sdk::io; use common::manifest::Manifest; -use common::constants::PAGE_SIZE; -use common::client_commands::ClientCommandCode; - -// TODO: temporary implementation that stores a single page, and without page integrity checks -struct OutsourcedMemory<'c> { - comm: Rc>, - idx: Option, - page: Page, - is_readonly: bool -} - -impl<'c> OutsourcedMemory<'c> { - fn new(comm: Rc>, is_readonly: bool) -> Self { - Self { - comm, - idx: None, - page: Page { data: [0; PAGE_SIZE] }, - is_readonly - } - } - - fn commit_page(&mut self) -> Result<(), &'static str> { - let Some(idx) = self.idx else { - panic!("No page to commit"); - }; - - let mut comm = self.comm.borrow_mut(); - - // First message: communicate the page to commit - // TODO: should add a byte to identify in which segment does the page belong - comm.append(&[ClientCommandCode::CommitPage as u8]); - comm.append(&idx.to_be_bytes()); - comm.reply(AppSW::InterruptedExecution); - - let Instruction::Continue(p1, p2) = comm.next_command() else { - return Err("INS not supported"); // expected "Continue" - }; - - if (p1, p2) != (0, 0) { - return Err("Wrong P1/P2"); - } - - // Second message message: communicate the page content - comm.append(&[ClientCommandCode::CommitPageContent as u8]); - comm.append(&self.page.data); +use common::vm::{Cpu, MemorySegment}; - let Instruction::Continue(p1, p2) = comm.next_command() else { - return Err("INS not supported"); // expected "Continue" - }; - - if (p1, p2) != (0, 0) { - return Err("Wrong P1/P2"); - } - - Ok(()) - } -} - -impl<'c> PagedMemory for OutsourcedMemory<'c> { - type PageRef<'a> = &'a mut Page where Self: 'a; - - fn get_page<'a>(&'a mut self, page_index: u32) -> Result, &'static str> { - if let Some(idx) = &mut self.idx { - if *idx == page_index { - return Ok(&mut self.page); - } else { - if !self.is_readonly { - self.commit_page()?; - } - } - } - - let mut comm = self.comm.borrow_mut(); - comm.append(&[ClientCommandCode::GetPage as u8]); - comm.append(&page_index.to_be_bytes()); - comm.reply(AppSW::InterruptedExecution); - - let Instruction::Continue(p1, p2) = comm.next_command() else { - return Err("INS not supported"); // expected "Continue" - }; - - if p2 != 0 { - return Err("Wrong P2"); - } - - let fetched_data = comm.get_data().map_err(|_| "Wrong APDU length")?; - if fetched_data.len() != PAGE_SIZE - 1 { - return Err("Wrong APDU length"); - } - // overwrite page content - self.page.data[0..PAGE_SIZE - 1].copy_from_slice(fetched_data); - self.page.data[PAGE_SIZE - 1] = p1; - - // update index - self.idx = Some(page_index); - - Ok(&mut self.page) - } -} +use crate::{println, AppSW}; +use super::lib::outsourced_mem::OutsourcedMemory; pub fn handler_start_vapp(comm: &mut io::Comm) -> Result<(), AppSW> { @@ -128,7 +30,7 @@ pub fn handler_start_vapp(comm: &mut io::Comm) -> Result<(), AppSW> { println!("Running app with Manifest: {:?}", manifest); println!("hmac: {:?}", hmac); - + let comm = Rc::new(RefCell::new(comm)); let code_seg = MemorySegment::::new( diff --git a/vm/src/main.rs b/vm/src/main.rs index 66b66bf..7c02b40 100644 --- a/vm/src/main.rs +++ b/vm/src/main.rs @@ -18,14 +18,8 @@ #![no_std] #![no_main] -mod app_ui { - pub mod menu; -} -mod handlers { - pub mod get_version; - pub mod register_vapp; - pub mod start_vapp; -} +mod app_ui; +mod handlers; mod settings;