mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-08 04:56:43 +00:00
Merge remote-tracking branch 'origin/main' into libstd-fs
This commit is contained in:
commit
748d4ce87d
18 changed files with 332 additions and 124 deletions
|
|
@ -441,33 +441,46 @@ impl ActionManager {
|
|||
VaultMode::Fido => crate::fido::U2F_APP_DICT,
|
||||
VaultMode::Totp => VAULT_TOTP_DICT,
|
||||
};
|
||||
match self.pddb.borrow().delete_key(dict, entry.key_name.as_str().unwrap_or("UTF8-error"), None) {
|
||||
Ok(_) => {
|
||||
self.modals.show_notification(t!("vault.completed", xous::LANG), None).ok();
|
||||
}
|
||||
Err(e) => {
|
||||
match e.kind() {
|
||||
std::io::ErrorKind::NotFound => {
|
||||
// handle special case of FIDO which is two dicts combined
|
||||
if entry.mode == VaultMode::Fido {
|
||||
// try the "other" dictionary
|
||||
match self.pddb.borrow()
|
||||
.delete_key(
|
||||
crate::ctap::FIDO_CRED_DICT,
|
||||
entry.key_name.as_str().unwrap_or("UTF8-error"),
|
||||
None) {
|
||||
Ok(_) => {
|
||||
self.modals.show_notification(t!("vault.completed", xous::LANG), None).ok();
|
||||
return;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
self.report_err(t!("vault.error.not_found", xous::LANG), None::<std::io::Error>);
|
||||
// first "get" the key, to resolve exactly what basis the key is in. This is because `delete_key()` will
|
||||
// only look in the most recently unlocked secret basis, it won't automatically descend into the database
|
||||
// and try to cull something willy-nilly.
|
||||
match self.pddb.borrow().get(dict, entry.key_name.as_str().unwrap_or("UTF8-error"),
|
||||
None, false, false, None, None::<fn()>
|
||||
) {
|
||||
Ok(candidate) => {
|
||||
let attr = candidate.attributes().expect("couldn't get key attributes");
|
||||
match self.pddb.borrow().delete_key(dict,
|
||||
entry.key_name.as_str().unwrap_or("UTF8-error"),
|
||||
Some(&attr.basis)) {
|
||||
Ok(_) => {
|
||||
self.modals.show_notification(t!("vault.completed", xous::LANG), None).ok();
|
||||
}
|
||||
Err(e) => {
|
||||
match e.kind() {
|
||||
std::io::ErrorKind::NotFound => {
|
||||
// handle special case of FIDO which is two dicts combined
|
||||
if entry.mode == VaultMode::Fido {
|
||||
// try the "other" dictionary
|
||||
match self.pddb.borrow()
|
||||
.delete_key(
|
||||
crate::ctap::FIDO_CRED_DICT,
|
||||
entry.key_name.as_str().unwrap_or("UTF8-error"),
|
||||
Some(&attr.basis)) {
|
||||
Ok(_) => {
|
||||
self.modals.show_notification(t!("vault.completed", xous::LANG), None).ok();
|
||||
return;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
self.report_err(t!("vault.error.not_found", xous::LANG), None::<std::io::Error>);
|
||||
}
|
||||
_ => self.report_err(t!("vault.error.internal_error", xous::LANG), Some(e)),
|
||||
}
|
||||
}
|
||||
_ => self.report_err(t!("vault.error.internal_error", xous::LANG), Some(e)),
|
||||
}
|
||||
}
|
||||
Err(e) => self.report_err(t!("vault.error.internal_error", xous::LANG), Some(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -485,6 +498,8 @@ impl ActionManager {
|
|||
false, false, None, Some(crate::basis_change)
|
||||
) {
|
||||
Ok(mut record) => {
|
||||
// resolve the basis of the key, so that we are editing it "in place"
|
||||
let attr = record.attributes().expect("couldn't get key attributes");
|
||||
let mut data = Vec::<u8>::new();
|
||||
let maybe_update = match record.read_to_end(&mut data) {
|
||||
Ok(_len) => {
|
||||
|
|
@ -501,13 +516,13 @@ impl ActionManager {
|
|||
pw.password = edit_data.content()[2].content.as_str().unwrap().to_string();
|
||||
pw.notes = edit_data.content()[3].content.as_str().unwrap().to_string();
|
||||
pw.atime = utc_now().timestamp() as u64;
|
||||
Some(pw)
|
||||
pw
|
||||
} else { log::error!("record error");
|
||||
self.report_err(t!("vault.error.record_error", xous::LANG), None::<std::io::Error>); None }
|
||||
self.report_err(t!("vault.error.record_error", xous::LANG), None::<std::io::Error>); return }
|
||||
}
|
||||
Err(e) => { log::error!("internal error"); self.report_err(t!("vault.error.internal_error", xous::LANG), Some(e)); None }
|
||||
Err(e) => { log::error!("internal error"); self.report_err(t!("vault.error.internal_error", xous::LANG), Some(e)); return }
|
||||
};
|
||||
maybe_update
|
||||
Some((maybe_update, attr.basis))
|
||||
}
|
||||
Err(e) => {
|
||||
match e.kind() {
|
||||
|
|
@ -523,12 +538,12 @@ impl ActionManager {
|
|||
None
|
||||
}
|
||||
};
|
||||
if let Some(update) = maybe_update {
|
||||
self.pddb.borrow().delete_key(dict, entry.key_name.as_str().unwrap(), None)
|
||||
if let Some((update, basis)) = maybe_update {
|
||||
self.pddb.borrow().delete_key(dict, entry.key_name.as_str().unwrap(), Some(&basis))
|
||||
.unwrap_or_else(|e| {log::error!("internal error");
|
||||
self.report_err(t!("vault.error.internal_error", xous::LANG), Some(e))});
|
||||
match self.pddb.borrow().get(
|
||||
dict, entry.key_name.as_str().unwrap(), None,
|
||||
dict, entry.key_name.as_str().unwrap(), Some(&basis),
|
||||
false, true, Some(VAULT_ALLOC_HINT),
|
||||
Some(crate::basis_change)
|
||||
) {
|
||||
|
|
@ -555,6 +570,8 @@ impl ActionManager {
|
|||
false, false, None, Some(crate::basis_change)
|
||||
) {
|
||||
Ok(mut record) => {
|
||||
// resolve the basis of the key, so that we are editing it "in place"
|
||||
let attr = record.attributes().expect("couldn't get key attributes");
|
||||
let mut data = Vec::<u8>::new();
|
||||
let maybe_update = match record.read_to_end(&mut data) {
|
||||
Ok(_len) => {
|
||||
|
|
@ -568,26 +585,26 @@ impl ActionManager {
|
|||
ai.name = edit_data.content()[0].content.as_str().unwrap().to_string();
|
||||
ai.notes = edit_data.content()[1].content.as_str().unwrap().to_string();
|
||||
ai.atime = utc_now().timestamp() as u64;
|
||||
Some(ai)
|
||||
} else { self.report_err(t!("vault.error.record_error", xous::LANG), None::<std::io::Error>); None }
|
||||
ai
|
||||
} else { self.report_err(t!("vault.error.record_error", xous::LANG), None::<std::io::Error>); return }
|
||||
}
|
||||
Err(e) => { self.report_err(t!("vault.error.internal_error", xous::LANG), Some(e)); None }
|
||||
Err(e) => { self.report_err(t!("vault.error.internal_error", xous::LANG), Some(e)); return }
|
||||
};
|
||||
maybe_update
|
||||
Some((maybe_update, attr.basis))
|
||||
}
|
||||
Err(e) => {
|
||||
match e.kind() {
|
||||
std::io::ErrorKind::NotFound => self.report_err(t!("vault.error.fido2", xous::LANG), None::<std::io::Error>),
|
||||
_ => self.report_err(t!("vault.error.internal_error", xous::LANG), Some(e)),
|
||||
}
|
||||
None
|
||||
return
|
||||
}
|
||||
};
|
||||
if let Some(update) = maybe_update {
|
||||
self.pddb.borrow().delete_key(dict, entry.key_name.as_str().unwrap(), None)
|
||||
if let Some((update, basis)) = maybe_update {
|
||||
self.pddb.borrow().delete_key(dict, entry.key_name.as_str().unwrap(), Some(&basis))
|
||||
.unwrap_or_else(|e| self.report_err(t!("vault.error.internal_error", xous::LANG), Some(e)));
|
||||
match self.pddb.borrow().get(
|
||||
dict, entry.key_name.as_str().unwrap(), None,
|
||||
dict, entry.key_name.as_str().unwrap(), Some(&basis),
|
||||
false, true, Some(VAULT_ALLOC_HINT),
|
||||
Some(crate::basis_change)
|
||||
) {
|
||||
|
|
@ -607,6 +624,8 @@ impl ActionManager {
|
|||
false, false, None, Some(crate::basis_change)
|
||||
) {
|
||||
Ok(mut record) => {
|
||||
// resolve the basis of the key, so that we are editing it "in place"
|
||||
let attr = record.attributes().expect("couldn't get key attributes");
|
||||
let mut data = Vec::<u8>::new();
|
||||
let maybe_update = match record.read_to_end(&mut data) {
|
||||
Ok(_len) => {
|
||||
|
|
@ -633,26 +652,26 @@ impl ActionManager {
|
|||
if let Ok(d) = u32::from_str_radix(edit_data.content()[5].content.as_str().unwrap(), 10) {
|
||||
pw.digits = d;
|
||||
}
|
||||
Some(pw)
|
||||
} else { self.report_err(t!("vault.error.record_error", xous::LANG), None::<std::io::Error>); None }
|
||||
pw
|
||||
} else { self.report_err(t!("vault.error.record_error", xous::LANG), None::<std::io::Error>); return }
|
||||
}
|
||||
Err(e) => { self.report_err(t!("vault.error.internal_error", xous::LANG), Some(e)); None }
|
||||
Err(e) => { self.report_err(t!("vault.error.internal_error", xous::LANG), Some(e)); return }
|
||||
};
|
||||
maybe_update
|
||||
Some((maybe_update, attr.basis))
|
||||
}
|
||||
Err(e) => {
|
||||
match e.kind() {
|
||||
std::io::ErrorKind::NotFound => self.report_err(t!("vault.error.not_found", xous::LANG), None::<std::io::Error>),
|
||||
_ => self.report_err(t!("vault.error.internal_error", xous::LANG), Some(e)),
|
||||
}
|
||||
None
|
||||
return
|
||||
}
|
||||
};
|
||||
if let Some(update) = maybe_update {
|
||||
self.pddb.borrow().delete_key(dict, entry.key_name.as_str().unwrap(), None)
|
||||
if let Some((update, basis)) = maybe_update {
|
||||
self.pddb.borrow().delete_key(dict, entry.key_name.as_str().unwrap(), Some(&basis))
|
||||
.unwrap_or_else(|e| self.report_err(t!("vault.error.internal_error", xous::LANG), Some(e)));
|
||||
match self.pddb.borrow().get(
|
||||
dict, entry.key_name.as_str().unwrap(), None,
|
||||
dict, entry.key_name.as_str().unwrap(), Some(&basis),
|
||||
false, true, Some(VAULT_ALLOC_HINT),
|
||||
Some(crate::basis_change)
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -65,8 +65,9 @@ pub(crate) const CRED_INITAL_SIZE: usize = 512;
|
|||
// With P=20 and K=150, we have I=2M which is enough for 500 increments per day for 10 years.
|
||||
#[allow(dead_code)] // openSK legacy
|
||||
const NUM_PAGES: usize = 20;
|
||||
#[allow(dead_code)] // OpenSK legacy
|
||||
const MAX_SUPPORTED_RESIDENTIAL_KEYS: usize = 150;
|
||||
// The limit is based on the performance of the PDDB to get a query response within
|
||||
// the compliance time-out limit. Optimization is needed to improve this number!
|
||||
const MAX_SUPPORTED_RESIDENTIAL_KEYS: usize = 32;
|
||||
|
||||
const MAX_PIN_RETRIES: u8 = 8;
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
|
|
@ -389,6 +390,7 @@ openssl asn1parse -in opensk_cert.pem -inform pem
|
|||
Some(CREDENTIAL_ID_SIZE), Some(crate::basis_change)
|
||||
) {
|
||||
Ok(mut cred) => {
|
||||
log::trace!("find {}", shortid);
|
||||
let mut data = Vec::<u8>::new();
|
||||
cred.read_to_end(&mut data).or(Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR))?;
|
||||
match deserialize_credential(&data) {
|
||||
|
|
@ -428,6 +430,9 @@ openssl asn1parse -in opensk_cert.pem -inform pem
|
|||
&mut self,
|
||||
new_credential: PublicKeyCredentialSource,
|
||||
) -> Result<(), Ctap2StatusCode> {
|
||||
if self.count_credentials()? >= MAX_SUPPORTED_RESIDENTIAL_KEYS {
|
||||
return Err(Ctap2StatusCode::CTAP2_ERR_KEY_STORE_FULL);
|
||||
}
|
||||
let shortid = self.cid_to_str(&new_credential.credential_id);
|
||||
match self.pddb.borrow().get(
|
||||
FIDO_CRED_DICT,
|
||||
|
|
@ -437,6 +442,7 @@ openssl asn1parse -in opensk_cert.pem -inform pem
|
|||
) {
|
||||
Ok(mut cred) => {
|
||||
let value = serialize_credential(new_credential)?;
|
||||
log::trace!("writing {}", shortid);
|
||||
cred.write(&value)
|
||||
.or(Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR))?;
|
||||
self.pddb.borrow().sync()
|
||||
|
|
@ -465,11 +471,13 @@ openssl asn1parse -in opensk_cert.pem -inform pem
|
|||
None, false, false,
|
||||
Some(CREDENTIAL_ID_SIZE), Some(crate::basis_change)
|
||||
).ok() {
|
||||
log::trace!("checking {}", cred_name);
|
||||
let mut data = Vec::<u8>::new();
|
||||
cred_entry.read_to_end(&mut data).or(Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR))?;
|
||||
if let Some(cred) = deserialize_credential(&data) {
|
||||
if cred.rp_id == rp_id
|
||||
&& (cred.is_discoverable() || !check_cred_protect) {
|
||||
log::trace!("filtered {}", cred_name);
|
||||
result.push(cred);
|
||||
}
|
||||
}
|
||||
|
|
@ -479,9 +487,8 @@ openssl asn1parse -in opensk_cert.pem -inform pem
|
|||
}
|
||||
|
||||
/// Returns the number of credentials.
|
||||
#[cfg(test)]
|
||||
pub fn count_credentials(&self) -> Result<usize, Ctap2StatusCode> {
|
||||
let mut cred_list = self.pddb.borrow().list_keys(
|
||||
let cred_list = self.pddb.borrow().list_keys(
|
||||
FIDO_CRED_DICT, None).unwrap_or(Vec::new());
|
||||
Ok(cred_list.len())
|
||||
}
|
||||
|
|
@ -615,7 +622,7 @@ openssl asn1parse -in opensk_cert.pem -inform pem
|
|||
let mut pin_hash = [0u8; PIN_AUTH_LENGTH];
|
||||
match ph.read(&mut pin_hash) {
|
||||
Ok(PIN_AUTH_LENGTH) => {
|
||||
log::info!("pin_hash: {:x?}", &pin_hash);
|
||||
log::trace!("pin_hash: {:x?}", &pin_hash);
|
||||
Ok(Some(pin_hash))
|
||||
},
|
||||
Ok(l) => {
|
||||
|
|
|
|||
|
|
@ -108,9 +108,6 @@ To clear test entries:
|
|||
pddb dictdelete fido.cred
|
||||
pddb dictdelete fido.u2fapps
|
||||
|
||||
Issue: editing an entry in a non-secret basis while a secret basis is open won't work because
|
||||
the delete key function doesn't work in that case. Need to modify the `get` routine to return
|
||||
the basis so we can specify which basis to edit...
|
||||
*/
|
||||
|
||||
#[derive(Debug, num_derive::FromPrimitive, num_derive::ToPrimitive)]
|
||||
|
|
@ -161,7 +158,7 @@ const ERR_TIMEOUT_MS: usize = 5000;
|
|||
|
||||
fn main() -> ! {
|
||||
log_server::init_wait().unwrap();
|
||||
log::set_max_level(log::LevelFilter::Debug);
|
||||
log::set_max_level(log::LevelFilter::Info);
|
||||
log::info!("my PID is {}", xous::process::id());
|
||||
|
||||
let xns = xous_names::XousNames::new().unwrap();
|
||||
|
|
@ -195,41 +192,46 @@ fn main() -> ! {
|
|||
let mut rng = ctap_crypto::rng256::XousRng256::new(&xns);
|
||||
// this call will block until the PDDB is mounted.
|
||||
let usb = usb_device_xous::UsbHid::new();
|
||||
let mut ctap_state = CtapState::new(&mut rng, check_user_presence, boot_time);
|
||||
let mut ctap_hid = CtapHid::new();
|
||||
loop {
|
||||
match usb.u2f_wait_incoming() {
|
||||
Ok(msg) => {
|
||||
log::trace!("FIDO listener got message: {:?}", msg);
|
||||
let now = ClockValue::new(tt.elapsed_ms() as i64, 1000);
|
||||
let reply = ctap_hid.process_hid_packet(&msg.packet, now, &mut ctap_state);
|
||||
// This block handles sending packets.
|
||||
for pkt_reply in reply {
|
||||
let mut reply = RawFidoMsg::default();
|
||||
reply.packet.copy_from_slice(&pkt_reply);
|
||||
let status = usb.u2f_send(reply);
|
||||
match status {
|
||||
Ok(()) => {
|
||||
log::trace!("Sent U2F packet");
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Error sending U2F packet: {:?}", e);
|
||||
// only run the main loop if the SoC is compatible
|
||||
if usb.is_soc_compatible() {
|
||||
let mut ctap_state = CtapState::new(&mut rng, check_user_presence, boot_time);
|
||||
let mut ctap_hid = CtapHid::new();
|
||||
loop {
|
||||
match usb.u2f_wait_incoming() {
|
||||
Ok(msg) => {
|
||||
log::trace!("FIDO listener got message: {:?}", msg);
|
||||
let now = ClockValue::new(tt.elapsed_ms() as i64, 1000);
|
||||
let reply = ctap_hid.process_hid_packet(&msg.packet, now, &mut ctap_state);
|
||||
// This block handles sending packets.
|
||||
for pkt_reply in reply {
|
||||
let mut reply = RawFidoMsg::default();
|
||||
reply.packet.copy_from_slice(&pkt_reply);
|
||||
let status = usb.u2f_send(reply);
|
||||
match status {
|
||||
Ok(()) => {
|
||||
log::trace!("Sent U2F packet");
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Error sending U2F packet: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
match e {
|
||||
xous::Error::ProcessTerminated => { // unplug happened, reset the authenticator
|
||||
log::info!("CTAP unplug_reset");
|
||||
ctap_state.unplug_reset();
|
||||
},
|
||||
_ => {
|
||||
log::warn!("FIDO listener got an error: {:?}", e);
|
||||
Err(e) => {
|
||||
match e {
|
||||
xous::Error::ProcessTerminated => { // unplug happened, reset the authenticator
|
||||
log::info!("CTAP unplug_reset");
|
||||
ctap_state.unplug_reset();
|
||||
},
|
||||
_ => {
|
||||
log::warn!("FIDO listener got an error: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log::warn!("SoC rev is incompatible with USB HID operations, the U2F/FIDO2 server is not started");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -457,12 +457,28 @@ pub(crate) fn start_fido_ux_thread() {
|
|||
}
|
||||
}
|
||||
};
|
||||
pddb.delete_key(U2F_APP_DICT, &app_id_str, None).ok();
|
||||
match pddb.get(
|
||||
// this get determines which basis the key is in
|
||||
let basis = match pddb.get(
|
||||
U2F_APP_DICT,
|
||||
&app_id_str,
|
||||
None, true, true,
|
||||
Some(256), Some(crate::basis_change)
|
||||
) {
|
||||
Ok(app_data) => {
|
||||
let attr = app_data.attributes().expect("couldn't get attributes");
|
||||
attr.basis
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("error updating app atime: {:?}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
pddb.delete_key(U2F_APP_DICT, &app_id_str, Some(&basis)).ok();
|
||||
match pddb.get(
|
||||
U2F_APP_DICT,
|
||||
&app_id_str,
|
||||
Some(&basis), true, true,
|
||||
Some(256), Some(crate::basis_change)
|
||||
) {
|
||||
Ok(mut app_data) => {
|
||||
app_data.write(&ser).expect("couldn't update atime");
|
||||
|
|
|
|||
|
|
@ -686,14 +686,32 @@ impl VaultUx {
|
|||
return Err(xous::Error::ProcessNotFound);
|
||||
}
|
||||
};
|
||||
match self.pddb.borrow().delete_key(crate::actions::VAULT_PASSWORD_DICT, entry, None) {
|
||||
|
||||
// this get determines which basis the key is in
|
||||
let basis = match self.pddb.borrow().get(
|
||||
crate::actions::VAULT_PASSWORD_DICT,
|
||||
entry,
|
||||
None, true, true,
|
||||
Some(256), Some(crate::basis_change)
|
||||
) {
|
||||
Ok(app_data) => {
|
||||
let attr = app_data.attributes().expect("couldn't get attributes");
|
||||
attr.basis
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("error updating key atime: {:?}", e);
|
||||
return Err(xous::Error::InternalError);
|
||||
}
|
||||
};
|
||||
|
||||
match self.pddb.borrow().delete_key(crate::actions::VAULT_PASSWORD_DICT, entry, Some(&basis)) {
|
||||
Ok(_) => {}
|
||||
Err(_e) => {
|
||||
return Err(xous::Error::InternalError);
|
||||
}
|
||||
}
|
||||
match self.pddb.borrow().get(
|
||||
crate::actions::VAULT_PASSWORD_DICT, entry, None,
|
||||
crate::actions::VAULT_PASSWORD_DICT, entry, Some(&basis),
|
||||
false, true, Some(crate::actions::VAULT_ALLOC_HINT),
|
||||
Some(crate::basis_change)
|
||||
) {
|
||||
|
|
@ -756,5 +774,6 @@ impl VaultUx {
|
|||
}
|
||||
pub(crate) fn ensure_hid(&self) {
|
||||
self.usb_dev.ensure_core(usb_device_xous::UsbDeviceType::Hid).unwrap();
|
||||
self.usb_dev.restrict_debug_access(true).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
@ -717,8 +717,9 @@ pub fn handle_inner(pid: PID, tid: TID, in_irq: bool, call: SysCall) -> SysCallR
|
|||
MemoryRange::new(
|
||||
start,
|
||||
// 0-length MemoryRanges are disallowed -- so return 4096 as the minimum in any case, even though it's a lie
|
||||
if length == 0 { 4096 } else { length }
|
||||
).unwrap()
|
||||
if length == 0 { 4096 } else { length },
|
||||
)
|
||||
.unwrap()
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
@ -920,6 +921,21 @@ pub fn handle_inner(pid: PID, tid: TID, in_irq: bool, call: SysCall) -> SysCallR
|
|||
MemoryManager::with_mut(|mm| mm.update_memory_flags(range, flags))?;
|
||||
Ok(xous_kernel::Result::Ok)
|
||||
}
|
||||
SysCall::AdjustProcessLimit(index, current, new) => match index {
|
||||
1 => arch::process::Process::with_inner_mut(|p| {
|
||||
if p.mem_heap_max == current {
|
||||
p.mem_heap_max = new;
|
||||
}
|
||||
Ok(xous_kernel::Result::Scalar2(index, p.mem_heap_max))
|
||||
}),
|
||||
2 => arch::process::Process::with_inner_mut(|p| {
|
||||
if p.mem_heap_size == current && new < p.mem_heap_max {
|
||||
p.mem_heap_size = new;
|
||||
}
|
||||
Ok(xous_kernel::Result::Scalar2(index, p.mem_heap_size))
|
||||
}),
|
||||
_ => Err(xous_kernel::Error::InvalidLimit),
|
||||
},
|
||||
/* https://github.com/betrusted-io/xous-core/issues/90
|
||||
SysCall::SetExceptionHandler(pc, sp) => SystemServices::with_mut(|ss| {
|
||||
ss.set_exception_handler(pid, pc, sp)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ use std::ops::Deref;
|
|||
* author: nworbnhoj
|
||||
*/
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub struct Bitmap {
|
||||
pub bound: Rectangle,
|
||||
tile_size: Point,
|
||||
|
|
@ -251,8 +251,8 @@ impl From<&Img> for Bitmap {
|
|||
};
|
||||
let mut mosaic: Vec<Tile> = Vec::new();
|
||||
|
||||
let pixels = Dither::new(BURKES.to_vec()).dither(&image);
|
||||
let mut px_index = 0;
|
||||
let words = Dither::new(BURKES.to_vec()).dither(&image);
|
||||
let mut wd_index = 0;
|
||||
let bits_per_word: i16 = BITS_PER_WORD.try_into().unwrap();
|
||||
for t in 0..tile_count {
|
||||
let t_top = t * tile_height;
|
||||
|
|
@ -266,15 +266,8 @@ impl From<&Img> for Bitmap {
|
|||
for y in t_top..=t_bottom {
|
||||
let mut x = t_left;
|
||||
while x <= t_right {
|
||||
let mut word: usize = 0;
|
||||
for w in 0..bits_per_word {
|
||||
if (x + w) > t_right {
|
||||
continue;
|
||||
}
|
||||
let color = pixels[px_index] as usize;
|
||||
word = word | (color << w);
|
||||
px_index += 1;
|
||||
}
|
||||
let word = words[wd_index];
|
||||
wd_index += 1;
|
||||
let anchor = Point::new(x.try_into().unwrap(), y.try_into().unwrap());
|
||||
tile.set_word(anchor, word.try_into().unwrap());
|
||||
x += bits_per_word;
|
||||
|
|
@ -302,7 +295,7 @@ pub enum PixelType {
|
|||
* author: nworbnhoj
|
||||
*/
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub struct Img {
|
||||
pixels: Vec<u8>,
|
||||
width: usize,
|
||||
|
|
@ -360,7 +353,7 @@ impl Img {
|
|||
let y_scale = self_height as f32 / height as f32;
|
||||
let self_x_base = x_scale * 0.5;
|
||||
let self_y_base = y_scale * 0.5;
|
||||
|
||||
|
||||
// Pretabulate horizontal pixel positions
|
||||
let mut self_x_tab: Vec<usize> = Vec::with_capacity(width);
|
||||
for buf_x in 0..width {
|
||||
|
|
@ -476,21 +469,29 @@ impl Dither {
|
|||
PixelColor::Light
|
||||
}
|
||||
}
|
||||
pub fn dither(&mut self, image: &Img) -> Vec<PixelColor> {
|
||||
let (width, height, length) = image.size();
|
||||
pub fn dither(&mut self, image: &Img) -> Vec<Word> {
|
||||
let bits_per_word: u32 = BITS_PER_WORD.try_into().unwrap();
|
||||
let (width, height, _) = image.size();
|
||||
self.provision(width.try_into().unwrap());
|
||||
let mut pixels: Vec<PixelColor> = Vec::with_capacity(length);
|
||||
let mut words: Vec<Word> = Vec::with_capacity((1 + width / BITS_PER_WORD) * height);
|
||||
for y in 0..height {
|
||||
let (mut w, mut word): (Word, Word) = (0, 0);
|
||||
for x in 0..width {
|
||||
let pixel = match image.get(x, y) {
|
||||
let color = match image.get(x, y) {
|
||||
Some(grey) => self.pixel(*grey),
|
||||
None => PixelColor::Dark,
|
||||
};
|
||||
pixels.push(pixel);
|
||||
word = word | ((color as u32) << w);
|
||||
w += 1;
|
||||
if w >= bits_per_word {
|
||||
words.push(word);
|
||||
(w, word) = (0, 0);
|
||||
}
|
||||
self.next();
|
||||
}
|
||||
words.push(word);
|
||||
}
|
||||
pixels
|
||||
words
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -163,8 +163,8 @@ pub fn spawn_test() {
|
|||
*/
|
||||
#[cfg(feature = "ditherpunk")]
|
||||
{
|
||||
log::info!("testing image");
|
||||
let img = clifford();
|
||||
log::info!("showing image");
|
||||
modals.show_image(&img).expect("show image modal failed");
|
||||
log::info!("image modal test done");
|
||||
}
|
||||
|
|
@ -181,7 +181,8 @@ fn clifford() -> Img {
|
|||
let mut buf = vec![255u8; (SIZE * SIZE).try_into().unwrap()];
|
||||
let (a, b, c, d) = (-2.0, -2.4, 1.1, -0.9);
|
||||
let (mut x, mut y): (f32, f32) = (0.0, 0.0);
|
||||
for _ in 0..=4000000 {
|
||||
log::info!("generating image");
|
||||
for _ in 0..=400000 { // this takes a couple minutes to run
|
||||
let x1 = f32::sin(a * y) + c * f32::cos(a * x);
|
||||
let y1 = f32::sin(b * x) + d * f32::cos(b * y);
|
||||
(x, y) = (x1, y1);
|
||||
|
|
@ -191,6 +192,7 @@ fn clifford() -> Img {
|
|||
buf[i] -= 1;
|
||||
}
|
||||
}
|
||||
log::info!("done: {:x?}", &buf[..32]);
|
||||
Img::new(buf, SIZE.try_into().unwrap(), PixelType::U8)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -423,8 +423,6 @@ fn main() -> ! {
|
|||
let pddb_sid = xns.register_name(api::SERVER_NAME_PDDB, None).expect("can't register server");
|
||||
log::trace!("registered with NS -- {:?}", pddb_sid);
|
||||
|
||||
log::trace!("ready to accept requests");
|
||||
|
||||
// shared entropy cache across all process-local services (it's more efficient to request entropy in blocks from the TRNG)
|
||||
let entropy = Rc::new(RefCell::new(TrngPool::new()));
|
||||
|
||||
|
|
@ -542,8 +540,11 @@ fn main() -> ! {
|
|||
let mut initial_heap: usize = 0;
|
||||
let mut latest_heap: usize = 0;
|
||||
let mut latest_cache: usize = 0;
|
||||
const HEAP_GC_THRESH: usize = 400 * 1024; // the heap breaks at 512kiB, so try cleaning up at 400k
|
||||
const HEAP_GC_TARGET: usize = 64 * 1024; // how much to try cleaning out in any one go.
|
||||
const HEAP_LARGER_LIMIT: usize = 2048 * 1024;
|
||||
const HEAP_GC_THRESH: usize = 1500 * 1024; // the largel limit is at 2048kiB, so try cleaning up at 1500k
|
||||
const HEAP_GC_TARGET: usize = 1024 * 1024; // how much to try cleaning out in any one go.
|
||||
const HEAP_INC_THRESH: usize = 256 * 1024; // increase from the default heap size of 512k if we pass this limit
|
||||
let mut heap_increased = false;
|
||||
|
||||
// register a suspend/resume listener
|
||||
let mut susres = susres::Susres::new(Some(susres::SuspendOrder::Early), &xns,
|
||||
|
|
@ -634,6 +635,31 @@ fn main() -> ! {
|
|||
latest_heap = heap_usage();
|
||||
log::info!("{} pruned, now: {} heap, {} cache", pruned, latest_heap, basis_cache.cache_size())
|
||||
}
|
||||
|
||||
// one-shot increase of heap limit once we pass a threshold
|
||||
// we don't put this at the very top of main because there may be some concurrency issue
|
||||
// if a heap increase is attempted while a lot of new processes are spawning.
|
||||
if (latest_heap > HEAP_INC_THRESH) && !heap_increased {
|
||||
let new_limit = HEAP_LARGER_LIMIT;
|
||||
let result = xous::rsyscall(xous::SysCall::AdjustProcessLimit(
|
||||
xous::Limits::HeapMaximum as usize,
|
||||
0,
|
||||
new_limit,
|
||||
));
|
||||
|
||||
if let Ok(xous::Result::Scalar2(1, current_limit)) = result {
|
||||
xous::rsyscall(xous::SysCall::AdjustProcessLimit(
|
||||
xous::Limits::HeapMaximum as usize,
|
||||
current_limit,
|
||||
new_limit,
|
||||
))
|
||||
.unwrap();
|
||||
log::info!("Heap limit increased to: {}", new_limit);
|
||||
} else {
|
||||
panic!("Unsupported syscall!");
|
||||
}
|
||||
heap_increased = true;
|
||||
}
|
||||
}
|
||||
Some(Opcode::ListBasis) => {
|
||||
let mut buffer = unsafe { Buffer::from_memory_message_mut(msg.body.memory_message_mut().unwrap()) };
|
||||
|
|
|
|||
|
|
@ -289,6 +289,25 @@ impl<'a> ShellCmdApi<'a> for NetCmd {
|
|||
}
|
||||
#[cfg(feature="ditherpunk")]
|
||||
"image" => {
|
||||
let new_limit = 2048 * 1024;
|
||||
let result = xous::rsyscall(xous::SysCall::AdjustProcessLimit(
|
||||
xous::Limits::HeapMaximum as usize,
|
||||
0,
|
||||
new_limit,
|
||||
));
|
||||
|
||||
if let Ok(xous::Result::Scalar2(1, current_limit)) = result {
|
||||
xous::rsyscall(xous::SysCall::AdjustProcessLimit(
|
||||
xous::Limits::HeapMaximum as usize,
|
||||
current_limit,
|
||||
new_limit,
|
||||
))
|
||||
.unwrap();
|
||||
log::info!("Our new heap is: {}", new_limit);
|
||||
} else {
|
||||
panic!("Unsupported syscall!");
|
||||
}
|
||||
|
||||
#[cfg(feature="tracking-alloc")]
|
||||
use tracking_allocator::{
|
||||
AllocationGroupToken, AllocationRegistry,
|
||||
|
|
@ -360,7 +379,7 @@ impl<'a> ShellCmdApi<'a> for NetCmd {
|
|||
} else {
|
||||
if len < last_chunk {
|
||||
log::info!("heuristic termination of read loop");
|
||||
// break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -362,7 +362,7 @@ fn main () -> ! {
|
|||
wrapped_main();
|
||||
|
||||
#[cfg(feature="ditherpunk")]
|
||||
let stack_size = 1024 * 1024;
|
||||
let stack_size = 2048 * 1024;
|
||||
#[cfg(feature="ditherpunk")]
|
||||
std::thread::Builder::new()
|
||||
.stack_size(stack_size)
|
||||
|
|
|
|||
|
|
@ -530,7 +530,7 @@ fn wrapped_main() -> ! {
|
|||
let (latest_activity, period) = llio
|
||||
.activity_instantaneous()
|
||||
.expect("couldn't get CPU activity");
|
||||
let activity_to_width = (((latest_activity * 1000) / (period)) * (cpuload_rect.width() - 4) as u32) / 1000;
|
||||
let activity_to_width = ((latest_activity as u64) * 1000u64 * (cpuload_rect.width() as u64 - 4)) / (period as u64 * 1000u64);
|
||||
draw_list.push(GamObjectType::Rect(
|
||||
Rectangle::new_coords_with_style(
|
||||
cpuload_rect.tl().x + 2,
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@ pub(crate) enum Opcode {
|
|||
/// Blocks the caller, waiting for a U2F message
|
||||
U2fRxDeferred,
|
||||
|
||||
/// Query if the HID driver was able to start
|
||||
IsSocCompatible,
|
||||
|
||||
/// Handle the USB interrupt
|
||||
UsbIrqHandler,
|
||||
/// Suspend/resume callback
|
||||
|
|
|
|||
|
|
@ -29,6 +29,24 @@ impl UsbHid {
|
|||
conn
|
||||
}
|
||||
}
|
||||
/// used to query if the HID core was able to start. Mainly to handle edge cases between updates.
|
||||
pub fn is_soc_compatible(&self) -> bool {
|
||||
match send_message(
|
||||
self.conn,
|
||||
Message::new_blocking_scalar(
|
||||
Opcode::IsSocCompatible.to_usize().unwrap(),
|
||||
0, 0, 0, 0
|
||||
)
|
||||
) {
|
||||
Ok(xous::Result::Scalar1(code)) => {
|
||||
match code {
|
||||
0 => false,
|
||||
_ => true
|
||||
}
|
||||
}
|
||||
_ => panic!("Internal error: illegal return type"),
|
||||
}
|
||||
}
|
||||
/// this will always trigger a reset, even if it's the same core we're switching to
|
||||
pub fn switch_to_core(&self, core: UsbDeviceType) -> Result<(), xous::Error> {
|
||||
match send_message(
|
||||
|
|
|
|||
|
|
@ -112,6 +112,9 @@ fn main() -> ! {
|
|||
// block any rx requests forever
|
||||
fido_listener = Some(msg);
|
||||
}
|
||||
Some(Opcode::IsSocCompatible) => msg_blocking_scalar_unpack!(msg, _, _, _, _, {
|
||||
xous::return_scalar(msg.sender, 0).expect("couldn't return compatibility status")
|
||||
}),
|
||||
Some(Opcode::Quit) => {
|
||||
break;
|
||||
}
|
||||
|
|
@ -177,7 +180,7 @@ fn main() -> ! {
|
|||
{
|
||||
let keyboard = composite.interface::<NKROBootKeyboardInterface<'_, _, _,>, _>();
|
||||
keyboard.write_report(&Vec::<Keyboard>::new()).ok();
|
||||
keyboard.tick().unwrap();
|
||||
keyboard.tick().ok();
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "none", target_os = "xous"))]
|
||||
|
|
@ -200,6 +203,9 @@ fn main() -> ! {
|
|||
usbmgmt.xous_resume();
|
||||
lockstatus_force_update = true; // notify the status bar that yes, it does need to redraw the lock status, even if the value hasn't changed since the last read
|
||||
}),
|
||||
Some(Opcode::IsSocCompatible) => msg_blocking_scalar_unpack!(msg, _, _, _, _, {
|
||||
xous::return_scalar(msg.sender, 1).expect("couldn't return compatibility status")
|
||||
}),
|
||||
Some(Opcode::U2fRxDeferred) => {
|
||||
if fido_listener_pid.is_none() {
|
||||
fido_listener_pid = msg.sender.pid();
|
||||
|
|
@ -408,11 +414,11 @@ fn main() -> ! {
|
|||
{
|
||||
let keyboard = composite.interface::<NKROBootKeyboardInterface<'_, _, _,>, _>();
|
||||
keyboard.write_report(&codes).ok();
|
||||
keyboard.tick().unwrap();
|
||||
keyboard.tick().ok();
|
||||
tt.sleep_ms(30).ok();
|
||||
if auto_up {
|
||||
keyboard.write_report(&[]).ok(); // this is the key-up
|
||||
keyboard.tick().unwrap();
|
||||
keyboard.tick().ok();
|
||||
tt.sleep_ms(30).ok();
|
||||
}
|
||||
}
|
||||
|
|
@ -444,10 +450,10 @@ fn main() -> ! {
|
|||
{
|
||||
let keyboard = composite.interface::<NKROBootKeyboardInterface<'_, _, _,>, _>();
|
||||
keyboard.write_report(&codes).ok();
|
||||
keyboard.tick().unwrap();
|
||||
keyboard.tick().ok();
|
||||
tt.sleep_ms(30).ok();
|
||||
keyboard.write_report(&[]).ok(); // this is the key-up
|
||||
keyboard.tick().unwrap();
|
||||
keyboard.tick().ok();
|
||||
tt.sleep_ms(30).ok();
|
||||
}
|
||||
sent += 1;
|
||||
|
|
|
|||
|
|
@ -75,6 +75,9 @@ pub use memoryflags::*;
|
|||
pub mod messages;
|
||||
pub use messages::*;
|
||||
|
||||
pub mod limits;
|
||||
pub use limits::*;
|
||||
|
||||
use crate::arch::ProcessStartup;
|
||||
|
||||
/// Server ID
|
||||
|
|
@ -194,6 +197,7 @@ pub enum Error {
|
|||
UseBeforeInit = 24,
|
||||
DoubleFree = 25,
|
||||
DebugInProgress = 26,
|
||||
InvalidLimit = 27,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
|
|
@ -226,6 +230,7 @@ impl Error {
|
|||
24 => UseBeforeInit,
|
||||
25 => DoubleFree,
|
||||
26 => DebugInProgress,
|
||||
27 => InvalidLimit,
|
||||
_ => UnknownError,
|
||||
}
|
||||
}
|
||||
|
|
@ -258,6 +263,7 @@ impl Error {
|
|||
UseBeforeInit => 24,
|
||||
DoubleFree => 25,
|
||||
DebugInProgress => 26,
|
||||
InvalidLimit => 27,
|
||||
UnknownError => usize::MAX,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
5
xous-rs/src/definitions/limits.rs
Normal file
5
xous-rs/src/definitions/limits.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#[repr(usize)]
|
||||
pub enum Limits {
|
||||
HeapMaximum = 1,
|
||||
HeapSize = 2,
|
||||
}
|
||||
|
|
@ -427,6 +427,36 @@ pub enum SysCall {
|
|||
usize, /* stack pointer */
|
||||
),
|
||||
|
||||
/// Adjust one of the limits within this process. Note that you must pass
|
||||
/// the current limit value in order to set the new limit. The current limit
|
||||
/// value is always returned, so this function may need to be called twice --
|
||||
/// once in order to get the current limit, and again to set the new limit.
|
||||
///
|
||||
/// ## Arguments
|
||||
///
|
||||
/// * **Index**: The item to adjust. Currently the following limits
|
||||
/// are supported:
|
||||
/// 1: Maximum heap size
|
||||
/// 2: Current heap size
|
||||
/// * **Current Limit**: Pass the current limit value here. The current
|
||||
/// limit must match in order for the new limit to take
|
||||
/// effect. This is used to avoid a race condition if two
|
||||
/// threads try to set the same limit.
|
||||
/// * **Proposed Limit**: The new value that you would like to use.
|
||||
///
|
||||
/// ## Returns
|
||||
///
|
||||
/// Returns a Scalar2 containing `(Index, Limit)`.
|
||||
///
|
||||
/// ## Errors
|
||||
///
|
||||
/// * **InvalidLimit**: The specified index was not valid
|
||||
AdjustProcessLimit(
|
||||
usize, /* process limit index */
|
||||
usize, /* expected current limit */
|
||||
usize, /* proposed new limit */
|
||||
),
|
||||
|
||||
/// This syscall does not exist. It captures all possible
|
||||
/// arguments so detailed analysis can be performed.
|
||||
Invalid(usize, usize, usize, usize, usize, usize, usize),
|
||||
|
|
@ -470,6 +500,7 @@ pub enum SysCallNumber {
|
|||
Disconnect = 35,
|
||||
JoinThread = 36,
|
||||
SetExceptionHandler = 37,
|
||||
AdjustProcessLimit = 38,
|
||||
Invalid,
|
||||
}
|
||||
|
||||
|
|
@ -513,6 +544,7 @@ impl SysCallNumber {
|
|||
35 => Disconnect,
|
||||
36 => JoinThread,
|
||||
37 => SetExceptionHandler,
|
||||
38 => AdjustProcessLimit,
|
||||
_ => Invalid,
|
||||
}
|
||||
}
|
||||
|
|
@ -867,6 +899,16 @@ impl SysCall {
|
|||
0,
|
||||
0,
|
||||
],
|
||||
SysCall::AdjustProcessLimit(index, current, new) => [
|
||||
SysCallNumber::AdjustProcessLimit as usize,
|
||||
*index,
|
||||
*current,
|
||||
*new,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
SysCall::Invalid(a1, a2, a3, a4, a5, a6, a7) => [
|
||||
SysCallNumber::Invalid as usize,
|
||||
*a1,
|
||||
|
|
@ -1030,6 +1072,7 @@ impl SysCall {
|
|||
SysCallNumber::Disconnect => SysCall::Disconnect(a1 as _),
|
||||
SysCallNumber::JoinThread => SysCall::JoinThread(a1 as _),
|
||||
SysCallNumber::SetExceptionHandler => SysCall::SetExceptionHandler(a1 as _, a2 as _),
|
||||
SysCallNumber::AdjustProcessLimit => SysCall::AdjustProcessLimit(a1, a2, a3),
|
||||
SysCallNumber::Invalid => SysCall::Invalid(a1, a2, a3, a4, a5, a6, a7),
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue