Skip to content

Commit

Permalink
Refactored OutsourcedMemory into a submodule; simplified module struc…
Browse files Browse the repository at this point in the history
…ture of the VM app
  • Loading branch information
bigspider committed Aug 29, 2024
1 parent ea78865 commit dd6c65a
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 110 deletions.
1 change: 1 addition & 0 deletions vm/src/app_ui/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod menu;
1 change: 1 addition & 0 deletions vm/src/handlers/lib/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod outsourced_mem;
108 changes: 108 additions & 0 deletions vm/src/handlers/lib/outsourced_mem.rs
Original file line number Diff line number Diff line change
@@ -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<RefCell<&'c mut io::Comm>>,
idx: Option<u32>,
page: Page,
is_readonly: bool
}

impl<'c> OutsourcedMemory<'c> {
pub fn new(comm: Rc<RefCell<&'c mut io::Comm>>, 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<Self::PageRef<'a>, &'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)
}
}
5 changes: 5 additions & 0 deletions vm/src/handlers/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub mod get_version;
pub mod register_vapp;
pub mod start_vapp;

mod lib;
106 changes: 4 additions & 102 deletions vm/src/handlers/start_vapp.rs
Original file line number Diff line number Diff line change
@@ -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<RefCell<&'c mut io::Comm>>,
idx: Option<u32>,
page: Page,
is_readonly: bool
}

impl<'c> OutsourcedMemory<'c> {
fn new(comm: Rc<RefCell<&'c mut io::Comm>>, 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<Self::PageRef<'a>, &'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> {
Expand All @@ -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::<OutsourcedMemory>::new(
Expand Down
10 changes: 2 additions & 8 deletions vm/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down

0 comments on commit dd6c65a

Please sign in to comment.