mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-08 04:56:43 +00:00
format sevices/pddb
wow the formatter hated this code. hope i can recognize it later on when it needs work, nobody else probably wants to touch it. :-/
This commit is contained in:
parent
8d30c5bfc5
commit
679435c5f4
25 changed files with 4474 additions and 3043 deletions
|
|
@ -1,9 +1,9 @@
|
|||
mod rkyv_enum;
|
||||
pub use rkyv_enum::*;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use bitfield::bitfield;
|
||||
use std::num::NonZeroU32;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
pub use rkyv_enum::*;
|
||||
|
||||
// on the "[allow(dead_code)]" directives: these constants are used to define the PDDB, and are
|
||||
// sometimes used by both `bin` (main.rs) and `lib` (lib.rs) views, but also, sometimes used
|
||||
|
|
@ -15,8 +15,8 @@ use core::ops::{Deref, DerefMut};
|
|||
// here, because sometimes, clippy just can't see the big picture.
|
||||
|
||||
// note this name cannot be changed because it is baked into `libstd`
|
||||
pub(crate) const SERVER_NAME_PDDB: &str = "_Plausibly Deniable Database_";
|
||||
pub(crate) const SERVER_NAME_PDDB_POLLER: &str = "_PDDB Mount Poller_";
|
||||
pub(crate) const SERVER_NAME_PDDB: &str = "_Plausibly Deniable Database_";
|
||||
pub(crate) const SERVER_NAME_PDDB_POLLER: &str = "_PDDB Mount Poller_";
|
||||
/// This is the registered name for a dedicated private API channel to the PDDB for doing the time reset
|
||||
/// Even though nobody but the PDDB should connect to this, we have to share it publicly so the PDDB can
|
||||
/// depend upon this constant.
|
||||
|
|
@ -43,10 +43,10 @@ pub(crate) const PDDB_VERSION: u32 = 0x00_00_02_01;
|
|||
#[allow(dead_code)]
|
||||
// PDDB_A_LEN may be shorter than xous::PDDB_LEN, to speed up testing.
|
||||
#[allow(dead_code)]
|
||||
#[cfg(not(any(feature="pddbtest",feature="autobasis",feature="ci",feature="smalldb")))]
|
||||
#[cfg(not(any(feature = "pddbtest", feature = "autobasis", feature = "ci", feature = "smalldb")))]
|
||||
pub(crate) const PDDB_A_LEN: usize = xous::PDDB_LEN as usize;
|
||||
#[allow(dead_code)]
|
||||
#[cfg(any(feature="pddbtest",feature="autobasis",feature="ci",feature="smalldb"))]
|
||||
#[cfg(any(feature = "pddbtest", feature = "autobasis", feature = "ci", feature = "smalldb"))]
|
||||
pub const PDDB_A_LEN: usize = 4 * 1024 * 1024;
|
||||
|
||||
/// range for the starting point of a journal number, picked from a random seed
|
||||
|
|
@ -108,7 +108,7 @@ pub(crate) const PDDB_FAST_SPACE_SYSTEM_BASIS: &'static str = ".FastSpace";
|
|||
|
||||
#[allow(dead_code)]
|
||||
// TODO: add hardware acceleration for BCRYPT so we can hit the OWASP target without excessive UX delay
|
||||
pub(crate) const BCRYPT_COST: u32 = 7; // 10 is the minimum recommended by OWASP; takes 5696 ms to verify @ 10 rounds; 804 ms to verify 7 rounds
|
||||
pub(crate) const BCRYPT_COST: u32 = 7; // 10 is the minimum recommended by OWASP; takes 5696 ms to verify @ 10 rounds; 804 ms to verify 7 rounds
|
||||
|
||||
#[derive(num_derive::FromPrimitive, num_derive::ToPrimitive, Debug)]
|
||||
pub(crate) enum Opcode {
|
||||
|
|
@ -160,7 +160,7 @@ pub(crate) enum Opcode {
|
|||
/// Write debug dump (only available in hosted mode)
|
||||
#[cfg(not(target_os = "xous"))]
|
||||
DangerousDebug = 25,
|
||||
#[cfg(all(feature="pddbtest", feature="autobasis"))]
|
||||
#[cfg(all(feature = "pddbtest", feature = "autobasis"))]
|
||||
BasisTesting = 26,
|
||||
|
||||
ListBasisStd = 26,
|
||||
|
|
@ -262,9 +262,11 @@ pub type ApiToken = [u32; 3];
|
|||
#[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
|
||||
#[repr(C)]
|
||||
pub struct PddbBasisList {
|
||||
/// the first 63 that fit in the list -- generally we anticipate not more than a few being open at a time, so this should be enough.
|
||||
pub list: [xous_ipc::String::<BASIS_NAME_LEN>; 63],
|
||||
/// total number of basis open. Should be <= 63, but we allow it to be larger to indicate cases where this structure wasn't big enough.
|
||||
/// the first 63 that fit in the list -- generally we anticipate not more than a few being open at a
|
||||
/// time, so this should be enough.
|
||||
pub list: [xous_ipc::String<BASIS_NAME_LEN>; 63],
|
||||
/// total number of basis open. Should be <= 63, but we allow it to be larger to indicate cases where
|
||||
/// this structure wasn't big enough.
|
||||
pub num: u32,
|
||||
}
|
||||
|
||||
|
|
@ -296,16 +298,16 @@ impl BasisRetentionPolicy {
|
|||
}
|
||||
#[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
|
||||
pub struct PddbBasisRequest {
|
||||
pub name: xous_ipc::String::<BASIS_NAME_LEN>,
|
||||
pub name: xous_ipc::String<BASIS_NAME_LEN>,
|
||||
pub code: PddbRequestCode,
|
||||
pub policy: Option<BasisRetentionPolicy>,
|
||||
}
|
||||
#[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
|
||||
pub struct PddbDictRequest {
|
||||
pub basis_specified: bool,
|
||||
pub basis: xous_ipc::String::<BASIS_NAME_LEN>,
|
||||
pub dict: xous_ipc::String::<DICT_NAME_LEN>,
|
||||
pub key: xous_ipc::String::<KEY_NAME_LEN>,
|
||||
pub basis: xous_ipc::String<BASIS_NAME_LEN>,
|
||||
pub dict: xous_ipc::String<DICT_NAME_LEN>,
|
||||
pub key: xous_ipc::String<KEY_NAME_LEN>,
|
||||
pub index: u32,
|
||||
pub token: [u32; 4],
|
||||
pub code: PddbRequestCode,
|
||||
|
|
@ -321,13 +323,14 @@ pub struct PddbDictRequest {
|
|||
#[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
|
||||
pub struct PddbKeyRequest {
|
||||
pub basis_specified: bool,
|
||||
pub basis: xous_ipc::String::<BASIS_NAME_LEN>,
|
||||
pub dict: xous_ipc::String::<DICT_NAME_LEN>,
|
||||
pub key: xous_ipc::String::<KEY_NAME_LEN>,
|
||||
pub basis: xous_ipc::String<BASIS_NAME_LEN>,
|
||||
pub dict: xous_ipc::String<DICT_NAME_LEN>,
|
||||
pub key: xous_ipc::String<KEY_NAME_LEN>,
|
||||
pub token: Option<ApiToken>,
|
||||
pub create_dict: bool,
|
||||
pub create_key: bool,
|
||||
pub alloc_hint: Option<u64>, // this is a usize but for IPC we must have defined memory sizes, so we pick the big option.
|
||||
pub alloc_hint: Option<u64>, /* this is a usize but for IPC we must have defined memory sizes, so we
|
||||
* pick the big option. */
|
||||
pub cb_sid: Option<[u32; 4]>,
|
||||
pub result: PddbRequestCode,
|
||||
}
|
||||
|
|
@ -335,7 +338,7 @@ pub struct PddbKeyRequest {
|
|||
pub(crate) const MAX_PDDBKLISTLEN: usize = 4064;
|
||||
/// A structure for requesting a token to access a particular key/value pair
|
||||
#[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
|
||||
pub (crate) struct PddbKeyList {
|
||||
pub(crate) struct PddbKeyList {
|
||||
pub token: [u32; 4],
|
||||
pub data: [u8; MAX_PDDBKLISTLEN],
|
||||
pub retcode: PddbRetcode,
|
||||
|
|
@ -345,17 +348,26 @@ pub (crate) struct PddbKeyList {
|
|||
/// A structure for bulk deletion of keys
|
||||
pub(crate) const MAX_PDDB_DELETE_LEN: usize = 3800; // approximate limit, might be a little higher if we cared to calculate it out
|
||||
#[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
|
||||
pub (crate) struct PddbDeleteList {
|
||||
pub(crate) struct PddbDeleteList {
|
||||
pub basis_specified: bool,
|
||||
pub basis: xous_ipc::String::<BASIS_NAME_LEN>,
|
||||
pub dict: xous_ipc::String::<DICT_NAME_LEN>,
|
||||
pub basis: xous_ipc::String<BASIS_NAME_LEN>,
|
||||
pub dict: xous_ipc::String<DICT_NAME_LEN>,
|
||||
pub data: [u8; MAX_PDDB_DELETE_LEN],
|
||||
pub retcode: PddbRetcode,
|
||||
}
|
||||
|
||||
/// Return codes for Read/Write API calls to the main server
|
||||
#[repr(u8)]
|
||||
#[derive(num_derive::FromPrimitive, num_derive::ToPrimitive, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Eq, PartialEq)]
|
||||
#[derive(
|
||||
num_derive::FromPrimitive,
|
||||
num_derive::ToPrimitive,
|
||||
Debug,
|
||||
rkyv::Archive,
|
||||
rkyv::Serialize,
|
||||
rkyv::Deserialize,
|
||||
Eq,
|
||||
PartialEq,
|
||||
)]
|
||||
pub(crate) enum PddbRetcode {
|
||||
Uninit = 0,
|
||||
Ok = 1,
|
||||
|
|
@ -380,7 +392,8 @@ pub(crate) struct PddbBuf {
|
|||
reserved: u8,
|
||||
/// length of the data field
|
||||
pub(crate) len: u16,
|
||||
/// point in the key stream. 64-bit for future-compatibility; but, can't be larger than 32 bits on a 32-bit target.
|
||||
/// point in the key stream. 64-bit for future-compatibility; but, can't be larger than 32 bits on a
|
||||
/// 32-bit target.
|
||||
pub(crate) position: u64,
|
||||
pub(crate) data: [u8; PDDB_BUF_DATA_LEN],
|
||||
}
|
||||
|
|
@ -401,12 +414,19 @@ pub struct PddbKeyRecord {
|
|||
/// and the record must be explicitly re-read with a non-bulk call to fetch its data,
|
||||
/// or the key has zero length. Check the `len` field to differentiate the two.
|
||||
/// (Turns out that `rkyv` crashes when deserializing a zero-length Vec)
|
||||
pub data: Option<Vec::<u8>>,
|
||||
pub data: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
/// Return codes for Read/Write API calls to the main server
|
||||
#[repr(u32)]
|
||||
#[derive(num_derive::FromPrimitive, num_derive::ToPrimitive, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
|
||||
#[derive(
|
||||
num_derive::FromPrimitive,
|
||||
num_derive::ToPrimitive,
|
||||
Debug,
|
||||
rkyv::Archive,
|
||||
rkyv::Serialize,
|
||||
rkyv::Deserialize,
|
||||
)]
|
||||
pub enum PddbBulkReadCode {
|
||||
/// Uninitialized value
|
||||
Uninit = 0,
|
||||
|
|
@ -433,18 +453,23 @@ pub struct BulkReadHeader {
|
|||
}
|
||||
impl Deref for BulkReadHeader {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
core::slice::from_raw_parts(self as *const BulkReadHeader as *const u8, core::mem::size_of::<BulkReadHeader>())
|
||||
as &[u8]
|
||||
core::slice::from_raw_parts(
|
||||
self as *const BulkReadHeader as *const u8,
|
||||
core::mem::size_of::<BulkReadHeader>(),
|
||||
) as &[u8]
|
||||
}
|
||||
}
|
||||
}
|
||||
impl DerefMut for BulkReadHeader {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
core::slice::from_raw_parts_mut(self as *mut BulkReadHeader as *mut u8, core::mem::size_of::<BulkReadHeader>())
|
||||
as &mut [u8]
|
||||
core::slice::from_raw_parts_mut(
|
||||
self as *mut BulkReadHeader as *mut u8,
|
||||
core::mem::size_of::<BulkReadHeader>(),
|
||||
) as &mut [u8]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -452,13 +477,15 @@ impl DerefMut for BulkReadHeader {
|
|||
#[allow(dead_code)]
|
||||
/// Ensure that the `PddbBuf` struct is exactly one page big
|
||||
const fn _assert_pddbbuf_is_4096_bytes() {
|
||||
unsafe { core::mem::transmute::<_, PddbBuf>([0u8; 4096]); }
|
||||
unsafe {
|
||||
core::mem::transmute::<_, PddbBuf>([0u8; 4096]);
|
||||
}
|
||||
}
|
||||
|
||||
impl PddbBuf {
|
||||
pub(crate) fn from_slice_mut(slice: &mut [u8]) -> &mut PddbBuf {
|
||||
// this transforms the slice [u8] into a PddbBuf ref.
|
||||
unsafe {core::mem::transmute::<*mut u8, &mut PddbBuf>(slice.as_mut_ptr()) }
|
||||
unsafe { core::mem::transmute::<*mut u8, &mut PddbBuf>(slice.as_mut_ptr()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -497,8 +524,8 @@ pub struct PddbKeyAttrIpc {
|
|||
pub len: u64,
|
||||
pub reserved: u64,
|
||||
pub age: u64,
|
||||
pub dict: xous_ipc::String::<DICT_NAME_LEN>,
|
||||
pub basis: xous_ipc::String::<BASIS_NAME_LEN>,
|
||||
pub dict: xous_ipc::String<DICT_NAME_LEN>,
|
||||
pub basis: xous_ipc::String<BASIS_NAME_LEN>,
|
||||
pub flags: u32,
|
||||
pub index: u32,
|
||||
pub token: ApiToken,
|
||||
|
|
@ -518,6 +545,7 @@ impl PddbKeyAttrIpc {
|
|||
code: PddbRequestCode::Uninit,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn to_attributes(&self) -> KeyAttributes {
|
||||
KeyAttributes {
|
||||
|
|
@ -530,6 +558,7 @@ impl PddbKeyAttrIpc {
|
|||
index: NonZeroU32::new(self.index).unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_attributes(attr: KeyAttributes, token: ApiToken) -> PddbKeyAttrIpc {
|
||||
PddbKeyAttrIpc {
|
||||
len: attr.len as u64,
|
||||
|
|
@ -550,7 +579,7 @@ impl PddbKeyAttrIpc {
|
|||
#[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
|
||||
pub struct PddbDangerousDebug {
|
||||
pub request: DebugRequest,
|
||||
pub dump_name: xous_ipc::String::<128>,
|
||||
pub dump_name: xous_ipc::String<128>,
|
||||
}
|
||||
#[cfg(not(target_os = "xous"))]
|
||||
#[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
|
||||
|
|
@ -570,6 +599,9 @@ mod tests {
|
|||
}
|
||||
#[test]
|
||||
fn test_pddb_len() {
|
||||
assert!(PDDB_A_LEN <= xous::PDDB_LEN as usize, "PDDB_A_LEN is larger than the maximum extents available in the hardware");
|
||||
assert!(
|
||||
PDDB_A_LEN <= xous::PDDB_LEN as usize,
|
||||
"PDDB_A_LEN is larger than the maximum extents available in the hardware"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@
|
|||
// As of now, the current version is 0.7.x and there isn't a timeline yet for 0.8.
|
||||
|
||||
#![allow(dead_code)]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
#[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
|
||||
pub enum BasisRetentionPolicy {
|
||||
Persist,
|
||||
ClearAfterSleeps(u32),
|
||||
|
|
@ -51,11 +50,10 @@ pub enum PddbRekeyOp {
|
|||
/// at this current time).
|
||||
ChangePass(xous_ipc::String<BASIS_NAME_LEN>),
|
||||
*/
|
||||
|
||||
/// Return codes
|
||||
Success,
|
||||
AuthFail,
|
||||
UserAbort,
|
||||
VerifyFail,
|
||||
InternalError,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,5 +27,5 @@ mod hosted;
|
|||
#[cfg(not(target_os = "xous"))]
|
||||
pub(crate) use hosted::*;
|
||||
|
||||
#[cfg(feature="migration1")]
|
||||
#[cfg(feature = "migration1")]
|
||||
mod migration1to2;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
// this code is based on https://github.com/Keats/rust-bcrypt
|
||||
// the original crate is not used directly because the base64 wrappers cause the crate
|
||||
// to be incompatible with a no-std environment. We are storing binary data directly
|
||||
|
|
@ -30,7 +29,11 @@ pub fn bcrypt(cost: u32, salt: &[u8], pw: &str, output: &mut [u8]) {
|
|||
assert!(output.len() == 24);
|
||||
|
||||
let pw_len = if pw.len() > crate::api::PASSWORD_LEN {
|
||||
log::warn!("password of length {} is truncated to {} bytes [reason: bcrypt limitation]", pw.len(), crate::api::PASSWORD_LEN);
|
||||
log::warn!(
|
||||
"password of length {} is truncated to {} bytes [reason: bcrypt limitation]",
|
||||
pw.len(),
|
||||
crate::api::PASSWORD_LEN
|
||||
);
|
||||
crate::api::PASSWORD_LEN
|
||||
} else {
|
||||
pw.len() + 1
|
||||
|
|
@ -47,19 +50,19 @@ pub fn bcrypt(cost: u32, salt: &[u8], pw: &str, output: &mut [u8]) {
|
|||
let state = setup(cost, salt, &plaintext_copy[..pw_len]);
|
||||
|
||||
// erase the plaintext copy as soon as we're done with it
|
||||
// an unsafe method is used because the compiler will correctly reason that plaintext_copy goes out of scope
|
||||
// and these writes are never read, and therefore they may be optimized out.
|
||||
// an unsafe method is used because the compiler will correctly reason that plaintext_copy goes out of
|
||||
// scope and these writes are never read, and therefore they may be optimized out.
|
||||
let pt_ptr = plaintext_copy.as_mut_ptr();
|
||||
for i in 0..plaintext_copy.len() {
|
||||
unsafe{pt_ptr.add(i).write_volatile(core::mem::zeroed());}
|
||||
unsafe {
|
||||
pt_ptr.add(i).write_volatile(core::mem::zeroed());
|
||||
}
|
||||
}
|
||||
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
|
||||
// OrpheanBeholderScryDoubt
|
||||
#[allow(clippy::unreadable_literal)]
|
||||
let mut ctext = [
|
||||
0x4f727068, 0x65616e42, 0x65686f6c, 0x64657253, 0x63727944, 0x6f756274,
|
||||
];
|
||||
let mut ctext = [0x4f727068, 0x65616e42, 0x65686f6c, 0x64657253, 0x63727944, 0x6f756274];
|
||||
for i in 0..3 {
|
||||
let i: usize = i * 2;
|
||||
for _ in 0..64 {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,10 +1,11 @@
|
|||
use core::ops::{Deref, DerefMut};
|
||||
use core::convert::TryInto;
|
||||
use core::mem::size_of;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
|
||||
use aes_gcm_siv::{Nonce, Tag};
|
||||
|
||||
use super::PAGE_SIZE;
|
||||
use crate::*;
|
||||
use core::mem::size_of;
|
||||
use aes_gcm_siv::{Nonce, Tag};
|
||||
|
||||
/// Each free_pool entry takes about 4 bytes, so give-or-take we have about 1000 free_pool
|
||||
/// entries per page of storage for the free_pool, or 4k * 1000 ~ 4MiB per page, when PhysAddr is a u32
|
||||
|
|
@ -34,14 +35,12 @@ impl From<u8> for SpaceState {
|
|||
}
|
||||
}
|
||||
impl From<SpaceState> for u8 {
|
||||
fn from(arg: SpaceState) -> Self {
|
||||
arg as u8
|
||||
}
|
||||
fn from(arg: SpaceState) -> Self { arg as u8 }
|
||||
}
|
||||
|
||||
pub(crate) const FASTSPACE_FREE_POOL_LEN: usize =
|
||||
((PAGE_SIZE * FASTSPACE_PAGES) - (size_of::<Nonce>() + size_of::<Tag>()))
|
||||
/ core::mem::size_of::<PhysPage>();
|
||||
pub(crate) const FASTSPACE_FREE_POOL_LEN: usize = ((PAGE_SIZE * FASTSPACE_PAGES)
|
||||
- (size_of::<Nonce>() + size_of::<Tag>()))
|
||||
/ core::mem::size_of::<PhysPage>();
|
||||
/// FastSpace tracks a limited set of physical pages
|
||||
/// An optimal implementation of this would fill whole pages with the free_pool array.
|
||||
/// This record is meant to be updated rarely, and atomically, in a make-before-break fashion:
|
||||
|
|
@ -60,17 +59,20 @@ pub(crate) const FASTSPACE_FREE_POOL_LEN: usize =
|
|||
/// The "rare" property is important especially as the disk size scales up; if we wanted to keep
|
||||
/// 100MiB of "fast space" on hand, this structure would span 25 pages.
|
||||
#[repr(C)]
|
||||
pub (crate) struct FastSpace {
|
||||
pub(crate) struct FastSpace {
|
||||
/// Not sure if there is a "better" way to compute things, but we want the number of entries in the
|
||||
/// free_pool array to "round out" the FastSpace record to be equal to exactly one page
|
||||
pub(crate) free_pool: [PhysPage; FASTSPACE_FREE_POOL_LEN],
|
||||
}
|
||||
impl Deref for FastSpace {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
core::slice::from_raw_parts(self as *const FastSpace as *const u8, core::mem::size_of::<FastSpace>())
|
||||
as &[u8]
|
||||
core::slice::from_raw_parts(
|
||||
self as *const FastSpace as *const u8,
|
||||
core::mem::size_of::<FastSpace>(),
|
||||
) as &[u8]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -84,10 +86,11 @@ pub(crate) struct FastSpaceInFlash {
|
|||
p_tag: [u8; size_of::<Tag>()],
|
||||
}
|
||||
|
||||
/// a 128-bit record that stores an encrypted update to the FastSpace pool, facilitating the "rarely" update property of the structure.
|
||||
/// a 128-bit record that stores an encrypted update to the FastSpace pool, facilitating the "rarely" update
|
||||
/// property of the structure.
|
||||
#[repr(C, packed)]
|
||||
#[cfg(not(feature = "u64_pa"))]
|
||||
pub (crate) struct SpaceUpdate {
|
||||
pub(crate) struct SpaceUpdate {
|
||||
nonce: u64,
|
||||
page_number: PhysPage,
|
||||
// this checksum is "weak" but we are protecting against two scenarios:
|
||||
|
|
@ -112,6 +115,7 @@ impl SpaceUpdate {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(nonce: u64, page_number: PhysPage) -> Self {
|
||||
let mut hashbuf: [u8; 12] = [0; 12];
|
||||
for (&src, dst) in nonce.to_le_bytes().iter().zip(hashbuf[..8].iter_mut()) {
|
||||
|
|
@ -121,16 +125,12 @@ impl SpaceUpdate {
|
|||
*dst = src;
|
||||
}
|
||||
let computed_sum = murmur3_32(&hashbuf[..12], u32::from_be_bytes(hashbuf[4..8].try_into().unwrap()));
|
||||
SpaceUpdate {
|
||||
nonce,
|
||||
page_number,
|
||||
checksum: computed_sum.to_le_bytes(),
|
||||
}
|
||||
SpaceUpdate { nonce, page_number, checksum: computed_sum.to_le_bytes() }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "u64_pa")]
|
||||
pub (crate) struct SpaceUpdate {
|
||||
pub(crate) struct SpaceUpdate {
|
||||
nonce: u64,
|
||||
page_number: PhysPage,
|
||||
// consider: using the top 12 bits of the PhysAddr as a checksum
|
||||
|
|
@ -138,18 +138,23 @@ pub (crate) struct SpaceUpdate {
|
|||
|
||||
impl Deref for SpaceUpdate {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
core::slice::from_raw_parts(self as *const SpaceUpdate as *const u8, core::mem::size_of::<SpaceUpdate>())
|
||||
as &[u8]
|
||||
core::slice::from_raw_parts(
|
||||
self as *const SpaceUpdate as *const u8,
|
||||
core::mem::size_of::<SpaceUpdate>(),
|
||||
) as &[u8]
|
||||
}
|
||||
}
|
||||
}
|
||||
impl DerefMut for SpaceUpdate {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
core::slice::from_raw_parts_mut(self as *mut SpaceUpdate as *mut u8, core::mem::size_of::<SpaceUpdate>())
|
||||
as &mut [u8]
|
||||
core::slice::from_raw_parts_mut(
|
||||
self as *mut SpaceUpdate as *mut u8,
|
||||
core::mem::size_of::<SpaceUpdate>(),
|
||||
) as &mut [u8]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -159,6 +164,9 @@ mod tests {
|
|||
use super::*;
|
||||
#[test]
|
||||
fn test_fast_space_size() {
|
||||
assert!(core::mem::size_of::<FastSpaceInFlash>() & (PAGE_SIZE - 1) == 0, "FastSpaceInFlash is not exactly a multiple of one page in size");
|
||||
assert!(
|
||||
core::mem::size_of::<FastSpaceInFlash>() & (PAGE_SIZE - 1) == 0,
|
||||
"FastSpaceInFlash is not exactly a multiple of one page in size"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
#![allow(dead_code)]
|
||||
use crate::api::*;
|
||||
|
||||
use std::sync::Once;
|
||||
use std::mem::MaybeUninit;
|
||||
|
||||
use std::fs::File;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::prelude::*;
|
||||
use std::io::SeekFrom;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::sync::Once;
|
||||
|
||||
use crate::api::*;
|
||||
|
||||
// This is considered bad practice for Rust to use a global singleton.
|
||||
// However, this hack puts the burden of emulation on the emulator, while
|
||||
|
|
@ -17,7 +16,7 @@ use std::io::SeekFrom;
|
|||
//
|
||||
// Note that this is a concurrently accessed, unsafe, unchecked vector.
|
||||
struct FlashSingleton {
|
||||
memory: Vec::<u8>,
|
||||
memory: Vec<u8>,
|
||||
disk: File,
|
||||
}
|
||||
|
||||
|
|
@ -28,11 +27,11 @@ fn flashmem() -> &'static mut FlashSingleton {
|
|||
unsafe {
|
||||
ONCE.call_once(|| {
|
||||
let mut disk = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.open("../tools/pddb-images/hosted.bin")
|
||||
.expect("Can't open a PDDB image file for writing");
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.open("../tools/pddb-images/hosted.bin")
|
||||
.expect("Can't open a PDDB image file for writing");
|
||||
|
||||
let mut memory = Vec::<u8>::with_capacity(PDDB_A_LEN);
|
||||
if disk.metadata().unwrap().len() == 0 {
|
||||
|
|
@ -44,7 +43,11 @@ fn flashmem() -> &'static mut FlashSingleton {
|
|||
match disk.read_to_end(&mut memory) {
|
||||
Ok(bytes_read) => {
|
||||
if bytes_read != PDDB_A_LEN {
|
||||
log::warn!("PDDB disk image is of an incorrect size: got {}, expected {}", bytes_read, PDDB_A_LEN);
|
||||
log::warn!(
|
||||
"PDDB disk image is of an incorrect size: got {}, expected {}",
|
||||
bytes_read,
|
||||
PDDB_A_LEN
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
|
@ -53,10 +56,7 @@ fn flashmem() -> &'static mut FlashSingleton {
|
|||
}
|
||||
}
|
||||
|
||||
let flashmem = FlashSingleton {
|
||||
memory,
|
||||
disk,
|
||||
};
|
||||
let flashmem = FlashSingleton { memory, disk };
|
||||
SINGLETON.write(flashmem);
|
||||
});
|
||||
SINGLETON.assume_init_mut()
|
||||
|
|
@ -71,28 +71,26 @@ pub struct KeyExport {
|
|||
/// page table key
|
||||
pub pt_key: [u8; 32],
|
||||
}
|
||||
pub struct EmuStorage {
|
||||
}
|
||||
pub struct EmuStorage {}
|
||||
impl EmuStorage {
|
||||
pub fn new() -> Self {
|
||||
EmuStorage {
|
||||
}
|
||||
}
|
||||
pub fn new() -> Self { EmuStorage {} }
|
||||
|
||||
pub unsafe fn as_slice<T>(&self) -> &[T] {
|
||||
core::slice::from_raw_parts(
|
||||
flashmem().memory.as_ptr() as *const T,
|
||||
flashmem().memory.len() / core::mem::size_of::<T>(),
|
||||
)
|
||||
}
|
||||
pub unsafe fn as_mut_slice(&mut self) -> &mut [u8] {
|
||||
flashmem().memory.as_mut_slice()
|
||||
core::slice::from_raw_parts(
|
||||
flashmem().memory.as_ptr() as *const T,
|
||||
flashmem().memory.len() / core::mem::size_of::<T>(),
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe fn as_mut_slice(&mut self) -> &mut [u8] { flashmem().memory.as_mut_slice() }
|
||||
|
||||
/// used to reset the storage for repeated test case generation
|
||||
pub fn reset(&mut self) {
|
||||
for b in flashmem().memory.as_mut_slice() {
|
||||
*b = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dump_fs(&self, name: &Option<String>) {
|
||||
let defaultname = String::from("pddb");
|
||||
let rootname = name.as_ref().unwrap_or(&defaultname);
|
||||
|
|
@ -100,6 +98,7 @@ impl EmuStorage {
|
|||
f.write_all(flashmem().memory.as_slice()).unwrap();
|
||||
f.flush().unwrap();
|
||||
}
|
||||
|
||||
pub fn dump_keys(&self, known_keys: &[KeyExport], name: &Option<String>) {
|
||||
let defaultname = String::from("pddb");
|
||||
let rootname = name.as_ref().unwrap_or(&defaultname);
|
||||
|
|
@ -114,26 +113,34 @@ impl EmuStorage {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct HostedSpinor {
|
||||
}
|
||||
pub struct HostedSpinor {}
|
||||
impl HostedSpinor {
|
||||
pub fn new() -> Self {
|
||||
HostedSpinor {
|
||||
}
|
||||
}
|
||||
pub fn patch(&self, _region: &[u8], _region_base: u32, data: &[u8], offset: u32) -> Result<(), xous::Error> {
|
||||
pub fn new() -> Self { HostedSpinor {} }
|
||||
|
||||
pub fn patch(
|
||||
&self,
|
||||
_region: &[u8],
|
||||
_region_base: u32,
|
||||
data: &[u8],
|
||||
offset: u32,
|
||||
) -> Result<(), xous::Error> {
|
||||
// println!("patch at {:x}+{}", offset, data.len());
|
||||
for (&src, dst) in data.iter().zip(
|
||||
flashmem().memory.as_mut_slice()[offset as usize..offset as usize + data.len()].iter_mut()
|
||||
) {
|
||||
for (&src, dst) in data
|
||||
.iter()
|
||||
.zip(flashmem().memory.as_mut_slice()[offset as usize..offset as usize + data.len()].iter_mut())
|
||||
{
|
||||
*dst = src;
|
||||
}
|
||||
flashmem().disk.seek(SeekFrom::Start(offset as u64)).expect("couldn't seek PDDB");
|
||||
flashmem().disk.write(data).expect("couldn't write PDDB");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn bulk_erase(&self, start: u32, len: u32) -> Result<(), xous::Error> {
|
||||
for b in flashmem().memory.as_mut_slice()[(start - xous::PDDB_LOC) as usize .. (start - xous::PDDB_LOC + len) as usize].iter_mut() {
|
||||
for b in flashmem().memory.as_mut_slice()
|
||||
[(start - xous::PDDB_LOC) as usize..(start - xous::PDDB_LOC + len) as usize]
|
||||
.iter_mut()
|
||||
{
|
||||
*b = 0xFF;
|
||||
}
|
||||
flashmem().disk.seek(SeekFrom::Start(start as u64)).expect("couldn't seek PDDB");
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,10 +1,10 @@
|
|||
use crate::api::*;
|
||||
use super::*;
|
||||
|
||||
use std::num::NonZeroU32;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use std::cmp::Ordering;
|
||||
use std::io::{Result, Error, ErrorKind};
|
||||
use std::io::{Error, ErrorKind, Result};
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use super::*;
|
||||
use crate::api::*;
|
||||
|
||||
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
||||
#[repr(C, align(8))]
|
||||
|
|
@ -30,12 +30,7 @@ impl KeyName {
|
|||
}
|
||||
}
|
||||
impl Default for KeyName {
|
||||
fn default() -> KeyName {
|
||||
KeyName {
|
||||
len: 0,
|
||||
data: [0; KEY_NAME_LEN - 1]
|
||||
}
|
||||
}
|
||||
fn default() -> KeyName { KeyName { len: 0, data: [0; KEY_NAME_LEN - 1] } }
|
||||
}
|
||||
|
||||
/// On-disk representation of the Key. Note that the storage on disk is mis-aligned relative
|
||||
|
|
@ -58,74 +53,79 @@ pub(crate) struct KeyDescriptor {
|
|||
}
|
||||
impl Default for KeyDescriptor {
|
||||
fn default() -> Self {
|
||||
KeyDescriptor {
|
||||
start: 0,
|
||||
len: 0,
|
||||
reserved: 0,
|
||||
flags: KeyFlags(0),
|
||||
age: 0,
|
||||
name: KeyName::default(),
|
||||
}
|
||||
KeyDescriptor { start: 0, len: 0, reserved: 0, flags: KeyFlags(0), age: 0, name: KeyName::default() }
|
||||
}
|
||||
}
|
||||
impl Deref for KeyDescriptor {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
core::slice::from_raw_parts(self as *const KeyDescriptor as *const u8, core::mem::size_of::<KeyDescriptor>())
|
||||
as &[u8]
|
||||
core::slice::from_raw_parts(
|
||||
self as *const KeyDescriptor as *const u8,
|
||||
core::mem::size_of::<KeyDescriptor>(),
|
||||
) as &[u8]
|
||||
}
|
||||
}
|
||||
}
|
||||
impl DerefMut for KeyDescriptor {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
core::slice::from_raw_parts_mut(self as *mut KeyDescriptor as *mut u8, core::mem::size_of::<KeyDescriptor>())
|
||||
as &mut [u8]
|
||||
core::slice::from_raw_parts_mut(
|
||||
self as *mut KeyDescriptor as *mut u8,
|
||||
core::mem::size_of::<KeyDescriptor>(),
|
||||
) as &mut [u8]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// In-RAM representation of a key. This file defines the storage for the KeyCacheEntry; most of the structure
|
||||
/// manipulations happen inside `dictionary.rs`, in part because to locate a Key in absolute memory space you need
|
||||
/// to know what Dictionary it comes from. This is a point to consider for a refactor: if we pull some info about
|
||||
/// the containing Dictionary into the key, we could associate more methods with the data structure. However, this
|
||||
/// means duplicating the dictionary index, a field that can then get out of sync.
|
||||
/// manipulations happen inside `dictionary.rs`, in part because to locate a Key in absolute memory space you
|
||||
/// need to know what Dictionary it comes from. This is a point to consider for a refactor: if we pull some
|
||||
/// info about the containing Dictionary into the key, we could associate more methods with the data
|
||||
/// structure. However, this means duplicating the dictionary index, a field that can then get out of sync.
|
||||
pub(crate) struct KeyCacheEntry {
|
||||
pub(crate) start: u64,
|
||||
pub(crate) len: u64,
|
||||
pub(crate) reserved: u64,
|
||||
pub(crate) flags: KeyFlags,
|
||||
pub(crate) age: u32,
|
||||
/// this is an ephemeral time since boot, not commited to disk, used only for deciding which entries to evict
|
||||
/// this is an ephemeral time since boot, not commited to disk, used only for deciding which entries to
|
||||
/// evict
|
||||
pub(crate) atime: u64,
|
||||
/// the current on-disk index of the KeyCacheEntry item, enumerated as "0" being the Dict descriptor and
|
||||
/// "1" being the first valid key. This is used to find the location of the key's metadata as stored on disk;
|
||||
/// it has nothing to do with where the data itself is stored (that's derived from `start`).
|
||||
/// "1" being the first valid key. This is used to find the location of the key's metadata as stored on
|
||||
/// disk; it has nothing to do with where the data itself is stored (that's derived from `start`).
|
||||
pub(crate) descriptor_index: NonZeroU32,
|
||||
/// indicates if the descriptor cache entry is currently synchronized with what's on disk. Does not imply anything about the data,
|
||||
/// but if the `data` field is None then there is nothing to in cache to be dirtied.
|
||||
/// indicates if the descriptor cache entry is currently synchronized with what's on disk. Does not imply
|
||||
/// anything about the data, but if the `data` field is None then there is nothing to in cache to be
|
||||
/// dirtied.
|
||||
pub(crate) clean: bool,
|
||||
/// if Some, contains the keys data contents. if None, you must refer to the disk contents to retrieve it.
|
||||
/// Current rule: "small" keys always have their data "hot"; large keys may often not keep their data around.
|
||||
/// if Some, contains the keys data contents. if None, you must refer to the disk contents to retrieve
|
||||
/// it. Current rule: "small" keys always have their data "hot"; large keys may often not keep their
|
||||
/// data around.
|
||||
pub(crate) data: Option<KeyCacheData>,
|
||||
}
|
||||
impl KeyCacheEntry {
|
||||
/// Given a base offset of the dictionary containing the key, compute the starting VirtAddr of the key itself.
|
||||
/// Given a base offset of the dictionary containing the key, compute the starting VirtAddr of the key
|
||||
/// itself.
|
||||
pub(crate) fn descriptor_vaddr(&self, dict_offset: VirtAddr) -> VirtAddr {
|
||||
VirtAddr::new(dict_offset.get() + ((self.descriptor_index.get() as u64) * DK_STRIDE as u64)).unwrap()
|
||||
}
|
||||
|
||||
/// Computes the modular position of the KeyDescriptor within a vpage.
|
||||
#[allow(dead_code)] // I feel like we should have been calling this /somewhere/ at some point in time, but I probably just re-wrote the math long-hand.
|
||||
pub(crate) fn descriptor_modulus(&self) -> usize {
|
||||
(self.descriptor_index.get() as usize) % (VPAGE_SIZE / DK_STRIDE)
|
||||
}
|
||||
|
||||
/// Computes the vpage offset as measured from the start of the dictionary storage region
|
||||
pub(crate) fn descriptor_vpage_num(&self) -> usize {
|
||||
(self.descriptor_index.get() as usize) / DK_PER_VPAGE
|
||||
}
|
||||
|
||||
/// returns the list of large-pool virtual pages belonging to this entry, if any.
|
||||
pub(crate) fn large_pool_vpages(&self) -> Vec::<VirtAddr> {
|
||||
pub(crate) fn large_pool_vpages(&self) -> Vec<VirtAddr> {
|
||||
let mut vpages = Vec::<VirtAddr>::new();
|
||||
if self.start >= LARGE_POOL_START {
|
||||
for vbase in (self.start..self.start + self.reserved).step_by(VPAGE_SIZE) {
|
||||
|
|
@ -134,6 +134,7 @@ impl KeyCacheEntry {
|
|||
}
|
||||
vpages
|
||||
}
|
||||
|
||||
/// returns a rough measure of the amount of data consumed by a given entry. It's not meant to
|
||||
/// be absolutely accurate, but it should give an accurate impression of the relative size of
|
||||
/// different cache entries. This metric is used to help decide which entries to discard.
|
||||
|
|
@ -143,15 +144,17 @@ impl KeyCacheEntry {
|
|||
Some(kcd) => match kcd {
|
||||
KeyCacheData::Small(ksd) => ksd.data.len(),
|
||||
KeyCacheData::Large(kld) => kld.data.len(),
|
||||
}
|
||||
},
|
||||
};
|
||||
core::mem::size_of::<KeyCacheEntry>() + data_size
|
||||
}
|
||||
|
||||
pub(crate) fn atime(&self) -> u64 { self.atime }
|
||||
|
||||
pub(crate) fn set_atime(&mut self, atime: u64) { self.atime = atime; }
|
||||
}
|
||||
|
||||
pub (crate) enum KeyCacheData {
|
||||
pub(crate) enum KeyCacheData {
|
||||
Small(KeySmallData),
|
||||
// the "Medium" type has a region reserved for it, but we haven't coded a handler for it.
|
||||
#[allow(dead_code)] // Large data caching isn't implemented, so of course, we don't ever create this type
|
||||
|
|
@ -160,7 +163,7 @@ pub (crate) enum KeyCacheData {
|
|||
/// Small data is optimized for low overhead, and always represent a complete copy of the data.
|
||||
pub(crate) struct KeySmallData {
|
||||
pub clean: bool,
|
||||
pub(crate) data: Vec::<u8>,
|
||||
pub(crate) data: Vec<u8>,
|
||||
}
|
||||
/// This can hold just a portion of a large key's data. For now, we now essentially manually
|
||||
/// encode a sub-slice in parts, but, later on we could get more clever and start to cache
|
||||
|
|
@ -169,17 +172,18 @@ pub(crate) struct KeySmallData {
|
|||
pub(crate) struct KeyLargeData {
|
||||
pub clean: bool,
|
||||
pub(crate) start: u64,
|
||||
pub(crate) data: Vec::<u8>,
|
||||
pub(crate) data: Vec<u8>,
|
||||
}
|
||||
|
||||
/// A storage pool for data that is strictly smaller than one VPAGE. These element are serialized
|
||||
/// and stored inside the "small data pool" area.
|
||||
pub(crate) struct KeySmallPool {
|
||||
// location of data within the Small memory region. Index is in units of SMALL_CAPACITY. (this should be encoded in the vector position)
|
||||
//pub(crate) index: u32,
|
||||
// location of data within the Small memory region. Index is in units of SMALL_CAPACITY. (this should be
|
||||
// encoded in the vector position) pub(crate) index: u32,
|
||||
/// list of data actually stored within the pool - resolve against `keys` HashMap.
|
||||
pub(crate) contents: Vec::<String>,
|
||||
/// keeps track of the available space within the pool, avoiding an expensive lookup every time we want to query the available space
|
||||
pub(crate) contents: Vec<String>,
|
||||
/// keeps track of the available space within the pool, avoiding an expensive lookup every time we want
|
||||
/// to query the available space
|
||||
pub(crate) avail: u16,
|
||||
/// if false, contents are modified and need syncing to disk
|
||||
pub(crate) clean: bool,
|
||||
|
|
@ -204,17 +208,11 @@ pub(crate) struct KeySmallPoolOrd {
|
|||
}
|
||||
// only compare based on the amount of data used
|
||||
impl Ord for KeySmallPoolOrd {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.avail.cmp(&other.avail)
|
||||
}
|
||||
fn cmp(&self, other: &Self) -> Ordering { self.avail.cmp(&other.avail) }
|
||||
}
|
||||
impl PartialOrd for KeySmallPoolOrd {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
|
||||
}
|
||||
impl PartialEq for KeySmallPoolOrd {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.avail == other.avail
|
||||
}
|
||||
fn eq(&self, other: &Self) -> bool { self.avail == other.avail }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use crate::*;
|
||||
use core::ops::Deref;
|
||||
use core::mem::size_of;
|
||||
use core::ops::Deref;
|
||||
|
||||
use crate::*;
|
||||
|
||||
pub(crate) const SCD_VERSION_MIGRATION1: u32 = 1;
|
||||
|
||||
|
|
@ -24,15 +25,18 @@ impl StaticCryptoDataV1 {
|
|||
}
|
||||
impl Deref for StaticCryptoDataV1 {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
core::slice::from_raw_parts(self as *const StaticCryptoDataV1 as *const u8, size_of::<StaticCryptoDataV1>())
|
||||
as &[u8]
|
||||
core::slice::from_raw_parts(
|
||||
self as *const StaticCryptoDataV1 as *const u8,
|
||||
size_of::<StaticCryptoDataV1>(),
|
||||
) as &[u8]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn data_aad_v1(pddb_os: &PddbOs, name: &str) -> Vec::<u8> {
|
||||
pub(crate) fn data_aad_v1(pddb_os: &PddbOs, name: &str) -> Vec<u8> {
|
||||
let mut aad = Vec::<u8>::new();
|
||||
aad.extend_from_slice(&name.as_bytes());
|
||||
let (old_version, _new_version) = PDDB_MIGRATE_1;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
// option. All files in the project carrying such notice may not be copied,
|
||||
// modified, or distributed except according to those terms.
|
||||
|
||||
|
||||
// This murmur3 code was vendored in on April 28, 2021. We choose to vendor the code for this simple
|
||||
// non-cryptographic hash in to reduce the number of crate dependencies in the build system. See
|
||||
// https://github.com/betrusted-io/xous-core/issues/54 for more details on why.
|
||||
|
|
@ -55,7 +54,6 @@ fn calc_k(k: u32) -> u32 {
|
|||
k.wrapping_mul(C1).rotate_left(R1).wrapping_mul(C2)
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
@ -75,18 +73,11 @@ mod tests {
|
|||
slice: &[0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38], // "12345678",
|
||||
hash_32: 0x91b313ce,
|
||||
},
|
||||
Result {
|
||||
slice: &[],
|
||||
hash_32: 0,
|
||||
},
|
||||
Result { slice: &[], hash_32: 0 },
|
||||
];
|
||||
|
||||
for test in &tests {
|
||||
assert_eq!(
|
||||
murmur3_32(test.slice, 0),
|
||||
test.hash_32,
|
||||
"Failed on slice {:x?}", test.slice
|
||||
);
|
||||
assert_eq!(murmur3_32(test.slice, 0), test.hash_32, "Failed on slice {:x?}", test.slice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
use super::{PAGE_SIZE, TrngPool, VirtAddr, murmur3_32, VPAGE_SIZE};
|
||||
use core::mem::size_of;
|
||||
use aes_gcm_siv::{Nonce, Tag};
|
||||
use std::rc::Rc;
|
||||
use core::cell::RefCell;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use core::convert::TryInto;
|
||||
use core::mem::size_of;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use std::rc::Rc;
|
||||
|
||||
use aes_gcm_siv::{Nonce, Tag};
|
||||
use bitflags::bitflags;
|
||||
|
||||
use super::{murmur3_32, TrngPool, VirtAddr, PAGE_SIZE, VPAGE_SIZE};
|
||||
|
||||
bitflags! {
|
||||
/// flags used by the page table
|
||||
pub struct PtFlags: u8 {
|
||||
|
|
@ -23,7 +24,7 @@ bitflags! {
|
|||
}
|
||||
}
|
||||
impl Default for PtFlags {
|
||||
fn default() -> PtFlags {PtFlags::INVALID}
|
||||
fn default() -> PtFlags { PtFlags::INVALID }
|
||||
}
|
||||
|
||||
/// A Page Table Entry. Must be equal in length to one AES block size (128 bits).
|
||||
|
|
@ -51,8 +52,8 @@ pub(crate) struct Pte {
|
|||
flags: PtFlags,
|
||||
/// 32-bit strength of a nonce, but can be varied
|
||||
nonce: [u8; 4],
|
||||
/// 32-bit "weak" checksum, used only for quick scans of the PTE to determine a coarse "in" or "out" classifier
|
||||
/// checksum is computed on all of the bits prior, so checksum(pddb_addr, flags, nonce)
|
||||
/// 32-bit "weak" checksum, used only for quick scans of the PTE to determine a coarse "in" or "out"
|
||||
/// classifier checksum is computed on all of the bits prior, so checksum(pddb_addr, flags, nonce)
|
||||
checksum: [u8; 4],
|
||||
}
|
||||
impl Pte {
|
||||
|
|
@ -70,22 +71,26 @@ impl Pte {
|
|||
|
||||
pte
|
||||
}
|
||||
|
||||
pub fn vaddr(&self) -> VirtAddr {
|
||||
let mut full_addr = [0u8; 8];
|
||||
// LSB encoded, so this loop deposits the partial pddb_addr in the LSBs, and the MSBs are correctly 0 from above initializer
|
||||
// LSB encoded, so this loop deposits the partial pddb_addr in the LSBs, and the MSBs are correctly 0
|
||||
// from above initializer
|
||||
for (&src, dst) in self.pddb_addr.iter().zip(full_addr.iter_mut()) {
|
||||
*dst = src;
|
||||
}
|
||||
VirtAddr::new(u64::from_le_bytes(full_addr) * VPAGE_SIZE as u64).unwrap()
|
||||
}
|
||||
|
||||
/// V1 databases stored the virtual address as a full address, instead of as a page number, which means
|
||||
/// the overall size of our database was about 4000x smaller than we had thought. This was fixed in v2,
|
||||
/// but this getter is required to migrate from v1.
|
||||
/// This allows us to retrieve the old address format for the first phase of migration.
|
||||
#[cfg(feature="migration1")]
|
||||
#[cfg(feature = "migration1")]
|
||||
pub fn vaddr_v1(&self) -> VirtAddr {
|
||||
let mut full_addr = [0u8; 8];
|
||||
// LSB encoded, so this loop deposits the partial pddb_addr in the LSBs, and the MSBs are correctly 0 from above initializer
|
||||
// LSB encoded, so this loop deposits the partial pddb_addr in the LSBs, and the MSBs are correctly 0
|
||||
// from above initializer
|
||||
for (&src, dst) in self.pddb_addr.iter().zip(full_addr.iter_mut()) {
|
||||
*dst = src;
|
||||
}
|
||||
|
|
@ -93,9 +98,8 @@ impl Pte {
|
|||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn flags(&self) -> PtFlags {
|
||||
self.flags
|
||||
}
|
||||
pub fn flags(&self) -> PtFlags { self.flags }
|
||||
|
||||
pub fn try_from_slice(slice: &[u8]) -> Option<Self> {
|
||||
if slice.len() == size_of::<Pte>() {
|
||||
let mut maybe_pt = Pte::default();
|
||||
|
|
@ -112,6 +116,7 @@ impl Pte {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Normally you should be using pt_patch_mapping(), which generates a new nonce every
|
||||
/// time the entry is patched. However, this function is provided for "bulk" operations
|
||||
/// such as migrations where we violate the abstractions to improve performance.
|
||||
|
|
@ -125,6 +130,7 @@ impl Pte {
|
|||
}
|
||||
impl Deref for Pte {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
core::slice::from_raw_parts(self as *const Pte as *const u8, core::mem::size_of::<Pte>())
|
||||
|
|
@ -165,6 +171,7 @@ pub(crate) struct EncryptedPage {
|
|||
journal_rev: [u8; 4],
|
||||
/// data is encrypted and holds the good stuff
|
||||
data: [u8; PAGE_SIZE - size_of::<Nonce>() - size_of::<Tag>() - size_of::<u32>()],
|
||||
/// tag is the authentication tag. If the page decrypts & authenticates, we know it's a valid data block for us.
|
||||
/// tag is the authentication tag. If the page decrypts & authenticates, we know it's a valid data block
|
||||
/// for us.
|
||||
p_tag: [u8; size_of::<Tag>()],
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
use core::mem::size_of;
|
||||
use aes_gcm_siv::Nonce;
|
||||
use std::convert::TryInto;
|
||||
use core::cell::RefCell;
|
||||
use core::mem::size_of;
|
||||
use std::convert::TryInto;
|
||||
|
||||
use aes_gcm_siv::Nonce;
|
||||
use rand_core::RngCore;
|
||||
|
||||
/// Crate-shared resource for TRNGs.
|
||||
pub(crate) struct TrngPool {
|
||||
trng: RefCell::<trng::Trng>,
|
||||
trng: RefCell<trng::Trng>,
|
||||
/// The PDDB eats a lot of entropy. Keep a local pool of entropy, so we're not wasting a lot of
|
||||
/// overhead passing messages to the TRNG hardware server.
|
||||
e_cache: RefCell::<Vec::<u8>>,
|
||||
e_cache: RefCell<Vec<u8>>,
|
||||
}
|
||||
impl TrngPool {
|
||||
pub fn new() -> Self {
|
||||
|
|
@ -17,11 +18,9 @@ impl TrngPool {
|
|||
let mut trng = trng::Trng::new(&xns).unwrap();
|
||||
let mut cache: [u8; 8192] = [0; 8192];
|
||||
trng.fill_bytes(&mut cache);
|
||||
TrngPool {
|
||||
trng: RefCell::new(trng),
|
||||
e_cache: RefCell::new(cache.to_vec())
|
||||
}
|
||||
TrngPool { trng: RefCell::new(trng), e_cache: RefCell::new(cache.to_vec()) }
|
||||
}
|
||||
|
||||
pub(crate) fn ensure_entropy(&self, amount: usize) {
|
||||
if self.e_cache.borrow().len() < amount {
|
||||
let mut cache: [u8; 8192] = [0; 8192];
|
||||
|
|
@ -29,37 +28,42 @@ impl TrngPool {
|
|||
self.e_cache.borrow_mut().extend_from_slice(&cache);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_u8(&self) -> u8 {
|
||||
self.ensure_entropy(1);
|
||||
self.e_cache.borrow_mut().pop().unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn get_u32(&self) -> u32 {
|
||||
self.ensure_entropy(4);
|
||||
let ret = u32::from_le_bytes(self.e_cache.borrow()[self.e_cache.borrow().len() - 4..].try_into().unwrap());
|
||||
let ret =
|
||||
u32::from_le_bytes(self.e_cache.borrow()[self.e_cache.borrow().len() - 4..].try_into().unwrap());
|
||||
let ecache_len = self.e_cache.borrow().len();
|
||||
self.e_cache.borrow_mut().truncate(ecache_len - 4);
|
||||
ret
|
||||
}
|
||||
|
||||
pub(crate) fn get_u64(&self) -> u64 {
|
||||
self.ensure_entropy(8);
|
||||
let ret = u64::from_le_bytes(self.e_cache.borrow()[self.e_cache.borrow().len() - 8..].try_into().unwrap());
|
||||
let ret =
|
||||
u64::from_le_bytes(self.e_cache.borrow()[self.e_cache.borrow().len() - 8..].try_into().unwrap());
|
||||
let ecache_len = self.e_cache.borrow().len();
|
||||
self.e_cache.borrow_mut().truncate(ecache_len - 8);
|
||||
ret
|
||||
}
|
||||
|
||||
pub(crate) fn get_slice(&self, bucket: &mut [u8]) {
|
||||
self.ensure_entropy(bucket.len());
|
||||
let drain_start = self.e_cache.borrow().len() - bucket.len();
|
||||
for (src, dst) in self.e_cache.borrow_mut().drain(
|
||||
drain_start..
|
||||
).zip(bucket.iter_mut()) {
|
||||
for (src, dst) in self.e_cache.borrow_mut().drain(drain_start..).zip(bucket.iter_mut()) {
|
||||
*dst = src;
|
||||
}
|
||||
}
|
||||
|
||||
/// generates a 96-bit nonce using the TRNG
|
||||
pub(crate) fn get_nonce(&self) -> [u8; size_of::<Nonce>()] {
|
||||
let mut nonce: [u8; size_of::<Nonce>()] = [0; size_of::<Nonce>()];
|
||||
self.get_slice(&mut nonce);
|
||||
nonce
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,20 @@
|
|||
use core::num::NonZeroU64;
|
||||
use core::ops::Add;
|
||||
use std::cmp::Ordering;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
use bitfield::bitfield;
|
||||
|
||||
use super::{PAGE_SIZE, VPAGE_SIZE};
|
||||
use crate::SpaceState;
|
||||
use bitfield::bitfield;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::cmp::Ordering;
|
||||
|
||||
/// for the life of me, I can't figure out how to query the AES crate to give me the length of a 256-bit key.
|
||||
/// I mean, we know what it is, it's well-defined and never changes. But it'd just be nice to you know,
|
||||
/// derive it from a const or something with symbolic meaning, but the KeySize Trait is buried in some sort
|
||||
/// of a NewBlock trait and I can't figure out how to access it. Looking at the example code on the AES crate
|
||||
/// on docs.rs, they just pull the number 16 out of their ass instead of referring to a trait.
|
||||
/// So, maybe that's just what you're supposed to do. ¯\_(ツ)_/¯ Oddly enough, a BLOCK_SIZE constant /is/ defined,
|
||||
/// but maybe that's because it's constant regardless of the key size so it's easy to do.
|
||||
/// So, maybe that's just what you're supposed to do. ¯\_(ツ)_/¯ Oddly enough, a BLOCK_SIZE constant /is/
|
||||
/// defined, but maybe that's because it's constant regardless of the key size so it's easy to do.
|
||||
pub(crate) const AES_KEYSIZE: usize = 32;
|
||||
|
||||
/// This has to be manually synchronized with the bit range of the `journal` field below. It doesn't look like
|
||||
|
|
@ -44,24 +46,16 @@ bitfield! {
|
|||
}
|
||||
// hashes should only key off of the page number, not the metadata
|
||||
impl Hash for PhysPage {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.page_number().hash(state);
|
||||
}
|
||||
fn hash<H: Hasher>(&self, state: &mut H) { self.page_number().hash(state); }
|
||||
}
|
||||
impl PartialEq for PhysPage {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.page_number() == other.page_number()
|
||||
}
|
||||
fn eq(&self, other: &Self) -> bool { self.page_number() == other.page_number() }
|
||||
}
|
||||
impl Ord for PhysPage {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.page_number().cmp(&other.page_number())
|
||||
}
|
||||
fn cmp(&self, other: &Self) -> Ordering { self.page_number().cmp(&other.page_number()) }
|
||||
}
|
||||
impl PartialOrd for PhysPage {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
|
||||
}
|
||||
|
||||
/// Storage for journal revisions.
|
||||
|
|
@ -90,10 +84,13 @@ impl PageAlignedVa {
|
|||
panic!("PageAlignedVa would not fit into a u32");
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn as_u64(&self) -> u64 {self.0.get()}
|
||||
pub(crate) fn as_u64(&self) -> u64 { self.0.get() }
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn as_usize(&self) -> usize {self.0.get() as usize}
|
||||
pub(crate) fn as_usize(&self) -> usize { self.0.get() as usize }
|
||||
|
||||
/// This will turn a PageAlignedVa into a page number
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn as_vpage_num(&self) -> usize {
|
||||
|
|
@ -102,8 +99,9 @@ impl PageAlignedVa {
|
|||
}
|
||||
}
|
||||
impl Default for PageAlignedVa {
|
||||
// 0 is not a valid address; the offset at VPAGE_SIZE is the location of BasisRoot, and that is the default value.
|
||||
fn default() -> Self {PageAlignedVa(VirtAddr::new(VPAGE_SIZE as u64).unwrap())}
|
||||
// 0 is not a valid address; the offset at VPAGE_SIZE is the location of BasisRoot, and that is the
|
||||
// default value.
|
||||
fn default() -> Self { PageAlignedVa(VirtAddr::new(VPAGE_SIZE as u64).unwrap()) }
|
||||
}
|
||||
impl From<u64> for PageAlignedVa {
|
||||
fn from(arg: u64) -> Self {
|
||||
|
|
@ -138,6 +136,7 @@ impl From<usize> for PageAlignedVa {
|
|||
}
|
||||
impl Add for PageAlignedVa {
|
||||
type Output = PageAlignedVa;
|
||||
|
||||
fn add(self, other: PageAlignedVa) -> PageAlignedVa {
|
||||
let a = self.0.get();
|
||||
let b = other.0.get();
|
||||
|
|
@ -150,42 +149,42 @@ impl Add for PageAlignedVa {
|
|||
pub(crate) struct PageAlignedPa(PhysAddr);
|
||||
impl PageAlignedPa {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn as_u32(&self) -> u32 {self.0 as u32}
|
||||
pub(crate) fn as_u32(&self) -> u32 { self.0 as u32 }
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn as_u64(&self) -> u64 {self.0 as u64}
|
||||
pub(crate) fn as_u64(&self) -> u64 { self.0 as u64 }
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn as_usize(&self) -> usize {self.0 as usize}
|
||||
pub(crate) fn as_usize(&self) -> usize { self.0 as usize }
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn as_phys_addr(&self) -> PhysAddr {self.0}
|
||||
pub(crate) fn as_phys_addr(&self) -> PhysAddr { self.0 }
|
||||
}
|
||||
impl From<u32> for PageAlignedPa {
|
||||
fn from(arg: u32) -> Self {
|
||||
if arg & (PAGE_SIZE as u32 - 1) == 0 {
|
||||
PageAlignedPa( (arg & !(PAGE_SIZE as u32 - 1)) as PhysAddr )
|
||||
PageAlignedPa((arg & !(PAGE_SIZE as u32 - 1)) as PhysAddr)
|
||||
} else {
|
||||
PageAlignedPa( ((arg & !(PAGE_SIZE as u32 - 1)) + PAGE_SIZE as u32) as PhysAddr )
|
||||
PageAlignedPa(((arg & !(PAGE_SIZE as u32 - 1)) + PAGE_SIZE as u32) as PhysAddr)
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<usize> for PageAlignedPa {
|
||||
fn from(arg: usize) -> Self {
|
||||
if arg & (PAGE_SIZE as usize - 1) == 0 {
|
||||
PageAlignedPa( (arg as u32 & !(PAGE_SIZE as u32 - 1)) as PhysAddr )
|
||||
PageAlignedPa((arg as u32 & !(PAGE_SIZE as u32 - 1)) as PhysAddr)
|
||||
} else {
|
||||
PageAlignedPa( ((arg as u32 & !(PAGE_SIZE as u32 - 1)) + PAGE_SIZE as u32) as PhysAddr )
|
||||
PageAlignedPa(((arg as u32 & !(PAGE_SIZE as u32 - 1)) + PAGE_SIZE as u32) as PhysAddr)
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<PageAlignedPa> for u32 {
|
||||
fn from(arg: PageAlignedPa) -> Self {
|
||||
arg.0 as u32
|
||||
}
|
||||
fn from(arg: PageAlignedPa) -> Self { arg.0 as u32 }
|
||||
}
|
||||
impl Add for PageAlignedPa {
|
||||
type Output = PageAlignedPa;
|
||||
fn add(self, other: PageAlignedPa) -> PageAlignedPa {
|
||||
PageAlignedPa(self.0 + other.0 as PhysAddr)
|
||||
}
|
||||
|
||||
fn add(self, other: PageAlignedPa) -> PageAlignedPa { PageAlignedPa(self.0 + other.0 as PhysAddr) }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
@ -197,10 +196,10 @@ mod tests {
|
|||
assert!(PAGE_SIZE & (PAGE_SIZE - 1) == 0, "PAGE_SIZE is not a power of two!");
|
||||
}
|
||||
/// This test exists because nothing in the bitfield spec explicitly requires that a true maps to a 1.
|
||||
/// In fact a lot of code would work just fine if you mapped true to 0 and false to 1: if you're just using
|
||||
/// the generated getter and setter, it woudln't matter.
|
||||
/// However, in our application, we fully expect a true to be a 1. This test exists to ensure this seemingly
|
||||
/// obvious but not explicitly stated fact always remains true.
|
||||
/// In fact a lot of code would work just fine if you mapped true to 0 and false to 1: if you're just
|
||||
/// using the generated getter and setter, it woudln't matter.
|
||||
/// However, in our application, we fully expect a true to be a 1. This test exists to ensure this
|
||||
/// seemingly obvious but not explicitly stated fact always remains true.
|
||||
#[test]
|
||||
fn test_bitfield_bool() {
|
||||
bitfield! {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
use crate::*;
|
||||
use xous::{CID, send_message, Message};
|
||||
use xous_ipc::Buffer;
|
||||
use std::io::{Error, ErrorKind, Result};
|
||||
use std::io::{Read, Seek, SeekFrom, Write};
|
||||
|
||||
use num_traits::*;
|
||||
use std::io::{Result, Error, ErrorKind};
|
||||
use std::io::{Read, Write, Seek, SeekFrom};
|
||||
use xous::{send_message, Message, CID};
|
||||
use xous_ipc::Buffer;
|
||||
|
||||
use crate::*;
|
||||
|
||||
pub struct PddbKey<'a> {
|
||||
pub(crate) token: ApiToken,
|
||||
|
|
@ -16,13 +17,13 @@ pub struct PddbKey<'a> {
|
|||
/// PddbKeys are created by Pddb
|
||||
impl<'a> PddbKey<'a> {
|
||||
/// this will clear all residual values in the buffer. Should be called whenever the Basis set changes.
|
||||
pub fn volatile_clear(&mut self) {
|
||||
self.buf.volatile_clear();
|
||||
}
|
||||
pub fn volatile_clear(&mut self) { self.buf.volatile_clear(); }
|
||||
|
||||
pub fn attributes(&self) -> Result<KeyAttributes> {
|
||||
let req = PddbKeyAttrIpc::new(self.token);
|
||||
let mut buf = Buffer::into_buf(req).expect("Couldn't convert memory structure");
|
||||
buf.lend_mut(self.conn, Opcode::KeyAttributes.to_u32().unwrap()).expect("couldn't execute KeyAttributes opcode");
|
||||
buf.lend_mut(self.conn, Opcode::KeyAttributes.to_u32().unwrap())
|
||||
.expect("couldn't execute KeyAttributes opcode");
|
||||
let ret = buf.to_original::<PddbKeyAttrIpc, _>().expect("couldn't restore req structure");
|
||||
match ret.code {
|
||||
PddbRequestCode::NoErr => Ok(ret.to_attributes()),
|
||||
|
|
@ -50,7 +51,8 @@ impl<'a> Seek for PddbKey<'a> {
|
|||
SeekFrom::End(p) => {
|
||||
let req = PddbKeyAttrIpc::new(self.token);
|
||||
let mut buf = Buffer::into_buf(req).expect("Couldn't convert memory structure");
|
||||
buf.lend_mut(self.conn, Opcode::KeyAttributes.to_u32().unwrap()).expect("couldn't execute KeyAttributes opcode");
|
||||
buf.lend_mut(self.conn, Opcode::KeyAttributes.to_u32().unwrap())
|
||||
.expect("couldn't execute KeyAttributes opcode");
|
||||
let ret = buf.to_original::<PddbKeyAttrIpc, _>().expect("couldn't restore req structure");
|
||||
match ret.code {
|
||||
PddbRequestCode::NoErr => {
|
||||
|
|
@ -61,7 +63,7 @@ impl<'a> Seek for PddbKey<'a> {
|
|||
} else {
|
||||
Err(Error::new(ErrorKind::InvalidInput, "Seek to negative offset"))
|
||||
}
|
||||
},
|
||||
}
|
||||
PddbRequestCode::NotFound => Err(Error::new(ErrorKind::NotFound, "Key not found")),
|
||||
_ => Err(Error::new(ErrorKind::Other, "Internal error requesting key attributes")),
|
||||
}
|
||||
|
|
@ -78,26 +80,24 @@ impl<'a> Read for PddbKey<'a> {
|
|||
// create pbuf from a pre-reserved chunk of memory, to save on allocator thrashing
|
||||
// note that it does mean that un-erased data from previous reads and writes are passed back
|
||||
// to the server, which is a kind of information leakage, but I think in practice we're
|
||||
// leaking that data back to a server where the data had either originated from or was disclosed at
|
||||
// one point.
|
||||
// leaking that data back to a server where the data had either originated from or was disclosed
|
||||
// at one point.
|
||||
let readlen = {
|
||||
let pbuf = PddbBuf::from_slice_mut(self.buf.as_mut());
|
||||
// sure, we could make it a loop, but...unrolled seems better
|
||||
pbuf.token[0] = self.token[0];
|
||||
pbuf.token[1] = self.token[1];
|
||||
pbuf.token[2] = self.token[2];
|
||||
let readlen = if buf.len() <= pbuf.data.len() {
|
||||
buf.len() as u16
|
||||
} else {
|
||||
pbuf.data.len() as u16
|
||||
};
|
||||
let readlen =
|
||||
if buf.len() <= pbuf.data.len() { buf.len() as u16 } else { pbuf.data.len() as u16 };
|
||||
pbuf.len = readlen;
|
||||
pbuf.retcode = PddbRetcode::Uninit;
|
||||
pbuf.position = self.pos;
|
||||
readlen
|
||||
};
|
||||
// this takes the buffer and remaps it to the server, and on return the data is mapped back
|
||||
self.buf.lend_mut(self.conn, Opcode::ReadKey.to_u32().unwrap())
|
||||
self.buf
|
||||
.lend_mut(self.conn, Opcode::ReadKey.to_u32().unwrap())
|
||||
.or(Err(Error::new(ErrorKind::Other, "Xous internal error")))?;
|
||||
{
|
||||
// at this point, pbuf has been mutated by the server with a return code and the return data.
|
||||
|
|
@ -112,12 +112,16 @@ impl<'a> Read for PddbKey<'a> {
|
|||
Ok(pbuf.len as usize)
|
||||
}
|
||||
PddbRetcode::BasisLost => Err(Error::new(ErrorKind::BrokenPipe, "Basis lost")),
|
||||
PddbRetcode::AccessDenied => Err(Error::new(ErrorKind::PermissionDenied, "Access denied")),
|
||||
PddbRetcode::UnexpectedEof => Ok(0), // I believe this is the "expected" behavior for reads that want to read beyond the current end of file
|
||||
PddbRetcode::AccessDenied => {
|
||||
Err(Error::new(ErrorKind::PermissionDenied, "Access denied"))
|
||||
}
|
||||
PddbRetcode::UnexpectedEof => Ok(0), /* I believe this is the "expected" behavior for
|
||||
* reads that want to read beyond the current end
|
||||
* of file */
|
||||
_ => {
|
||||
log::error!("Unhandled error code: {:?}", pbuf.retcode);
|
||||
Err(Error::new(ErrorKind::Other, "Unhandled error code in PddbKey Read"))
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -135,11 +139,8 @@ impl<'a> Write for PddbKey<'a> {
|
|||
pbuf.token[0] = self.token[0];
|
||||
pbuf.token[1] = self.token[1];
|
||||
pbuf.token[2] = self.token[2];
|
||||
let writelen = if buf.len() <= pbuf.data.len() {
|
||||
buf.len() as u16
|
||||
} else {
|
||||
pbuf.data.len() as u16
|
||||
};
|
||||
let writelen =
|
||||
if buf.len() <= pbuf.data.len() { buf.len() as u16 } else { pbuf.data.len() as u16 };
|
||||
pbuf.len = writelen;
|
||||
pbuf.retcode = PddbRetcode::Uninit;
|
||||
for (&src, dst) in buf.iter().zip(pbuf.data.iter_mut()) {
|
||||
|
|
@ -149,7 +150,8 @@ impl<'a> Write for PddbKey<'a> {
|
|||
writelen
|
||||
};
|
||||
// this takes the buffer and remaps it to the server, and on return the data is mapped back
|
||||
self.buf.lend_mut(self.conn, Opcode::WriteKey.to_u32().unwrap())
|
||||
self.buf
|
||||
.lend_mut(self.conn, Opcode::WriteKey.to_u32().unwrap())
|
||||
.or(Err(Error::new(ErrorKind::Other, "Xous internal error")))?;
|
||||
{
|
||||
// at this point, pbuf has been mutated by the server with a return code and the return data.
|
||||
|
|
@ -161,22 +163,28 @@ impl<'a> Write for PddbKey<'a> {
|
|||
Ok(pbuf.len as usize)
|
||||
}
|
||||
PddbRetcode::BasisLost => Err(Error::new(ErrorKind::BrokenPipe, "Basis lost")),
|
||||
PddbRetcode::AccessDenied => Err(Error::new(ErrorKind::PermissionDenied, "Access denied")),
|
||||
PddbRetcode::AccessDenied => {
|
||||
Err(Error::new(ErrorKind::PermissionDenied, "Access denied"))
|
||||
}
|
||||
_ => Err(Error::new(ErrorKind::Other, "Unhandled error code in PddbKey Write")),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> Result<()> {
|
||||
let response = send_message(
|
||||
self.conn,
|
||||
Message::new_blocking_scalar(Opcode::WriteKeyFlush.to_usize().unwrap(), 0, 0, 0, 0)
|
||||
).or(Err(Error::new(ErrorKind::Other, "Xous internal error")))?;
|
||||
Message::new_blocking_scalar(Opcode::WriteKeyFlush.to_usize().unwrap(), 0, 0, 0, 0),
|
||||
)
|
||||
.or(Err(Error::new(ErrorKind::Other, "Xous internal error")))?;
|
||||
if let xous::Result::Scalar1(rcode) = response {
|
||||
match FromPrimitive::from_u8(rcode as u8) {
|
||||
Some(PddbRetcode::Ok) => Ok(()),
|
||||
Some(PddbRetcode::BasisLost) => Err(Error::new(ErrorKind::BrokenPipe, "Basis lost")),
|
||||
Some(PddbRetcode::DiskFull) => Err(Error::new(ErrorKind::OutOfMemory, "Out of disk space, some data lost on sync")),
|
||||
Some(PddbRetcode::DiskFull) => {
|
||||
Err(Error::new(ErrorKind::OutOfMemory, "Out of disk space, some data lost on sync"))
|
||||
}
|
||||
_ => Err(Error::new(ErrorKind::Interrupted, "Flush failed for unspecified reasons")),
|
||||
}
|
||||
} else {
|
||||
|
|
@ -191,12 +199,22 @@ impl<'a> Drop for PddbKey<'a> {
|
|||
self.buf.volatile_clear(); // clears any confidential data in our memory buffer
|
||||
|
||||
// notify the server that we can drop the connection state when our object goes out of scope
|
||||
send_message(self.conn, Message::new_blocking_scalar(Opcode::KeyDrop.to_usize().unwrap(),
|
||||
self.token[0] as usize, self.token[1] as usize, self.token[2] as usize, 0)).expect("couldn't send KeyDrop message");
|
||||
send_message(
|
||||
self.conn,
|
||||
Message::new_blocking_scalar(
|
||||
Opcode::KeyDrop.to_usize().unwrap(),
|
||||
self.token[0] as usize,
|
||||
self.token[1] as usize,
|
||||
self.token[2] as usize,
|
||||
0,
|
||||
),
|
||||
)
|
||||
.expect("couldn't send KeyDrop message");
|
||||
|
||||
if REFCOUNT.fetch_sub(1, Ordering::Relaxed) == 1 {
|
||||
unsafe{xous::disconnect(self.conn).unwrap();}
|
||||
unsafe {
|
||||
xous::disconnect(self.conn).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,12 +1,12 @@
|
|||
mod senres;
|
||||
mod utils;
|
||||
|
||||
use senres::{Senres, SenresMut};
|
||||
|
||||
use crate::backend::BasisCache;
|
||||
use crate::backend::PddbOs;
|
||||
use crate::FileHandle;
|
||||
|
||||
use senres::{Senres, SenresMut};
|
||||
|
||||
#[repr(u8)]
|
||||
enum FileType {
|
||||
Basis = 0,
|
||||
|
|
@ -48,13 +48,8 @@ pub(crate) fn stat_path(
|
|||
let mut backing = unsafe { senres::Message::from_mut_slice(mem.buf.as_slice_mut()) }
|
||||
.or(Err(crate::PddbRetcode::InternalError))?;
|
||||
|
||||
let reader = backing
|
||||
.reader(*b"StaQ")
|
||||
.ok_or(crate::PddbRetcode::InternalError)?;
|
||||
let path = reader
|
||||
.try_get_ref_from::<str>()
|
||||
.or(Err(crate::PddbRetcode::InternalError))?
|
||||
.to_owned();
|
||||
let reader = backing.reader(*b"StaQ").ok_or(crate::PddbRetcode::InternalError)?;
|
||||
let path = reader.try_get_ref_from::<str>().or(Err(crate::PddbRetcode::InternalError))?.to_owned();
|
||||
|
||||
// TODO: use the internal cache inside `basis_cache` to avoid cloning
|
||||
let (basis, remainder) =
|
||||
|
|
@ -62,18 +57,13 @@ pub(crate) fn stat_path(
|
|||
.or(Err(crate::PddbRetcode::InternalError))?;
|
||||
core::mem::drop(reader);
|
||||
|
||||
let mut writer = backing
|
||||
.writer(*b"StaR")
|
||||
.ok_or(crate::PddbRetcode::InternalError)?;
|
||||
let mut writer = backing.writer(*b"StaR").ok_or(crate::PddbRetcode::InternalError)?;
|
||||
|
||||
// The only time these two are empty is when we want to list the default basis, which
|
||||
// itself is not a valid path
|
||||
if basis.is_none() && remainder.is_none() {
|
||||
writer.append(4u8); // None
|
||||
log::error!(
|
||||
"path {} has no basis and no remainder, and therefore does not exist",
|
||||
path
|
||||
);
|
||||
log::error!("path {} has no basis and no remainder, and therefore does not exist", path);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
|
@ -153,22 +143,16 @@ pub(crate) fn list_path(
|
|||
let mut backing = unsafe { senres::Message::from_mut_slice(mem.buf.as_slice_mut()) }
|
||||
.or(Err(crate::PddbRetcode::InternalError))?;
|
||||
|
||||
let reader = backing
|
||||
.reader(*b"PthQ")
|
||||
.ok_or(crate::PddbRetcode::InternalError)?;
|
||||
let reader = backing.reader(*b"PthQ").ok_or(crate::PddbRetcode::InternalError)?;
|
||||
|
||||
let path = reader
|
||||
.try_get_ref_from()
|
||||
.or(Err(crate::PddbRetcode::InternalError))?;
|
||||
let path = reader.try_get_ref_from().or(Err(crate::PddbRetcode::InternalError))?;
|
||||
let (basis, dict) =
|
||||
utils::split_basis_and_dict(path, || basis_cache.basis_latest().map(|m| m.to_owned()))
|
||||
.or(Err(crate::PddbRetcode::InternalError))?;
|
||||
|
||||
core::mem::drop(reader);
|
||||
|
||||
let mut writer = backing
|
||||
.writer(*b"PthR")
|
||||
.ok_or(crate::PddbRetcode::InternalError)?;
|
||||
let mut writer = backing.writer(*b"PthR").ok_or(crate::PddbRetcode::InternalError)?;
|
||||
|
||||
// The only time these two are empty is when we want to list the default basis.
|
||||
if basis.is_none() && dict.is_none() {
|
||||
|
|
@ -249,13 +233,9 @@ pub(crate) fn list_basis(
|
|||
.or(Err(crate::PddbRetcode::InternalError))?;
|
||||
|
||||
{
|
||||
backing
|
||||
.reader(*b"basQ")
|
||||
.ok_or(crate::PddbRetcode::InternalError)?;
|
||||
backing.reader(*b"basQ").ok_or(crate::PddbRetcode::InternalError)?;
|
||||
}
|
||||
let mut writer = backing
|
||||
.writer(*b"basR")
|
||||
.ok_or(crate::PddbRetcode::InternalError)?;
|
||||
let mut writer = backing.writer(*b"basR").ok_or(crate::PddbRetcode::InternalError)?;
|
||||
|
||||
// Add the count of bases
|
||||
writer.append(basis_list.len() as u32);
|
||||
|
|
@ -288,41 +268,22 @@ pub(crate) fn open_key(
|
|||
let alloc_hint: usize;
|
||||
let cb_sid: Option<xous::SID>;
|
||||
let (requested_basis, requested_dict) = {
|
||||
let reader = backing
|
||||
.reader(*b"KyOQ")
|
||||
.ok_or(crate::PddbRetcode::InternalError)?;
|
||||
let reader = backing.reader(*b"KyOQ").ok_or(crate::PddbRetcode::InternalError)?;
|
||||
|
||||
let path = reader
|
||||
.try_get_ref_from()
|
||||
.or(Err(crate::PddbRetcode::InternalError))?;
|
||||
create_file = reader
|
||||
.try_get_from()
|
||||
.or(Err(crate::PddbRetcode::InternalError))?;
|
||||
let path = reader.try_get_ref_from().or(Err(crate::PddbRetcode::InternalError))?;
|
||||
create_file = reader.try_get_from().or(Err(crate::PddbRetcode::InternalError))?;
|
||||
|
||||
create_path = reader
|
||||
.try_get_from()
|
||||
.or(Err(crate::PddbRetcode::InternalError))?;
|
||||
create_path = reader.try_get_from().or(Err(crate::PddbRetcode::InternalError))?;
|
||||
|
||||
create_new = reader
|
||||
.try_get_from()
|
||||
.or(Err(crate::PddbRetcode::InternalError))?;
|
||||
create_new = reader.try_get_from().or(Err(crate::PddbRetcode::InternalError))?;
|
||||
|
||||
append = reader
|
||||
.try_get_from()
|
||||
.or(Err(crate::PddbRetcode::InternalError))?;
|
||||
append = reader.try_get_from().or(Err(crate::PddbRetcode::InternalError))?;
|
||||
|
||||
truncate = reader
|
||||
.try_get_from()
|
||||
.or(Err(crate::PddbRetcode::InternalError))?;
|
||||
truncate = reader.try_get_from().or(Err(crate::PddbRetcode::InternalError))?;
|
||||
|
||||
alloc_hint = reader
|
||||
.try_get_from::<u64>()
|
||||
.or(Err(crate::PddbRetcode::InternalError))? as usize;
|
||||
alloc_hint = reader.try_get_from::<u64>().or(Err(crate::PddbRetcode::InternalError))? as usize;
|
||||
|
||||
cb_sid = if let Some(sid) = reader
|
||||
.try_get_from()
|
||||
.or(Err(crate::PddbRetcode::InternalError))?
|
||||
{
|
||||
cb_sid = if let Some(sid) = reader.try_get_from().or(Err(crate::PddbRetcode::InternalError))? {
|
||||
Some(xous::SID::from_array(sid))
|
||||
} else {
|
||||
None
|
||||
|
|
@ -339,16 +300,13 @@ pub(crate) fn open_key(
|
|||
|
||||
// Split the final ":key" off from the dict. If there are no ":" then this will fail
|
||||
// with the "no key was specified" error.
|
||||
let (requested_dict, requested_key) = requested_dict
|
||||
.rsplit_once(std::path::MAIN_SEPARATOR)
|
||||
.ok_or_else(|| {
|
||||
let (requested_dict, requested_key) =
|
||||
requested_dict.rsplit_once(std::path::MAIN_SEPARATOR).ok_or_else(|| {
|
||||
log::error!("no key was specified");
|
||||
crate::PddbRetcode::AccessDenied
|
||||
})?;
|
||||
|
||||
let mut writer = backing
|
||||
.writer(*b"KyOR")
|
||||
.ok_or(crate::PddbRetcode::InternalError)?;
|
||||
let mut writer = backing.writer(*b"KyOR").ok_or(crate::PddbRetcode::InternalError)?;
|
||||
|
||||
// Behavior for opening files:
|
||||
// 1. If `bname` is defined, then we only loop once.
|
||||
|
|
@ -359,24 +317,19 @@ pub(crate) fn open_key(
|
|||
let bname = Some(basis.as_str());
|
||||
|
||||
// If the dictionary wasn't found, either add it or move on
|
||||
if basis_cache
|
||||
.dict_attributes(pddb_os, requested_dict, bname)
|
||||
.is_err()
|
||||
{
|
||||
if basis_cache.dict_attributes(pddb_os, requested_dict, bname).is_err() {
|
||||
if !create_path {
|
||||
continue;
|
||||
}
|
||||
basis_cache
|
||||
.dict_add(pddb_os, requested_dict, bname)
|
||||
.map_err(|e| {
|
||||
log::error!(
|
||||
"unable to add dict {} to basis {}: {:?}",
|
||||
requested_dict,
|
||||
bname.unwrap_or("internal_error"),
|
||||
e
|
||||
);
|
||||
crate::PddbRetcode::InternalError
|
||||
})?;
|
||||
basis_cache.dict_add(pddb_os, requested_dict, bname).map_err(|e| {
|
||||
log::error!(
|
||||
"unable to add dict {} to basis {}: {:?}",
|
||||
requested_dict,
|
||||
bname.unwrap_or("internal_error"),
|
||||
e
|
||||
);
|
||||
crate::PddbRetcode::InternalError
|
||||
})?;
|
||||
}
|
||||
|
||||
let mut len = 0;
|
||||
|
|
@ -399,11 +352,7 @@ pub(crate) fn open_key(
|
|||
requested_key,
|
||||
&[],
|
||||
None,
|
||||
if alloc_hint > 0 {
|
||||
Some(alloc_hint)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
if alloc_hint > 0 { Some(alloc_hint) } else { None },
|
||||
bname,
|
||||
true,
|
||||
)
|
||||
|
|
@ -420,7 +369,9 @@ pub(crate) fn open_key(
|
|||
} else if create_new {
|
||||
log::error!(
|
||||
"user requested to create {}{}{} with `create_new` set, but that file already exists",
|
||||
requested_dict, std::path::MAIN_SEPARATOR, requested_key
|
||||
requested_dict,
|
||||
std::path::MAIN_SEPARATOR,
|
||||
requested_key
|
||||
);
|
||||
return Err(crate::PddbRetcode::DiskFull);
|
||||
} else if truncate {
|
||||
|
|
@ -432,11 +383,7 @@ pub(crate) fn open_key(
|
|||
requested_key,
|
||||
&[],
|
||||
None,
|
||||
if alloc_hint > 0 {
|
||||
Some(alloc_hint)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
if alloc_hint > 0 { Some(alloc_hint) } else { None },
|
||||
bname,
|
||||
true,
|
||||
)
|
||||
|
|
@ -452,8 +399,7 @@ pub(crate) fn open_key(
|
|||
}
|
||||
|
||||
// The basis exists for sure.
|
||||
let conn =
|
||||
cb_sid.map(|cb_sid| xous::connect(cb_sid).expect("couldn't connect for callback"));
|
||||
let conn = cb_sid.map(|cb_sid| xous::connect(cb_sid).expect("couldn't connect for callback"));
|
||||
let file_handle = crate::FileHandle {
|
||||
dict: String::from(requested_dict),
|
||||
key: String::from(requested_key),
|
||||
|
|
@ -462,11 +408,7 @@ pub(crate) fn open_key(
|
|||
length: len,
|
||||
deleted: false,
|
||||
conn,
|
||||
alloc_hint: if alloc_hint > 0 {
|
||||
Some(alloc_hint)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
alloc_hint: if alloc_hint > 0 { Some(alloc_hint) } else { None },
|
||||
};
|
||||
|
||||
// Look for the first `None` record in the file descriptor list. If there
|
||||
|
|
@ -494,11 +436,7 @@ pub(crate) fn open_key(
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
log::error!(
|
||||
"unable to find key {} in dict {}",
|
||||
requested_key,
|
||||
requested_dict
|
||||
);
|
||||
log::error!("unable to find key {} in dict {}", requested_key, requested_dict);
|
||||
|
||||
// If we fall off the end, then the dict/key do not exist
|
||||
Err(crate::PddbRetcode::BasisLost)
|
||||
|
|
@ -557,45 +495,26 @@ pub(crate) fn delete_key(
|
|||
let backing = unsafe { senres::Message::from_mut_slice(mem.buf.as_slice_mut()) }
|
||||
.or(Err(crate::PddbRetcode::InternalError))?;
|
||||
|
||||
let reader = backing
|
||||
.reader(*b"RmKQ")
|
||||
.ok_or(crate::PddbRetcode::InternalError)?;
|
||||
let reader = backing.reader(*b"RmKQ").ok_or(crate::PddbRetcode::InternalError)?;
|
||||
|
||||
let full_path = reader
|
||||
.try_get_ref_from::<str>()
|
||||
.or(Err(crate::PddbRetcode::BasisLost))?;
|
||||
let full_path = reader.try_get_ref_from::<str>().or(Err(crate::PddbRetcode::BasisLost))?;
|
||||
|
||||
let (basis, path) = utils::split_basis_and_dict(full_path, || {
|
||||
basis_cache.basis_latest().map(|m| m.to_owned())
|
||||
})
|
||||
.or(Err(crate::PddbRetcode::AccessDenied))?;
|
||||
let (basis, path) =
|
||||
utils::split_basis_and_dict(full_path, || basis_cache.basis_latest().map(|m| m.to_owned()))
|
||||
.or(Err(crate::PddbRetcode::AccessDenied))?;
|
||||
let path = path.ok_or(crate::PddbRetcode::AccessDenied)?;
|
||||
let bname = basis.as_deref();
|
||||
let (dict, key) = path
|
||||
.rsplit_once(std::path::MAIN_SEPARATOR)
|
||||
.ok_or(crate::PddbRetcode::AccessDenied)?;
|
||||
let (dict, key) = path.rsplit_once(std::path::MAIN_SEPARATOR).ok_or(crate::PddbRetcode::AccessDenied)?;
|
||||
|
||||
// Perform the actual removal
|
||||
basis_cache
|
||||
.key_remove(pddb_os, dict, key, bname, false)
|
||||
.or_else(|e| {
|
||||
log::error!(
|
||||
"unable to delete key {} in dict {} (basis {:?}): {:?}",
|
||||
key,
|
||||
dict,
|
||||
bname,
|
||||
e
|
||||
);
|
||||
Err(crate::PddbRetcode::UnexpectedEof)
|
||||
})?;
|
||||
basis_cache.key_remove(pddb_os, dict, key, bname, false).or_else(|e| {
|
||||
log::error!("unable to delete key {} in dict {} (basis {:?}): {:?}", key, dict, bname, e);
|
||||
Err(crate::PddbRetcode::UnexpectedEof)
|
||||
})?;
|
||||
|
||||
// Mark the entry as deleted in all remaining file handles in the entire system
|
||||
for fds in all_fds.values_mut() {
|
||||
for fd in fds
|
||||
.iter_mut()
|
||||
.filter(|f| f.is_some())
|
||||
.map(|f| f.as_mut().unwrap())
|
||||
{
|
||||
for fd in fds.iter_mut().filter(|f| f.is_some()).map(|f| f.as_mut().unwrap()) {
|
||||
if fd.basis == basis && fd.key == key && fd.dict == dict {
|
||||
fd.deleted = true;
|
||||
}
|
||||
|
|
@ -616,12 +535,7 @@ pub(crate) fn write_key(
|
|||
let mut retcode = crate::PddbRetcode::InternalError;
|
||||
|
||||
for basis in basis_cache.access_list().iter() {
|
||||
log::debug!(
|
||||
"write (spec: {:?}){:?} {}",
|
||||
file.basis,
|
||||
file.basis.as_ref().unwrap_or(basis),
|
||||
file.key
|
||||
);
|
||||
log::debug!("write (spec: {:?}){:?} {}", file.basis, file.basis.as_ref().unwrap_or(basis), file.key);
|
||||
let length_to_write = mem.valid.map(|v| v.get()).unwrap_or_default();
|
||||
// Safety: all `u8` values are valid
|
||||
if basis_cache
|
||||
|
|
@ -633,10 +547,11 @@ pub(crate) fn write_key(
|
|||
// &mut pbuf.data[..pbuf.len as usize],
|
||||
Some(file.offset as usize),
|
||||
file.alloc_hint,
|
||||
// this is a bit inefficient because if a specific basis is specified *and* the key does not exist,
|
||||
// it'll retry the same basis for a number of times equal to the number of bases open.
|
||||
// However, usually, there's only 1-2 bases open, and usually, if you specify a basis,
|
||||
// the key will be a hit, so, we let it stand.
|
||||
// this is a bit inefficient because if a specific basis is specified *and* the key does not
|
||||
// exist, it'll retry the same basis for a number of times equal to the
|
||||
// number of bases open. However, usually, there's only 1-2 bases open, and
|
||||
// usually, if you specify a basis, the key will be a hit, so, we let it
|
||||
// stand.
|
||||
Some(file.basis.as_ref().unwrap_or(basis)),
|
||||
false,
|
||||
)
|
||||
|
|
@ -665,11 +580,7 @@ pub(crate) fn seek_key(
|
|||
) -> Result<u64, crate::PddbRetcode> {
|
||||
let file = get_fd(fds, fd)?;
|
||||
|
||||
fn seek_from_point(
|
||||
this: &mut FileHandle,
|
||||
point: u64,
|
||||
by: i64,
|
||||
) -> Result<u64, crate::PddbRetcode> {
|
||||
fn seek_from_point(this: &mut FileHandle, point: u64, by: i64) -> Result<u64, crate::PddbRetcode> {
|
||||
let by64 = by as u64;
|
||||
// Note that it's possible to seek past the end of a key, and in this case
|
||||
// the `offset` will be greater than the `len`. This is fine, and `len` will
|
||||
|
|
@ -712,12 +623,7 @@ pub(crate) fn read_key(
|
|||
|
||||
let mut retcode = crate::PddbRetcode::Ok;
|
||||
for basis in basis_cache.access_list().iter() {
|
||||
log::debug!(
|
||||
"read (spec: {:?}){:?} {}",
|
||||
file.basis,
|
||||
file.basis.as_ref().unwrap_or(basis),
|
||||
file.key
|
||||
);
|
||||
log::debug!("read (spec: {:?}){:?} {}", file.basis, file.basis.as_ref().unwrap_or(basis), file.key);
|
||||
// Safety: all u8 values are valid
|
||||
if let Ok(readlen) = basis_cache
|
||||
.key_read(
|
||||
|
|
@ -726,18 +632,17 @@ pub(crate) fn read_key(
|
|||
&file.key,
|
||||
unsafe { &mut mem.buf.as_slice_mut()[0..mem.valid.map(|v| v.get()).unwrap_or_default()] },
|
||||
Some(file.offset as usize),
|
||||
// this is a bit inefficient because if a specific basis is specified *and* the key does not exist,
|
||||
// it'll retry the same basis for a number of times equal to the number of bases open.
|
||||
// However, usually, there's only 1-2 bases open, and usually, if you specify a basis,
|
||||
// the key will be a hit, so, we let it stand.
|
||||
// this is a bit inefficient because if a specific basis is specified *and* the key does not
|
||||
// exist, it'll retry the same basis for a number of times equal to the
|
||||
// number of bases open. However, usually, there's only 1-2 bases open, and
|
||||
// usually, if you specify a basis, the key will be a hit, so, we let it
|
||||
// stand.
|
||||
Some(file.basis.as_ref().unwrap_or(basis)),
|
||||
)
|
||||
.map_err(|e| {
|
||||
match e.kind() {
|
||||
std::io::ErrorKind::NotFound => retcode = crate::PddbRetcode::BasisLost,
|
||||
std::io::ErrorKind::UnexpectedEof => {
|
||||
retcode = crate::PddbRetcode::UnexpectedEof
|
||||
}
|
||||
std::io::ErrorKind::UnexpectedEof => retcode = crate::PddbRetcode::UnexpectedEof,
|
||||
std::io::ErrorKind::OutOfMemory => retcode = crate::PddbRetcode::DiskFull,
|
||||
_ => retcode = crate::PddbRetcode::InternalError,
|
||||
};
|
||||
|
|
@ -749,12 +654,7 @@ pub(crate) fn read_key(
|
|||
return Ok(());
|
||||
}
|
||||
}
|
||||
log::error!(
|
||||
"couldn't find file {} in dict {} in basis {:?}",
|
||||
file.key,
|
||||
file.dict,
|
||||
file.basis
|
||||
);
|
||||
log::error!("couldn't find file {} in dict {} in basis {:?}", file.key, file.dict, file.basis);
|
||||
Err(retcode)
|
||||
}
|
||||
|
||||
|
|
@ -768,17 +668,11 @@ pub(crate) fn list_dict(
|
|||
.or(Err(crate::PddbRetcode::InternalError))?;
|
||||
let bname;
|
||||
{
|
||||
let reader = backing
|
||||
.reader(*b"LiDQ")
|
||||
.ok_or(crate::PddbRetcode::InternalError)?;
|
||||
bname = reader
|
||||
.try_get_from::<Option<String>>()
|
||||
.map_err(|_| crate::PddbRetcode::InternalError)?;
|
||||
let reader = backing.reader(*b"LiDQ").ok_or(crate::PddbRetcode::InternalError)?;
|
||||
bname = reader.try_get_from::<Option<String>>().map_err(|_| crate::PddbRetcode::InternalError)?;
|
||||
}
|
||||
|
||||
let mut writer = backing
|
||||
.writer(*b"LiDR")
|
||||
.ok_or(crate::PddbRetcode::InternalError)?;
|
||||
let mut writer = backing.writer(*b"LiDR").ok_or(crate::PddbRetcode::InternalError)?;
|
||||
|
||||
let dict_list = basis_cache.dict_list(pddb_os, bname.as_deref());
|
||||
writer.append(dict_list.len() as u32);
|
||||
|
|
@ -800,33 +694,17 @@ pub(crate) fn list_key(
|
|||
let bname;
|
||||
let key;
|
||||
{
|
||||
let reader = backing
|
||||
.reader(*b"LiKQ")
|
||||
.ok_or(crate::PddbRetcode::InternalError)?;
|
||||
bname = reader
|
||||
.try_get_from::<Option<String>>()
|
||||
.map_err(|_| crate::PddbRetcode::InternalError)?;
|
||||
key = reader
|
||||
.try_get_ref_from::<str>()
|
||||
.map_err(|_| crate::PddbRetcode::InternalError)?
|
||||
.to_owned();
|
||||
let reader = backing.reader(*b"LiKQ").ok_or(crate::PddbRetcode::InternalError)?;
|
||||
bname = reader.try_get_from::<Option<String>>().map_err(|_| crate::PddbRetcode::InternalError)?;
|
||||
key = reader.try_get_ref_from::<str>().map_err(|_| crate::PddbRetcode::InternalError)?.to_owned();
|
||||
}
|
||||
|
||||
let mut writer = backing
|
||||
.writer(*b"LiKR")
|
||||
.ok_or(crate::PddbRetcode::InternalError)?;
|
||||
let mut writer = backing.writer(*b"LiKR").ok_or(crate::PddbRetcode::InternalError)?;
|
||||
|
||||
let (key_list, _, _) = basis_cache
|
||||
.key_list(pddb_os, &key, bname.as_deref())
|
||||
.or_else(|e| {
|
||||
log::error!(
|
||||
"unable to get key list of dict {} in basis {:?}: {:?}",
|
||||
key,
|
||||
bname,
|
||||
e
|
||||
);
|
||||
Err(crate::PddbRetcode::InternalError)
|
||||
})?;
|
||||
let (key_list, _, _) = basis_cache.key_list(pddb_os, &key, bname.as_deref()).or_else(|e| {
|
||||
log::error!("unable to get key list of dict {} in basis {:?}: {:?}", key, bname, e);
|
||||
Err(crate::PddbRetcode::InternalError)
|
||||
})?;
|
||||
|
||||
writer.append(key_list.len() as u32);
|
||||
for dict in key_list.iter() {
|
||||
|
|
@ -844,13 +722,9 @@ pub(crate) fn delete_dict(
|
|||
// Safety: the memory message must be aligned, and we test for validity here
|
||||
let backing = unsafe { senres::Message::from_mut_slice(mem.buf.as_slice_mut()) }
|
||||
.or(Err(crate::PddbRetcode::InternalError))?;
|
||||
let reader = backing
|
||||
.reader(*b"RmDQ")
|
||||
.ok_or(crate::PddbRetcode::InternalError)?;
|
||||
let reader = backing.reader(*b"RmDQ").ok_or(crate::PddbRetcode::InternalError)?;
|
||||
|
||||
let path = reader
|
||||
.try_get_ref_from::<str>()
|
||||
.or(Err(crate::PddbRetcode::InternalError))?;
|
||||
let path = reader.try_get_ref_from::<str>().or(Err(crate::PddbRetcode::InternalError))?;
|
||||
let (bname, dict) =
|
||||
utils::split_basis_and_dict(path, || basis_cache.basis_latest().map(|m| m.to_owned()))
|
||||
.or(Err(crate::PddbRetcode::InternalError))?;
|
||||
|
|
@ -870,10 +744,7 @@ pub(crate) fn delete_dict(
|
|||
}
|
||||
}
|
||||
|
||||
if basis_cache
|
||||
.dict_remove(pddb_os, &dict, bname.as_deref(), false)
|
||||
.is_err()
|
||||
{
|
||||
if basis_cache.dict_remove(pddb_os, &dict, bname.as_deref(), false).is_err() {
|
||||
log::error!("error removing dict {} in basis {:?}", dict, bname);
|
||||
return Err(crate::PddbRetcode::InternalError);
|
||||
}
|
||||
|
|
@ -889,29 +760,23 @@ pub(crate) fn create_dict(
|
|||
// Safety: the memory message must be aligned, and we test for validity here
|
||||
let backing = unsafe { senres::Message::from_mut_slice(mem.buf.as_slice_mut()) }
|
||||
.or(Err(crate::PddbRetcode::InternalError))?;
|
||||
let reader = backing
|
||||
.reader(*b"NuDQ")
|
||||
.ok_or(crate::PddbRetcode::InternalError)?;
|
||||
let reader = backing.reader(*b"NuDQ").ok_or(crate::PddbRetcode::InternalError)?;
|
||||
|
||||
let path = reader
|
||||
.try_get_ref_from::<str>()
|
||||
.or(Err(crate::PddbRetcode::InternalError))?;
|
||||
let path = reader.try_get_ref_from::<str>().or(Err(crate::PddbRetcode::InternalError))?;
|
||||
let (basis, dict) =
|
||||
utils::split_basis_and_dict(path, || basis_cache.basis_latest().map(|m| m.to_owned()))
|
||||
.or(Err(crate::PddbRetcode::InternalError))?;
|
||||
let dict = dict.ok_or(crate::PddbRetcode::InternalError)?;
|
||||
|
||||
basis_cache
|
||||
.dict_add(pddb_os, &dict, basis.as_deref())
|
||||
.map_err(|e| {
|
||||
log::error!(
|
||||
"unable to add dict {} to basis {}: {:?}",
|
||||
dict,
|
||||
basis.as_deref().unwrap_or("internal_error"),
|
||||
e
|
||||
);
|
||||
crate::PddbRetcode::InternalError
|
||||
})?;
|
||||
basis_cache.dict_add(pddb_os, &dict, basis.as_deref()).map_err(|e| {
|
||||
log::error!(
|
||||
"unable to add dict {} to basis {}: {:?}",
|
||||
dict,
|
||||
basis.as_deref().unwrap_or("internal_error"),
|
||||
e
|
||||
);
|
||||
crate::PddbRetcode::InternalError
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,26 +69,18 @@ impl<'a> Message<'a> {
|
|||
data: unsafe { core::slice::from_raw_parts_mut(data as *mut u8, len) },
|
||||
})
|
||||
}
|
||||
|
||||
// Need to figure out how to make the non-mutable version work, since `data`
|
||||
// must be a mutable vec.
|
||||
pub fn from_slice(data: &'a [u8]) -> Result<Self, ()> {
|
||||
Ok(Message {
|
||||
message_id: 0,
|
||||
auto_return: false,
|
||||
data,
|
||||
})
|
||||
Ok(Message { message_id: 0, auto_return: false, data })
|
||||
}
|
||||
|
||||
pub fn from_mut_slice(data: &'a mut [u8]) -> Result<MutableMessage<'a>, ()> {
|
||||
Ok(MutableMessage {
|
||||
message_id: 0,
|
||||
mutable: true,
|
||||
auto_return: false,
|
||||
data,
|
||||
})
|
||||
}
|
||||
pub fn auto_return(&mut self, enable: bool) {
|
||||
self.auto_return = enable;
|
||||
Ok(MutableMessage { message_id: 0, mutable: true, auto_return: false, data })
|
||||
}
|
||||
|
||||
pub fn auto_return(&mut self, enable: bool) { self.auto_return = enable; }
|
||||
}
|
||||
|
||||
#[cfg(target_os = "xous")]
|
||||
|
|
@ -123,52 +115,35 @@ impl<'a> Drop for Message<'a> {
|
|||
fn drop(&mut self) {
|
||||
if self.auto_return {
|
||||
#[cfg(target_os = "xous")]
|
||||
return_memory_message(
|
||||
self.message_id,
|
||||
self.data.as_ptr() as usize,
|
||||
self.data.len(),
|
||||
);
|
||||
return_memory_message(self.message_id, self.data.as_ptr() as usize, self.data.len());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SenresMut for MutableMessage<'a> {
|
||||
fn as_mut_slice(&mut self) -> &mut [u8] {
|
||||
self.data
|
||||
}
|
||||
fn as_mut_ptr(&mut self) -> *mut u8 {
|
||||
self as *mut _ as *mut u8
|
||||
}
|
||||
fn as_mut_slice(&mut self) -> &mut [u8] { self.data }
|
||||
|
||||
fn as_mut_ptr(&mut self) -> *mut u8 { self as *mut _ as *mut u8 }
|
||||
}
|
||||
|
||||
impl<'a> Senres for MutableMessage<'a> {
|
||||
fn as_slice(&self) -> &[u8] {
|
||||
self.data
|
||||
}
|
||||
fn len(&self) -> usize {
|
||||
self.data.len()
|
||||
}
|
||||
fn as_ptr(&self) -> *const u8 {
|
||||
self as *const _ as *const u8
|
||||
}
|
||||
fn can_create_writer(&self) -> bool {
|
||||
self.mutable
|
||||
}
|
||||
fn as_slice(&self) -> &[u8] { self.data }
|
||||
|
||||
fn len(&self) -> usize { self.data.len() }
|
||||
|
||||
fn as_ptr(&self) -> *const u8 { self as *const _ as *const u8 }
|
||||
|
||||
fn can_create_writer(&self) -> bool { self.mutable }
|
||||
}
|
||||
|
||||
impl<'a> Senres for Message<'a> {
|
||||
fn as_slice(&self) -> &[u8] {
|
||||
self.data
|
||||
}
|
||||
fn len(&self) -> usize {
|
||||
self.data.len()
|
||||
}
|
||||
fn as_ptr(&self) -> *const u8 {
|
||||
self as *const _ as *const u8
|
||||
}
|
||||
fn can_create_writer(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn as_slice(&self) -> &[u8] { self.data }
|
||||
|
||||
fn len(&self) -> usize { self.data.len() }
|
||||
|
||||
fn as_ptr(&self) -> *const u8 { self as *const _ as *const u8 }
|
||||
|
||||
fn can_create_writer(&self) -> bool { false }
|
||||
}
|
||||
|
||||
pub trait Senres {
|
||||
|
|
@ -176,18 +151,13 @@ pub trait Senres {
|
|||
fn as_ptr(&self) -> *const u8;
|
||||
fn len(&self) -> usize;
|
||||
|
||||
fn can_create_writer(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn can_create_writer(&self) -> bool { true }
|
||||
|
||||
fn reader(&self, fourcc: [u8; 4]) -> Option<Reader<Self>>
|
||||
where
|
||||
Self: core::marker::Sized,
|
||||
{
|
||||
let reader = Reader {
|
||||
backing: self,
|
||||
offset: core::cell::Cell::new(0),
|
||||
};
|
||||
let reader = Reader { backing: self, offset: core::cell::Cell::new(0) };
|
||||
if SENRES_V1_MAGIC != reader.try_get_from().ok()? {
|
||||
return None;
|
||||
}
|
||||
|
|
@ -199,9 +169,7 @@ pub trait Senres {
|
|||
}
|
||||
|
||||
#[cfg(not(target_os = "xous"))]
|
||||
fn lend(&self, _connection: u32, _opcode: usize) -> Result<(), ()> {
|
||||
Ok(())
|
||||
}
|
||||
fn lend(&self, _connection: u32, _opcode: usize) -> Result<(), ()> { Ok(()) }
|
||||
|
||||
#[cfg(target_os = "xous")]
|
||||
fn lend(&self, connection: u32, opcode: usize) -> Result<(), ()> {
|
||||
|
|
@ -246,18 +214,13 @@ pub trait SenresMut: Senres {
|
|||
if !self.can_create_writer() {
|
||||
return None;
|
||||
}
|
||||
let mut writer = Writer {
|
||||
backing: self,
|
||||
offset: 0,
|
||||
};
|
||||
let mut writer = Writer { backing: self, offset: 0 };
|
||||
writer.append(SENRES_V1_MAGIC);
|
||||
writer.append(fourcc);
|
||||
Some(writer)
|
||||
}
|
||||
#[cfg(not(target_os = "xous"))]
|
||||
fn lend_mut(&mut self, _connection: u32, _opcode: usize) -> Result<(), ()> {
|
||||
Ok(())
|
||||
}
|
||||
fn lend_mut(&mut self, _connection: u32, _opcode: usize) -> Result<(), ()> { Ok(()) }
|
||||
#[cfg(target_os = "xous")]
|
||||
fn lend_mut(&mut self, connection: u32, opcode: usize) -> Result<(), ()> {
|
||||
let mut a0 = Syscall::SendMessage as usize;
|
||||
|
|
@ -294,7 +257,6 @@ pub trait SenresMut: Senres {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct Writer<'a, Backing: SenresMut> {
|
||||
backing: &'a mut Backing,
|
||||
offset: usize,
|
||||
|
|
@ -341,30 +303,21 @@ impl<const N: usize> Stack<N> {
|
|||
}
|
||||
|
||||
impl<const N: usize> SenresMut for Stack<N> {
|
||||
fn as_mut_slice(&mut self) -> &mut [u8] {
|
||||
self.data.as_mut_slice()
|
||||
}
|
||||
fn as_mut_ptr(&mut self) -> *mut u8 {
|
||||
&mut self.data as *mut _ as *mut u8
|
||||
}
|
||||
fn as_mut_slice(&mut self) -> &mut [u8] { self.data.as_mut_slice() }
|
||||
|
||||
fn as_mut_ptr(&mut self) -> *mut u8 { &mut self.data as *mut _ as *mut u8 }
|
||||
}
|
||||
|
||||
impl<const N: usize> Senres for Stack<N> {
|
||||
fn as_slice(&self) -> &[u8] {
|
||||
self.data.as_slice()
|
||||
}
|
||||
fn len(&self) -> usize {
|
||||
N
|
||||
}
|
||||
fn as_ptr(&self) -> *const u8 {
|
||||
&self.data as *const _ as *const u8
|
||||
}
|
||||
fn as_slice(&self) -> &[u8] { self.data.as_slice() }
|
||||
|
||||
fn len(&self) -> usize { N }
|
||||
|
||||
fn as_ptr(&self) -> *const u8 { &self.data as *const _ as *const u8 }
|
||||
}
|
||||
|
||||
impl<'a, Backing: SenresMut> Writer<'a, Backing> {
|
||||
pub fn append<T: SenSer<Backing>>(&mut self, other: T) {
|
||||
other.append_to(self);
|
||||
}
|
||||
pub fn append<T: SenSer<Backing>>(&mut self, other: T) { other.append_to(self); }
|
||||
|
||||
pub fn delayed_append<T: SenSer<Backing>>(&mut self) -> DelayedWriter<Backing, T> {
|
||||
let delayed_writer = DelayedWriter {
|
||||
|
|
@ -398,9 +351,7 @@ impl<'a, Backing: SenresMut> Writer<'a, Backing> {
|
|||
}
|
||||
|
||||
impl<'a, Backing: Senres> Reader<'a, Backing> {
|
||||
pub fn try_get_from<T: RecDes<Backing>>(&self) -> Result<T, ()> {
|
||||
T::try_get_from(self)
|
||||
}
|
||||
pub fn try_get_from<T: RecDes<Backing>>(&self) -> Result<T, ()> { T::try_get_from(self) }
|
||||
|
||||
pub fn try_get_ref_from<T: RecDesRef<'a, Backing> + ?Sized>(&'a self) -> Result<&T, ()> {
|
||||
T::try_get_ref_from(self)
|
||||
|
|
@ -418,10 +369,8 @@ macro_rules! primitive_impl {
|
|||
impl<Backing: SenresMut> SenSer<Backing> for $SelfT {
|
||||
fn append_to(&self, senres: &mut Writer<Backing>) {
|
||||
senres.align_to(core::mem::align_of::<Self>());
|
||||
for (src, dest) in self
|
||||
.to_le_bytes()
|
||||
.iter()
|
||||
.zip(senres.backing.as_mut_slice()[senres.offset..].iter_mut())
|
||||
for (src, dest) in
|
||||
self.to_le_bytes().iter().zip(senres.backing.as_mut_slice()[senres.offset..].iter_mut())
|
||||
{
|
||||
*dest = *src;
|
||||
senres.offset += 1;
|
||||
|
|
@ -438,9 +387,7 @@ macro_rules! primitive_impl {
|
|||
return Err(());
|
||||
}
|
||||
let val = Self::from_le_bytes(
|
||||
senres.backing.as_slice()[offset..offset + my_size]
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
senres.backing.as_slice()[offset..offset + my_size].try_into().unwrap(),
|
||||
);
|
||||
senres.offset.set(offset + my_size);
|
||||
Ok(val)
|
||||
|
|
@ -562,10 +509,8 @@ impl<T: RecDes<Backing>, Backing: Senres, const N: usize> RecDes<Backing> for [T
|
|||
impl<Backing: SenresMut> SenSer<Backing> for str {
|
||||
fn append_to(&self, senres: &mut Writer<Backing>) {
|
||||
senres.append(self.len() as u32);
|
||||
for (src, dest) in self
|
||||
.as_bytes()
|
||||
.iter()
|
||||
.zip(senres.backing.as_mut_slice()[senres.offset..].iter_mut())
|
||||
for (src, dest) in
|
||||
self.as_bytes().iter().zip(senres.backing.as_mut_slice()[senres.offset..].iter_mut())
|
||||
{
|
||||
*dest = *src;
|
||||
senres.offset += 1;
|
||||
|
|
@ -576,10 +521,8 @@ impl<Backing: SenresMut> SenSer<Backing> for str {
|
|||
impl<Backing: SenresMut> SenSer<Backing> for &str {
|
||||
fn append_to(&self, senres: &mut Writer<Backing>) {
|
||||
senres.append(self.len() as u32);
|
||||
for (src, dest) in self
|
||||
.as_bytes()
|
||||
.iter()
|
||||
.zip(senres.backing.as_mut_slice()[senres.offset..].iter_mut())
|
||||
for (src, dest) in
|
||||
self.as_bytes().iter().zip(senres.backing.as_mut_slice()[senres.offset..].iter_mut())
|
||||
{
|
||||
*dest = *src;
|
||||
senres.offset += 1;
|
||||
|
|
@ -594,12 +537,10 @@ impl<Backing: Senres> RecDes<Backing> for String {
|
|||
if offset + len > senres.backing.as_slice().len() {
|
||||
return Err(());
|
||||
}
|
||||
core::str::from_utf8(&senres.backing.as_slice()[offset..offset + len])
|
||||
.or(Err(()))
|
||||
.map(|e| {
|
||||
senres.offset.set(offset + len);
|
||||
e.to_owned()
|
||||
})
|
||||
core::str::from_utf8(&senres.backing.as_slice()[offset..offset + len]).or(Err(())).map(|e| {
|
||||
senres.offset.set(offset + len);
|
||||
e.to_owned()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -610,12 +551,10 @@ impl<'a, Backing: Senres> RecDesRef<'a, Backing> for str {
|
|||
if offset + len > senres.backing.as_slice().len() {
|
||||
return Err(());
|
||||
}
|
||||
core::str::from_utf8(&senres.backing.as_slice()[offset..offset + len])
|
||||
.or(Err(()))
|
||||
.map(|e| {
|
||||
senres.offset.set(offset + len);
|
||||
e
|
||||
})
|
||||
core::str::from_utf8(&senres.backing.as_slice()[offset..offset + len]).or(Err(())).map(|e| {
|
||||
senres.offset.set(offset + len);
|
||||
e
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -627,10 +566,7 @@ impl<'a, Backing: Senres, T: RecDes<Backing>> RecDesRef<'a, Backing> for [T] {
|
|||
return Err(());
|
||||
}
|
||||
let ret = unsafe {
|
||||
core::slice::from_raw_parts(
|
||||
senres.backing.as_slice().as_ptr().add(offset) as *const T,
|
||||
len,
|
||||
)
|
||||
core::slice::from_raw_parts(senres.backing.as_slice().as_ptr().add(offset) as *const T, len)
|
||||
};
|
||||
senres.offset.set(offset + len * core::mem::size_of::<T>());
|
||||
Ok(ret)
|
||||
|
|
@ -638,9 +574,7 @@ impl<'a, Backing: Senres, T: RecDes<Backing>> RecDesRef<'a, Backing> for [T] {
|
|||
}
|
||||
|
||||
impl<const N: usize> Default for Stack<N> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
fn default() -> Self { Self::new() }
|
||||
}
|
||||
|
||||
fn do_stuff(_r: &Stack) {
|
||||
|
|
@ -683,9 +617,7 @@ fn smoke_test() {
|
|||
println!("u32 val: {}", val);
|
||||
let val: u64 = reader.try_get_from().expect("couldn't get the u64 value");
|
||||
println!("u64 val: {:x}", val);
|
||||
let val: &str = reader
|
||||
.try_get_ref_from()
|
||||
.expect("couldn't get string value");
|
||||
let val: &str = reader.try_get_ref_from().expect("couldn't get string value");
|
||||
println!("String val: {}", val);
|
||||
let val: String = reader.try_get_from().expect("couldn't get string2 value");
|
||||
println!("String2 val: {}", val);
|
||||
|
|
@ -694,9 +626,7 @@ fn smoke_test() {
|
|||
let val: Option<u32> = reader.try_get_from().expect("couldn't get Option<u32>");
|
||||
println!("Option<u32> val: {:?}", val);
|
||||
|
||||
let val: u8 = reader
|
||||
.try_get_from()
|
||||
.expect("couldn't get u8 weird padding");
|
||||
let val: u8 = reader.try_get_from().expect("couldn't get u8 weird padding");
|
||||
println!("u8 val: {}", val);
|
||||
|
||||
let val: &[i32] = reader.try_get_ref_from().expect("couldn't get &[i32]");
|
||||
|
|
|
|||
|
|
@ -19,15 +19,14 @@ pub fn get_path<'a>(s: &'a str, prefix: &'a str) -> Option<&'a str> {
|
|||
let without_prefix = s.strip_prefix(prefix)?.strip_prefix(':')?;
|
||||
let mut path_split = without_prefix.split(':');
|
||||
let parent = path_split.next();
|
||||
if path_split.next().is_some() {
|
||||
None
|
||||
} else {
|
||||
parent
|
||||
}
|
||||
if path_split.next().is_some() { None } else { parent }
|
||||
}
|
||||
|
||||
/// Split a path into its constituant Basis and Dict, if the path is legal.
|
||||
pub fn split_basis_and_dict<F: FnMut() -> Option<String>>(src: &str, mut default: F) -> io::Result<(Option<String>, Option<String>)> {
|
||||
pub fn split_basis_and_dict<F: FnMut() -> Option<String>>(
|
||||
src: &str,
|
||||
mut default: F,
|
||||
) -> io::Result<(Option<String>, Option<String>)> {
|
||||
let mut basis = None;
|
||||
let dict;
|
||||
if let Some(src) = src.strip_prefix(MAIN_SEP) {
|
||||
|
|
@ -70,9 +69,7 @@ pub fn split_basis_and_dict<F: FnMut() -> Option<String>>(src: &str, mut default
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn default_path() -> Option<String> {
|
||||
Some("{DEFAULT}".to_owned())
|
||||
}
|
||||
fn default_path() -> Option<String> { Some("{DEFAULT}".to_owned()) }
|
||||
|
||||
#[test]
|
||||
fn empty_string() {
|
||||
|
|
@ -91,26 +88,23 @@ fn dict_with_colon() {
|
|||
|
||||
#[test]
|
||||
fn dict_with_two_colons() {
|
||||
assert_eq!(split_basis_and_dict("one:two:three", default_path).unwrap(), (None, Some("one:two:three".to_owned())));
|
||||
assert_eq!(
|
||||
split_basis_and_dict("one:two:three", default_path).unwrap(),
|
||||
(None, Some("one:two:three".to_owned()))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn dict_with_trailing_colon() {
|
||||
split_basis_and_dict("one:", default_path).unwrap();
|
||||
}
|
||||
fn dict_with_trailing_colon() { split_basis_and_dict("one:", default_path).unwrap(); }
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn two_dicts_with_trailing_colon() {
|
||||
split_basis_and_dict("one:two:", default_path).unwrap();
|
||||
}
|
||||
fn two_dicts_with_trailing_colon() { split_basis_and_dict("one:two:", default_path).unwrap(); }
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn basis_with_dict_with_trailing_colon() {
|
||||
split_basis_and_dict(":one:two:", default_path).unwrap();
|
||||
}
|
||||
fn basis_with_dict_with_trailing_colon() { split_basis_and_dict(":one:two:", default_path).unwrap(); }
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
|
|
@ -125,12 +119,18 @@ fn basis_missing_colon() {
|
|||
|
||||
#[test]
|
||||
fn basis_with_one_dict() {
|
||||
assert_eq!(split_basis_and_dict(":one:two", default_path).unwrap(), (Some("one".to_owned()), Some("two".to_owned())));
|
||||
assert_eq!(
|
||||
split_basis_and_dict(":one:two", default_path).unwrap(),
|
||||
(Some("one".to_owned()), Some("two".to_owned()))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basis_with_two_dicts() {
|
||||
assert_eq!(split_basis_and_dict(":one:two:three", default_path).unwrap(), (Some("one".to_owned()), Some("two:three".to_owned())));
|
||||
assert_eq!(
|
||||
split_basis_and_dict(":one:two:three", default_path).unwrap(),
|
||||
(Some("one".to_owned()), Some("two:three".to_owned()))
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn double_colon() {
|
||||
|
|
@ -146,29 +146,29 @@ fn single_colon() {
|
|||
#[test]
|
||||
fn double_colon_two_keys() {
|
||||
let default = default_path();
|
||||
assert_eq!(split_basis_and_dict("::foo:bar", default_path).unwrap(), (default, Some("foo:bar".to_owned())));
|
||||
assert_eq!(
|
||||
split_basis_and_dict("::foo:bar", default_path).unwrap(),
|
||||
(default, Some("foo:bar".to_owned()))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn double_colon_three_keys() {
|
||||
let default = default_path();
|
||||
assert_eq!(split_basis_and_dict("::foo:bar:baz", default_path).unwrap(), (default, Some("foo:bar:baz".to_owned())));
|
||||
assert_eq!(
|
||||
split_basis_and_dict("::foo:bar:baz", default_path).unwrap(),
|
||||
(default, Some("foo:bar:baz".to_owned()))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn double_colon_three_keys_trailing_colon() {
|
||||
split_basis_and_dict("::foo:bar:baz:", default_path).unwrap();
|
||||
}
|
||||
fn double_colon_three_keys_trailing_colon() { split_basis_and_dict("::foo:bar:baz:", default_path).unwrap(); }
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn dict_with_two_keys_two_trailing_colons() {
|
||||
split_basis_and_dict("foo:bar::", default_path).unwrap();
|
||||
}
|
||||
fn dict_with_two_keys_two_trailing_colons() { split_basis_and_dict("foo:bar::", default_path).unwrap(); }
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn dict_with_two_keys_three_trailing_colons() {
|
||||
split_basis_and_dict("foo:bar:::", default_path).unwrap();
|
||||
}
|
||||
fn dict_with_two_keys_three_trailing_colons() { split_basis_and_dict("foo:bar:::", default_path).unwrap(); }
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,30 +1,27 @@
|
|||
use gam::*;
|
||||
use num_traits::*;
|
||||
use locales::t;
|
||||
use crate::api::*;
|
||||
use num_traits::*;
|
||||
use xous_ipc::String;
|
||||
|
||||
use crate::api::*;
|
||||
|
||||
pub(crate) fn pddb_menu(conn: xous::CID) {
|
||||
let mut menu_items = Vec::<MenuItem>::new();
|
||||
|
||||
menu_items.push(
|
||||
MenuItem {
|
||||
name: String::from_str(t!("pddb.menu.listbasis", locales::LANG)),
|
||||
action_conn: Some(conn),
|
||||
action_opcode: Opcode::MenuListBasis.to_u32().unwrap(),
|
||||
action_payload: MenuPayload::Scalar([0, 0, 0, 0]),
|
||||
close_on_select: true,
|
||||
}
|
||||
);
|
||||
menu_items.push(
|
||||
MenuItem {
|
||||
name: String::from_str(t!("pddb.menu.change_unlock_pin", locales::LANG)),
|
||||
action_conn: Some(conn),
|
||||
action_opcode: Opcode::MenuChangePin.to_u32().unwrap(),
|
||||
action_payload: MenuPayload::Scalar([0, 0, 0, 0]),
|
||||
close_on_select: true,
|
||||
}
|
||||
);
|
||||
menu_items.push(MenuItem {
|
||||
name: String::from_str(t!("pddb.menu.listbasis", locales::LANG)),
|
||||
action_conn: Some(conn),
|
||||
action_opcode: Opcode::MenuListBasis.to_u32().unwrap(),
|
||||
action_payload: MenuPayload::Scalar([0, 0, 0, 0]),
|
||||
close_on_select: true,
|
||||
});
|
||||
menu_items.push(MenuItem {
|
||||
name: String::from_str(t!("pddb.menu.change_unlock_pin", locales::LANG)),
|
||||
action_conn: Some(conn),
|
||||
action_opcode: Opcode::MenuChangePin.to_u32().unwrap(),
|
||||
action_payload: MenuPayload::Scalar([0, 0, 0, 0]),
|
||||
close_on_select: true,
|
||||
});
|
||||
menu_items.push(MenuItem {
|
||||
name: String::from_str(t!("mainmenu.closemenu", locales::LANG)),
|
||||
action_conn: None,
|
||||
|
|
@ -34,4 +31,4 @@ pub(crate) fn pddb_menu(conn: xous::CID) {
|
|||
});
|
||||
|
||||
menu_matic(menu_items, PDDB_MENU_NAME, None);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::thread;
|
||||
#[allow(unused_imports)]
|
||||
use std::io::{Error, ErrorKind, Write, Read};
|
||||
use std::io::{Error, ErrorKind, Read, Write};
|
||||
use std::thread;
|
||||
|
||||
const PROFILING_DICT: &'static str = "pdict";
|
||||
const NUMKEYS: usize = 200;
|
||||
|
|
@ -21,9 +21,7 @@ pub fn do_query_work() {
|
|||
|
||||
let key_count = match pddb.list_keys(PROFILING_DICT, None) {
|
||||
Ok(kl) => kl.len(),
|
||||
Err(_e) => {
|
||||
0
|
||||
}
|
||||
Err(_e) => 0,
|
||||
};
|
||||
|
||||
// populate the dictionary if we're short the number of keys we want to have
|
||||
|
|
@ -31,15 +29,7 @@ pub fn do_query_work() {
|
|||
if key_count < NUMKEYS {
|
||||
for _ in 0..NUMKEYS - key_count {
|
||||
let guid = gen_guid(&mut trng);
|
||||
match pddb.get(
|
||||
PROFILING_DICT,
|
||||
&guid,
|
||||
None,
|
||||
true,
|
||||
true,
|
||||
Some(256),
|
||||
None::<fn()>
|
||||
) {
|
||||
match pddb.get(PROFILING_DICT, &guid, None, true, true, Some(256), None::<fn()>) {
|
||||
Ok(mut key) => {
|
||||
let mut rdata = [0u8; 192];
|
||||
trng.fill_bytes(&mut rdata);
|
||||
|
|
@ -63,4 +53,4 @@ pub fn do_query_work() {
|
|||
|
||||
log::info!("quitting");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,28 @@
|
|||
use rand_chacha::ChaCha8Rng;
|
||||
use rand_chacha::rand_core::RngCore;
|
||||
use rand_chacha::rand_core::SeedableRng;
|
||||
use crate::*;
|
||||
use core::sync::atomic::{AtomicU64, Ordering};
|
||||
use std::collections::{BTreeSet, HashSet};
|
||||
use std::io::Result;
|
||||
|
||||
use rand_chacha::rand_core::RngCore;
|
||||
use rand_chacha::rand_core::SeedableRng;
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
|
||||
use crate::*;
|
||||
|
||||
const UPPER_BOUND: usize = 9000;
|
||||
const LOWER_BOUND: usize = 12; // needs to be big enough to compute murmur3 hash + hold checksum
|
||||
|
||||
static RNG_LOCAL_STATE: AtomicU64 = AtomicU64::new(3);
|
||||
|
||||
fn gen_key(dictname: &str, keynum: usize, lower_size_bound: usize, upper_size_bound: usize) -> (String, Vec::<u8>) {
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(RNG_LOCAL_STATE.load(Ordering::SeqCst) + xous::TESTING_RNG_SEED.load(core::sync::atomic::Ordering::SeqCst));
|
||||
fn gen_key(
|
||||
dictname: &str,
|
||||
keynum: usize,
|
||||
lower_size_bound: usize,
|
||||
upper_size_bound: usize,
|
||||
) -> (String, Vec<u8>) {
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(
|
||||
RNG_LOCAL_STATE.load(Ordering::SeqCst)
|
||||
+ xous::TESTING_RNG_SEED.load(core::sync::atomic::Ordering::SeqCst),
|
||||
);
|
||||
// we want roughly half our keys to be in the small bin, and half in the large bin
|
||||
let keylen = if rng.next_u32() < (u32::MAX / 2) {
|
||||
((rng.next_u64() as usize) % (VPAGE_SIZE - lower_size_bound)) + lower_size_bound
|
||||
|
|
@ -25,12 +35,13 @@ fn gen_key(dictname: &str, keynum: usize, lower_size_bound: usize, upper_size_bo
|
|||
// but it helps the test checking program check things.
|
||||
let keyname = format!("sanitycheck|{}|key{}|len{}", dictname, keynum, keylen);
|
||||
let mut keydata = Vec::<u8>::new();
|
||||
for i in 0..keylen-4 {
|
||||
for i in 0..keylen - 4 {
|
||||
// the data starts with a number equal to the key number, and increments from there
|
||||
keydata.push((keynum + i) as u8);
|
||||
}
|
||||
// a checksum is appended to each run of data
|
||||
// copy the stored data, and pad it out to a multiple of word lengths with 0's so we can compute the checksum
|
||||
// copy the stored data, and pad it out to a multiple of word lengths with 0's so we can compute the
|
||||
// checksum
|
||||
let mut checkdata = Vec::<u8>::new();
|
||||
for &b in &keydata {
|
||||
checkdata.push(b);
|
||||
|
|
@ -44,14 +55,17 @@ fn gen_key(dictname: &str, keynum: usize, lower_size_bound: usize, upper_size_bo
|
|||
(keyname, keydata)
|
||||
}
|
||||
|
||||
pub(crate) fn create_basis_testcase(hw: &mut PddbOs, basis_cache: &mut BasisCache,
|
||||
maybe_num_dicts: Option<usize>, maybe_num_keys: Option<usize>, maybe_key_sizes: Option<(usize, usize)>,
|
||||
pub(crate) fn create_basis_testcase(
|
||||
hw: &mut PddbOs,
|
||||
basis_cache: &mut BasisCache,
|
||||
maybe_num_dicts: Option<usize>,
|
||||
maybe_num_keys: Option<usize>,
|
||||
maybe_key_sizes: Option<(usize, usize)>,
|
||||
maybe_extra_reserved: Option<usize>,
|
||||
) -> Result<()> {
|
||||
|
||||
hw.pddb_format(false, None).unwrap();
|
||||
let sys_basis = hw.pddb_mount().expect("couldn't mount system basis");
|
||||
basis_cache.basis_add(sys_basis);
|
||||
basis_cache.basis_add(sys_basis);
|
||||
|
||||
let num_dicts = maybe_num_dicts.unwrap_or(4);
|
||||
let num_keys = maybe_num_keys.unwrap_or(34);
|
||||
|
|
@ -72,14 +86,20 @@ pub(crate) fn create_basis_testcase(hw: &mut PddbOs, basis_cache: &mut BasisCach
|
|||
let (keyname, keydata) = gen_key(&dictname, keynum, key_lower_bound, key_upper_bound);
|
||||
// now we're ready to write it out
|
||||
if maybe_extra_reserved.is_none() {
|
||||
// we do this slightly funky way instead of just passing Some(0) because we want to test the "None" path explicitly
|
||||
basis_cache.key_update(hw, &dictname, &keyname, &keydata, None,
|
||||
None,
|
||||
None, false)?;
|
||||
// we do this slightly funky way instead of just passing Some(0) because we want to test the
|
||||
// "None" path explicitly
|
||||
basis_cache.key_update(hw, &dictname, &keyname, &keydata, None, None, None, false)?;
|
||||
} else {
|
||||
basis_cache.key_update(hw, &dictname, &keyname, &keydata, None,
|
||||
basis_cache.key_update(
|
||||
hw,
|
||||
&dictname,
|
||||
&keyname,
|
||||
&keydata,
|
||||
None,
|
||||
Some(keydata.len() + extra_reserved),
|
||||
None, false)?;
|
||||
None,
|
||||
false,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -87,9 +107,14 @@ pub(crate) fn create_basis_testcase(hw: &mut PddbOs, basis_cache: &mut BasisCach
|
|||
}
|
||||
|
||||
/// Delete & add dictionary consistency check
|
||||
pub(crate) fn delete_add_dict_consistency(hw: &mut PddbOs, basis_cache: &mut BasisCache,
|
||||
maybe_num_dicts: Option<usize>, maybe_num_keys: Option<usize>, maybe_key_sizes: Option<(usize, usize)>,
|
||||
maybe_extra_reserved: Option<usize>, basis_name: Option<&str>
|
||||
pub(crate) fn delete_add_dict_consistency(
|
||||
hw: &mut PddbOs,
|
||||
basis_cache: &mut BasisCache,
|
||||
maybe_num_dicts: Option<usize>,
|
||||
maybe_num_keys: Option<usize>,
|
||||
maybe_key_sizes: Option<(usize, usize)>,
|
||||
maybe_extra_reserved: Option<usize>,
|
||||
basis_name: Option<&str>,
|
||||
) -> Result<()> {
|
||||
let evict_count = maybe_num_dicts.unwrap_or(1);
|
||||
let num_keys = maybe_num_keys.unwrap_or(36);
|
||||
|
|
@ -113,7 +138,7 @@ pub(crate) fn delete_add_dict_consistency(hw: &mut PddbOs, basis_cache: &mut Bas
|
|||
if evicted < evict_count {
|
||||
log::debug!("evicting dict {}", evict_dict);
|
||||
match basis_cache.dict_remove(hw, evict_dict, basis_name, false) {
|
||||
Ok(_) => {},
|
||||
Ok(_) => {}
|
||||
Err(e) => log::error!("Error evicting dictionary {}: {:?}", evict_dict, e),
|
||||
}
|
||||
} else {
|
||||
|
|
@ -128,14 +153,20 @@ pub(crate) fn delete_add_dict_consistency(hw: &mut PddbOs, basis_cache: &mut Bas
|
|||
log::debug!("adding {}:{}", dictname, keyname);
|
||||
// now we're ready to write it out
|
||||
if maybe_extra_reserved.is_none() {
|
||||
// we do this slightly funky way instead of just passing Some(0) because we want to test the "None" path explicitly
|
||||
basis_cache.key_update(hw, &dictname, &keyname, &keydata, None,
|
||||
None,
|
||||
basis_name, false)?;
|
||||
// we do this slightly funky way instead of just passing Some(0) because we want to test the
|
||||
// "None" path explicitly
|
||||
basis_cache.key_update(hw, &dictname, &keyname, &keydata, None, None, basis_name, false)?;
|
||||
} else {
|
||||
basis_cache.key_update(hw, &dictname, &keyname, &keydata, None,
|
||||
basis_cache.key_update(
|
||||
hw,
|
||||
&dictname,
|
||||
&keyname,
|
||||
&keydata,
|
||||
None,
|
||||
Some(keydata.len() + extra_reserved),
|
||||
basis_name, false)?;
|
||||
basis_name,
|
||||
false,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -143,9 +174,13 @@ pub(crate) fn delete_add_dict_consistency(hw: &mut PddbOs, basis_cache: &mut Bas
|
|||
}
|
||||
|
||||
/// patch data check
|
||||
pub(crate) fn patch_test(hw: &mut PddbOs, basis_cache: &mut BasisCache,
|
||||
maybe_patch_offset: Option<usize>, maybe_patch_data: Option<String>, extend: bool) -> Result<()> {
|
||||
|
||||
pub(crate) fn patch_test(
|
||||
hw: &mut PddbOs,
|
||||
basis_cache: &mut BasisCache,
|
||||
maybe_patch_offset: Option<usize>,
|
||||
maybe_patch_data: Option<String>,
|
||||
extend: bool,
|
||||
) -> Result<()> {
|
||||
let patch_offset = maybe_patch_offset.unwrap_or(5);
|
||||
let patch_data = maybe_patch_data.unwrap_or("patched!".to_string());
|
||||
|
||||
|
|
@ -172,15 +207,33 @@ pub(crate) fn patch_test(hw: &mut PddbOs, basis_cache: &mut BasisCache,
|
|||
let key_list = key_list_unord;
|
||||
for key in key_list.iter() {
|
||||
log::debug!("updating {}:{}", dict, key);
|
||||
// this actually does something a bit more complicated on a multi-basis system than you'd think:
|
||||
// it will get the union of all key names, and then patch the *latest open basis* only with new data.
|
||||
// note: if the key didn't already exist in the latest open basis, it's added, with just that patch data in it.
|
||||
// to override this behavior, you'd want to specify a _specific_ basis, but for testing purposes, we only have one
|
||||
// so we're doing this way that would lead to surprising results if it were copied as template code elsewhere.
|
||||
match basis_cache.key_update(hw, dict, key, patch_data.as_bytes(), Some(patch_offset), None, None, false) {
|
||||
// this actually does something a bit more complicated on a multi-basis system than you'd
|
||||
// think: it will get the union of all key names, and then patch the *latest
|
||||
// open basis* only with new data. note: if the key didn't already exist in
|
||||
// the latest open basis, it's added, with just that patch data in it.
|
||||
// to override this behavior, you'd want to specify a _specific_ basis, but for testing
|
||||
// purposes, we only have one so we're doing this way that would lead to
|
||||
// surprising results if it were copied as template code elsewhere.
|
||||
match basis_cache.key_update(
|
||||
hw,
|
||||
dict,
|
||||
key,
|
||||
patch_data.as_bytes(),
|
||||
Some(patch_offset),
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
log::error!("couldn't update key {}:{} with {} bytes data offset {}: {:?}", dict, key, patch_data.as_bytes().len(), patch_offset, e);
|
||||
log::error!(
|
||||
"couldn't update key {}:{} with {} bytes data offset {}: {:?}",
|
||||
dict,
|
||||
key,
|
||||
patch_data.as_bytes().len(),
|
||||
patch_offset,
|
||||
e
|
||||
);
|
||||
panic!("error updating patch key");
|
||||
}
|
||||
}
|
||||
|
|
@ -192,7 +245,7 @@ pub(crate) fn patch_test(hw: &mut PddbOs, basis_cache: &mut BasisCache,
|
|||
if !extend {
|
||||
// now re-compute the checksum
|
||||
let mut checkdata = Vec::<u8>::new();
|
||||
for &b in &patchbuf[..readlen-4] {
|
||||
for &b in &patchbuf[..readlen - 4] {
|
||||
checkdata.push(b);
|
||||
}
|
||||
log::trace!("checkdata len: {}", checkdata.len());
|
||||
|
|
@ -200,7 +253,16 @@ pub(crate) fn patch_test(hw: &mut PddbOs, basis_cache: &mut BasisCache,
|
|||
checkdata.push(0);
|
||||
}
|
||||
let checksum = murmur3_32(&checkdata, 0);
|
||||
basis_cache.key_update(hw, dict, key, &checksum.to_le_bytes(), Some(readlen-4), None, None, false)?;
|
||||
basis_cache.key_update(
|
||||
hw,
|
||||
dict,
|
||||
key,
|
||||
&checksum.to_le_bytes(),
|
||||
Some(readlen - 4),
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
)?;
|
||||
} else {
|
||||
// this gloms a new checksum onto the existing record, adding 4 new bytes.
|
||||
let mut checkdata = Vec::<u8>::new();
|
||||
|
|
@ -212,7 +274,16 @@ pub(crate) fn patch_test(hw: &mut PddbOs, basis_cache: &mut BasisCache,
|
|||
checkdata.push(0);
|
||||
}
|
||||
let checksum = murmur3_32(&checkdata, 0);
|
||||
basis_cache.key_update(hw, dict, key, &checksum.to_le_bytes(), Some(readlen), None, None, false)?;
|
||||
basis_cache.key_update(
|
||||
hw,
|
||||
dict,
|
||||
key,
|
||||
&checksum.to_le_bytes(),
|
||||
Some(readlen),
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -220,8 +291,12 @@ pub(crate) fn patch_test(hw: &mut PddbOs, basis_cache: &mut BasisCache,
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn delete_pattern(hw: &mut PddbOs, basis_cache: &mut BasisCache,
|
||||
maybe_num_dicts: Option<usize>, maybe_num_keys: Option<usize>, maybe_key_sizes: Option<(usize, usize)>,
|
||||
pub(crate) fn delete_pattern(
|
||||
hw: &mut PddbOs,
|
||||
basis_cache: &mut BasisCache,
|
||||
maybe_num_dicts: Option<usize>,
|
||||
maybe_num_keys: Option<usize>,
|
||||
maybe_key_sizes: Option<(usize, usize)>,
|
||||
maybe_extra_reserved: Option<usize>,
|
||||
) -> Result<()> {
|
||||
let evict_count = maybe_num_dicts.unwrap_or(2);
|
||||
|
|
@ -250,9 +325,10 @@ pub(crate) fn delete_pattern(hw: &mut PddbOs, basis_cache: &mut BasisCache,
|
|||
key_list.insert(s);
|
||||
}
|
||||
for (index, key) in key_list.iter().enumerate() {
|
||||
if index % 2 == (evict_iter % 2) { // exercise odd/even patterns
|
||||
if index % 2 == (evict_iter % 2) {
|
||||
// exercise odd/even patterns
|
||||
log::info!("deleting {}:{}", evict_dict, key);
|
||||
basis_cache.key_remove(hw, evict_dict, key,None, false).unwrap();
|
||||
basis_cache.key_remove(hw, evict_dict, key, None, false).unwrap();
|
||||
let da = basis_cache.dict_attributes(hw, evict_dict, None).unwrap();
|
||||
log::info!("{:?}", da);
|
||||
}
|
||||
|
|
@ -288,18 +364,23 @@ pub(crate) fn delete_pattern(hw: &mut PddbOs, basis_cache: &mut BasisCache,
|
|||
log::warn!("rng collision on keygen: {}, deleting key", keyname);
|
||||
basis_cache.key_remove(hw, dictname, &keyname, None, false)?;
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if maybe_extra_reserved.is_none() {
|
||||
// we do this slightly funky way instead of just passing Some(0) because we want to test the "None" path explicitly
|
||||
basis_cache.key_update(hw, dictname, &keyname, &keydata, None,
|
||||
None,
|
||||
None, false)?;
|
||||
// we do this slightly funky way instead of just passing Some(0) because we want to test the
|
||||
// "None" path explicitly
|
||||
basis_cache.key_update(hw, dictname, &keyname, &keydata, None, None, None, false)?;
|
||||
} else {
|
||||
basis_cache.key_update(hw, dictname, &keyname, &keydata, None,
|
||||
basis_cache.key_update(
|
||||
hw,
|
||||
dictname,
|
||||
&keyname,
|
||||
&keydata,
|
||||
None,
|
||||
Some(keydata.len() + extra_reserved),
|
||||
None, false)?;
|
||||
None,
|
||||
false,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -360,7 +441,11 @@ pub(crate) fn list_all(hw: &mut PddbOs, basis_cache: &mut BasisCache) {
|
|||
let da = match basis_cache.dict_attributes(hw, &dict, None) {
|
||||
Ok(da) => da,
|
||||
Err(e) => {
|
||||
log::warn!("dictionary {} not in sub-basis (this is normal for multi-basis systems, {:?}", dict, e);
|
||||
log::warn!(
|
||||
"dictionary {} not in sub-basis (this is normal for multi-basis systems, {:?}",
|
||||
dict,
|
||||
e
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
|
@ -370,7 +455,10 @@ pub(crate) fn list_all(hw: &mut PddbOs, basis_cache: &mut BasisCache) {
|
|||
for key in key_list.iter() {
|
||||
let attrs = match basis_cache.key_attributes(hw, dict, key, None) {
|
||||
Ok(a) => a,
|
||||
Err(e) => {log::debug!("key not in basis, searching another basis, {:?}", e); continue},
|
||||
Err(e) => {
|
||||
log::debug!("key not in basis, searching another basis, {:?}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
log::debug!("{}:{}=>{:?}", dict, key, attrs);
|
||||
sanity_count += 1;
|
||||
|
|
@ -398,14 +486,16 @@ pub(crate) fn ci_tests(pddb_os: &mut PddbOs) -> Result<()> {
|
|||
const EXTRA_BASIS_PW: &'static str = "some password blah blah";
|
||||
|
||||
log::set_max_level(log::LevelFilter::Info);
|
||||
log::info!("Seed for this run: {}", xous::TESTING_RNG_SEED.load(core::sync::atomic::Ordering::SeqCst));
|
||||
log::info!(
|
||||
"Seed for this run: {}",
|
||||
xous::TESTING_RNG_SEED.load(core::sync::atomic::Ordering::SeqCst)
|
||||
);
|
||||
|
||||
pddb_os.test_reset();
|
||||
log::info!("Creating `basecase1e`");
|
||||
log::set_max_level(log::LevelFilter::Info);
|
||||
let mut basis_cache = BasisCache::new();
|
||||
create_basis_testcase(pddb_os, &mut basis_cache, None,
|
||||
None, None, Some(32))?;
|
||||
create_basis_testcase(pddb_os, &mut basis_cache, None, None, None, Some(32))?;
|
||||
log::info!("Saving `basecase1e` to local host");
|
||||
pddb_os.dbg_dump(Some("basecase1e".to_string()), None);
|
||||
let extra_basis_key = pddb_os.basis_derive_key(EXTRA_BASIS, EXTRA_BASIS_PW);
|
||||
|
|
@ -413,23 +503,18 @@ pub(crate) fn ci_tests(pddb_os: &mut PddbOs) -> Result<()> {
|
|||
for (&src, dst) in EXTRA_BASIS.as_bytes().iter().zip(name.iter_mut()) {
|
||||
*dst = src;
|
||||
}
|
||||
let extra_export = KeyExport {
|
||||
basis_name: name,
|
||||
key: extra_basis_key.data,
|
||||
pt_key: extra_basis_key.pt,
|
||||
};
|
||||
let mut export: Vec::<KeyExport> = Vec::new();
|
||||
let extra_export =
|
||||
KeyExport { basis_name: name, key: extra_basis_key.data, pt_key: extra_basis_key.pt };
|
||||
let mut export: Vec<KeyExport> = Vec::new();
|
||||
export.push(extra_export);
|
||||
|
||||
log::info!("Building a second basis");
|
||||
basis_cache.basis_create(pddb_os,
|
||||
EXTRA_BASIS, EXTRA_BASIS_PW).expect("couldn't build test basis");
|
||||
basis_cache.basis_create(pddb_os, EXTRA_BASIS, EXTRA_BASIS_PW).expect("couldn't build test basis");
|
||||
|
||||
log::info!("heap usage: {}", heap_usage());
|
||||
test_prune(pddb_os, &mut basis_cache);
|
||||
log::info!("Doing delete/add consistency with data extension");
|
||||
delete_add_dict_consistency(pddb_os, &mut basis_cache, None,
|
||||
None, None, None, None)?;
|
||||
delete_add_dict_consistency(pddb_os, &mut basis_cache, None, None, None, None, None)?;
|
||||
test_prune(pddb_os, &mut basis_cache);
|
||||
log::info!("Saving `dachecke` to local host");
|
||||
pddb_os.dbg_dump(Some("dachecke".to_string()), None);
|
||||
|
|
@ -454,22 +539,19 @@ pub(crate) fn ci_tests(pddb_os: &mut PddbOs) -> Result<()> {
|
|||
pddb_os.dbg_dump(Some("patterne2".to_string()), None);
|
||||
|
||||
log::info!("Doing delete/add consistency with data extension 2");
|
||||
delete_add_dict_consistency(pddb_os, &mut basis_cache, Some(3),
|
||||
Some(50), None, None, None)?;
|
||||
delete_add_dict_consistency(pddb_os, &mut basis_cache, Some(3), Some(50), None, None, None)?;
|
||||
log::info!("Saving `dachecke2` to local host");
|
||||
pddb_os.dbg_dump(Some("dachecke2".to_string()), None);
|
||||
test_prune(pddb_os, &mut basis_cache);
|
||||
|
||||
log::info!("Doing delete/add consistency with data extension 3");
|
||||
delete_add_dict_consistency(pddb_os, &mut basis_cache, Some(3),
|
||||
Some(50), None, None, None)?;
|
||||
delete_add_dict_consistency(pddb_os, &mut basis_cache, Some(3), Some(50), None, None, None)?;
|
||||
log::info!("Saving `dachecke3` to local host");
|
||||
pddb_os.dbg_dump(Some("dachecke3".to_string()), None);
|
||||
test_prune(pddb_os, &mut basis_cache);
|
||||
|
||||
log::info!("Doing delete/add consistency with data extension 4");
|
||||
delete_add_dict_consistency(pddb_os, &mut basis_cache, Some(6),
|
||||
Some(50), None, None, None)?;
|
||||
delete_add_dict_consistency(pddb_os, &mut basis_cache, Some(6), Some(50), None, None, None)?;
|
||||
log::info!("Saving `dachecke4` to local host");
|
||||
pddb_os.dbg_dump(Some("dachecke4".to_string()), None);
|
||||
test_prune(pddb_os, &mut basis_cache);
|
||||
|
|
@ -491,14 +573,22 @@ pub(crate) fn ci_tests(pddb_os: &mut PddbOs) -> Result<()> {
|
|||
}
|
||||
|
||||
log::info!("Mounting the second basis");
|
||||
if let Some(basis2) = basis_cache.basis_unlock(pddb_os,
|
||||
EXTRA_BASIS, EXTRA_BASIS_PW, BasisRetentionPolicy::Persist) {
|
||||
if let Some(basis2) =
|
||||
basis_cache.basis_unlock(pddb_os, EXTRA_BASIS, EXTRA_BASIS_PW, BasisRetentionPolicy::Persist)
|
||||
{
|
||||
basis_cache.basis_add(basis2);
|
||||
}
|
||||
log::set_max_level(log::LevelFilter::Info);
|
||||
log::info!("Adding keys to Basis2");
|
||||
delete_add_dict_consistency(pddb_os, &mut basis_cache, Some(3),
|
||||
Some(15), None, None, Some(EXTRA_BASIS))?;
|
||||
delete_add_dict_consistency(
|
||||
pddb_os,
|
||||
&mut basis_cache,
|
||||
Some(3),
|
||||
Some(15),
|
||||
None,
|
||||
None,
|
||||
Some(EXTRA_BASIS),
|
||||
)?;
|
||||
log::info!("Saving `basis2` to local host");
|
||||
test_prune(pddb_os, &mut basis_cache);
|
||||
pddb_os.dbg_dump(Some("basis2".to_string()), Some(&export));
|
||||
|
|
@ -543,11 +633,15 @@ pub(crate) fn ci_tests(pddb_os: &mut PddbOs) -> Result<()> {
|
|||
remount_list.insert(key.to_string());
|
||||
}
|
||||
}
|
||||
assert!(remount_list.difference(&pre_list).count() == 0, "remounted list is not identical to the original list");
|
||||
assert!(
|
||||
remount_list.difference(&pre_list).count() == 0,
|
||||
"remounted list is not identical to the original list"
|
||||
);
|
||||
|
||||
log::info!("Mounting the second basis again");
|
||||
if let Some(basis2) = basis_cache.basis_unlock(pddb_os,
|
||||
EXTRA_BASIS, EXTRA_BASIS_PW, BasisRetentionPolicy::Persist) {
|
||||
if let Some(basis2) =
|
||||
basis_cache.basis_unlock(pddb_os, EXTRA_BASIS, EXTRA_BASIS_PW, BasisRetentionPolicy::Persist)
|
||||
{
|
||||
basis_cache.basis_add(basis2);
|
||||
}
|
||||
let mut merge2_list = HashSet::<String>::new();
|
||||
|
|
@ -557,7 +651,10 @@ pub(crate) fn ci_tests(pddb_os: &mut PddbOs) -> Result<()> {
|
|||
merge2_list.insert(key.to_string());
|
||||
}
|
||||
}
|
||||
assert!(merge2_list.difference(&merge_list).count() == 0, "merged list is different from the original list after remount");
|
||||
assert!(
|
||||
merge2_list.difference(&merge_list).count() == 0,
|
||||
"merged list is different from the original list after remount"
|
||||
);
|
||||
list_all(pddb_os, &mut basis_cache);
|
||||
|
||||
log::info!("CI done");
|
||||
|
|
@ -567,11 +664,11 @@ pub(crate) fn ci_tests(pddb_os: &mut PddbOs) -> Result<()> {
|
|||
}
|
||||
|
||||
fn test_prune(hw: &mut PddbOs, basis_cache: &mut BasisCache) {
|
||||
const TARGET_SIZE: usize = 150*1024;
|
||||
const TARGET_SIZE: usize = 150 * 1024;
|
||||
let cache_size = basis_cache.cache_size();
|
||||
if cache_size > TARGET_SIZE {
|
||||
log::info!("size is {}, requesting prune of {}", cache_size, cache_size - TARGET_SIZE);
|
||||
log::info!("pruned {}", basis_cache.cache_prune(hw, cache_size - TARGET_SIZE));
|
||||
}
|
||||
log::info!("size is now {}", basis_cache.cache_size());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
use xous::{SID, CID};
|
||||
|
||||
use gam::modal::*;
|
||||
use locales::t;
|
||||
use num_traits::*;
|
||||
use xous::msg_scalar_unpack;
|
||||
use xous::{CID, SID};
|
||||
use xous_ipc::Buffer;
|
||||
|
||||
use num_traits::*;
|
||||
|
||||
use gam::modal::*;
|
||||
|
||||
use locales::t;
|
||||
use crate::BasisRequestPassword;
|
||||
/*
|
||||
Conclusions:
|
||||
|
|
@ -59,8 +56,8 @@ pub(crate) fn password_ux_manager(
|
|||
// the CID of the main loop, as a backchannel for async callbacks.
|
||||
_main_cid: CID,
|
||||
// the SID we're to use for our loop handler, for getting requests
|
||||
ux_sid: SID) {
|
||||
|
||||
ux_sid: SID,
|
||||
) {
|
||||
let ux_cid = xous::connect(ux_sid).unwrap();
|
||||
// create a thread that just handles the redrawing requests
|
||||
// build the core data structure here
|
||||
|
|
@ -74,16 +71,17 @@ pub(crate) fn password_ux_manager(
|
|||
);
|
||||
password_action.reset_action_payloads(1, None);
|
||||
|
||||
let mut pddb_modal =
|
||||
Modal::new(
|
||||
gam::PDDB_MODAL_NAME,
|
||||
ActionType::TextEntry(password_action.clone()),
|
||||
Some(t!("pddb.password", locales::LANG)),
|
||||
None,
|
||||
gam::SYSTEM_STYLE,
|
||||
8
|
||||
);
|
||||
pddb_modal.spawn_helper(ux_sid, pddb_modal.sid,
|
||||
let mut pddb_modal = Modal::new(
|
||||
gam::PDDB_MODAL_NAME,
|
||||
ActionType::TextEntry(password_action.clone()),
|
||||
Some(t!("pddb.password", locales::LANG)),
|
||||
None,
|
||||
gam::SYSTEM_STYLE,
|
||||
8,
|
||||
);
|
||||
pddb_modal.spawn_helper(
|
||||
ux_sid,
|
||||
pddb_modal.sid,
|
||||
PwManagerOpcode::ModalRedraw.to_u32().unwrap(),
|
||||
PwManagerOpcode::ModalKeypress.to_u32().unwrap(),
|
||||
PwManagerOpcode::ModalDrop.to_u32().unwrap(),
|
||||
|
|
@ -104,20 +102,32 @@ pub(crate) fn password_ux_manager(
|
|||
};
|
||||
pddb_modal.modify(
|
||||
Some(ActionType::TextEntry(password_action.clone())),
|
||||
Some(t!("pddb.password", locales::LANG)), false,
|
||||
Some(format!("{}'{}'", t!("pddb.password_for", locales::LANG), db_name.as_str().unwrap()).as_str()), false, None
|
||||
Some(t!("pddb.password", locales::LANG)),
|
||||
false,
|
||||
Some(
|
||||
format!("{}'{}'", t!("pddb.password_for", locales::LANG), db_name.as_str().unwrap())
|
||||
.as_str(),
|
||||
),
|
||||
false,
|
||||
None,
|
||||
);
|
||||
log::info!(
|
||||
"{}PDDB.REQPW,{},{}",
|
||||
xous::BOOKEND_START,
|
||||
db_name.as_str().unwrap(),
|
||||
xous::BOOKEND_END
|
||||
);
|
||||
log::info!("{}PDDB.REQPW,{},{}", xous::BOOKEND_START, db_name.as_str().unwrap(), xous::BOOKEND_END);
|
||||
pddb_modal.activate();
|
||||
dr = Some(msg);
|
||||
|
||||
},
|
||||
}
|
||||
Some(PwManagerOpcode::PwReturn) => {
|
||||
let mut buf = unsafe { Buffer::from_memory_message(msg.body.memory_message().unwrap()) };
|
||||
let pw = buf.to_original::<gam::modal::TextEntryPayloads, _>().unwrap();
|
||||
|
||||
if let Some(mut response) = dr.take() {
|
||||
let mut buffer = unsafe { Buffer::from_memory_message_mut(response.body.memory_message_mut().unwrap()) };
|
||||
let mut buffer = unsafe {
|
||||
Buffer::from_memory_message_mut(response.body.memory_message_mut().unwrap())
|
||||
};
|
||||
let mut request = buffer.to_original::<BasisRequestPassword, _>().unwrap();
|
||||
request.plaintext_pw = Some(xous_ipc::String::from_str(pw.first().as_str()));
|
||||
// return the password to the caller
|
||||
|
|
@ -129,10 +139,10 @@ pub(crate) fn password_ux_manager(
|
|||
|
||||
pw.first().volatile_clear(); // ensure the data is destroyed after sending to the keys enclave
|
||||
buf.volatile_clear();
|
||||
},
|
||||
}
|
||||
Some(PwManagerOpcode::ModalRedraw) => {
|
||||
pddb_modal.redraw();
|
||||
},
|
||||
}
|
||||
Some(PwManagerOpcode::ModalKeypress) => msg_scalar_unpack!(msg, k1, k2, k3, k4, {
|
||||
let keys = [
|
||||
core::char::from_u32(k1 as u32).unwrap_or('\u{0000}'),
|
||||
|
|
@ -142,14 +152,15 @@ pub(crate) fn password_ux_manager(
|
|||
];
|
||||
pddb_modal.key_event(keys);
|
||||
}),
|
||||
Some(PwManagerOpcode::ModalDrop) => { // this guy should never quit, it's a core OS service
|
||||
Some(PwManagerOpcode::ModalDrop) => {
|
||||
// this guy should never quit, it's a core OS service
|
||||
panic!("Password modal for PDDB quit unexpectedly");
|
||||
},
|
||||
}
|
||||
Some(PwManagerOpcode::Quit) => {
|
||||
log::warn!("received quit on PDDB password UX renderer loop");
|
||||
xous::return_scalar(msg.sender, 0).unwrap();
|
||||
break;
|
||||
},
|
||||
}
|
||||
|
||||
None => {
|
||||
log::error!("couldn't convert opcode");
|
||||
|
|
|
|||
Loading…
Reference in a new issue