From d277ae955191d4da24333c11027a297106554752 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gianguido=20Sor=C3=A0?= Date: Fri, 4 Nov 2022 17:31:27 +0100 Subject: [PATCH 1/8] feat: show boot process notifications for PDDB This commit shows two notifications: 1. as soon as the device boots, a notification greets the user and tells them everything is fine, the device is booting 2. as soon as the user enters (or doesn't) enter the password, a notification tell the user Xous is loading and mounting PDDB I spent too much time on this but I believe it's a nice UX improvement. --- services/pddb/src/main.rs | 40 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/services/pddb/src/main.rs b/services/pddb/src/main.rs index 4e4944e70..2f31e039b 100644 --- a/services/pddb/src/main.rs +++ b/services/pddb/src/main.rs @@ -394,7 +394,7 @@ use std::collections::{HashMap, BTreeSet}; use std::io::ErrorKind; use core::fmt::Write; use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use locales::t; @@ -490,6 +490,34 @@ fn wrapped_main() -> ! { } }); + let hide_startingup_notif = Arc::new(Mutex::new(false)); + let hide_startingup_notif_clone = hide_startingup_notif.clone(); + + std::thread::spawn(move || { + // For some weird reason spawning a dynamic notification without waiting 800ms in a separate thread + // makes it impossible to read, because it gets covered by hundreds of those modal security lines (???). + // This thread waits on hide_startingup_notif to become true, then disimsses the dynamic notification that it created + // previously. + // To allow other threads to do work, yield to kernel every time the variable is read as false. + + let xns = xous_names::XousNames::new().unwrap(); + let modals = modals::Modals::new(&xns).expect("can't connect to Modals server"); + + std::thread::sleep(std::time::Duration::from_millis(1000)); + + modals.dynamic_notification(Some("Starting up..."), Some("Precursor is booting up, please wait.")).unwrap(); + + loop { + if *hide_startingup_notif_clone.lock().unwrap() { + modals.dynamic_notification_close().unwrap(); + break; + } + + xous::yield_slice(); + }; + }); + + // OS-specific PDDB driver let mut pddb_os = PddbOs::new(Rc::clone(&entropy), pw_cid); // storage for the basis cache @@ -656,6 +684,8 @@ fn wrapped_main() -> ! { // - code = 2 -> mount failed, because too many PINs were retried. `count` is the number of retries. // If we need more nuance out of this routine, consider creating a custom public enum type to help marshall this. Opcode::TryMount => xous::msg_blocking_scalar_unpack!(msg, _, _, _, _, { + *hide_startingup_notif.lock().unwrap() = true; + if basis_cache.basis_count() > 0 { xous::return_scalar2(msg.sender, 0, 0).expect("couldn't return scalar"); } else { @@ -669,6 +699,8 @@ fn wrapped_main() -> ! { } else { match ensure_password(&modals, &mut pddb_os, pw_cid) { PasswordState::Correct => { + modals.dynamic_notification(Some("Starting up..."), Some("Mounting PDDB, please wait.")).unwrap(); + if try_mount_or_format(&modals, &mut pddb_os, &mut basis_cache, PasswordState::Correct, time_resetter) { is_mounted.store(true, Ordering::SeqCst); for requester in mount_notifications.drain(..) { @@ -680,8 +712,12 @@ fn wrapped_main() -> ! { } else { xous::return_scalar2(msg.sender, 1, 0).expect("couldn't return scalar"); } + + modals.dynamic_notification_close().unwrap(); }, PasswordState::Uninit => { + modals.dynamic_notification(Some("Starting up..."), Some("Mounting PDDB, please wait.")).unwrap(); + if try_mount_or_format(&modals, &mut pddb_os, &mut basis_cache, PasswordState::Uninit, time_resetter) { for requester in mount_notifications.drain(..) { xous::return_scalar2(requester, 0, 0).expect("couldn't return scalar"); @@ -693,6 +729,8 @@ fn wrapped_main() -> ! { } else { xous::return_scalar2(msg.sender, 1, 0).expect("couldn't return scalar"); } + + modals.dynamic_notification_close().unwrap(); }, PasswordState::ForcedAbort(failcount) => { xous::return_scalar2(msg.sender, 2, From 7c4ca05922a06ca2e366f89ee1011404ced71c9b Mon Sep 17 00:00:00 2001 From: bunnie Date: Sat, 5 Nov 2022 23:06:18 +0800 Subject: [PATCH 2/8] adjust modal trust level down so it's not identical to chat --- services/gam/src/layouts/modal.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/gam/src/layouts/modal.rs b/services/gam/src/layouts/modal.rs index 76b0803b0..1c432743c 100644 --- a/services/gam/src/layouts/modal.rs +++ b/services/gam/src/layouts/modal.rs @@ -8,7 +8,7 @@ use graphics_server::*; use crate::{LayoutApi, LayoutBehavior}; use crate::contexts::MISC_CONTEXT_DEFAULT_TRUST; -const TRUST_OFFSET: u8 = 1; +const TRUST_OFFSET: u8 = 16; #[derive(Debug, Copy, Clone)] pub(crate) struct ModalLayout { From 45009a01d95b6449c4d59456b91a6fd2b08f3a7f Mon Sep 17 00:00:00 2001 From: bunnie Date: Sat, 5 Nov 2022 23:06:47 +0800 Subject: [PATCH 3/8] add debugging hints for figuring out context switch bugs in the future --- services/gam/src/contexts.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/gam/src/contexts.rs b/services/gam/src/contexts.rs index c45bc1241..b50647c3d 100644 --- a/services/gam/src/contexts.rs +++ b/services/gam/src/contexts.rs @@ -330,6 +330,7 @@ impl ContextManager { token: [u32; 4], clear: bool, ) -> Result<(), xous::Error> { + //log::set_max_level(log::LevelFilter::Trace); self.notify_app_switch(token).ok(); let mut leaving_visibility: bool = false; @@ -483,6 +484,7 @@ impl ContextManager { self.redraw().expect("couldn't redraw the currently focused app"); } } + //log::set_max_level(log::LevelFilter::Info); Ok(()) } pub(crate) fn set_pred_api_token(&mut self, at: ApiToken) { From 0d02415c82db51523d3051065e91e97fb663eb7c Mon Sep 17 00:00:00 2001 From: bunnie Date: Sun, 6 Nov 2022 03:05:30 +0800 Subject: [PATCH 4/8] remove automounter from the status thread it's now in shellchat. In general, the program that is assigned as the initial app context is responsible for ensuring the PDDB is mounted. Thus, if `vault` were to become a stand-alone app, it should include some code to make sure the PDDB is mounted as part of its boot sequence. The reason is that it allows the initial app to guide the power-on experience, instead of delegating this to the `status` bar, which is oblivious to the state of the app. --- services/status/src/main.rs | 35 ----------------------------------- 1 file changed, 35 deletions(-) diff --git a/services/status/src/main.rs b/services/status/src/main.rs index ec77fb239..b9c592242 100644 --- a/services/status/src/main.rs +++ b/services/status/src/main.rs @@ -633,41 +633,6 @@ fn wrapped_main() -> ! { #[cfg(any(feature="precursor", feature="renode"))] llio.clear_wakeup_alarm().unwrap(); // this is here to clear any wake-up alarms that were set by a prior coldboot command - // spawn a thread to auto-mount the PDDB - let _ = thread::spawn({ - move || { - let tt = ticktimer_server::Ticktimer::new().unwrap(); - tt.sleep_ms(2000).unwrap(); // a brief pause, to allow the other startup bits to finish running - loop { - let (no_retry_failure, count) = pddb::Pddb::new().try_mount(); - if no_retry_failure { - // this includes both successfully mounted, and user abort of mount attempt - break; - } else { - // this indicates system was guttered due to a retry failure - let xns = xous_names::XousNames::new().unwrap(); - let susres = susres::Susres::new_without_hook(&xns).unwrap(); - let llio = llio::Llio::new(&xns); - if ((llio.adc_vbus().unwrap() as u32) * 503) < 150_000 { - // try to force suspend if possible, so that users who are just playing around with - // the device don't run the battery down accidentally. - susres.initiate_suspend().ok(); - tt.sleep_ms(1000).unwrap(); - let modals = modals::Modals::new(&xns).unwrap(); - modals.show_notification( - &t!("login.fail", xous::LANG).replace("{fails}", &count.to_string()), - None - ).ok(); - } else { - // otherwise force a reboot cycle to slow down guessers - susres.reboot(true).expect("Couldn't reboot after too many failed password attempts"); - tt.sleep_ms(5000).unwrap(); - } - } - } - } - }); - pump_run.store(true, Ordering::Relaxed); // start status thread updating loop { let msg = xous::receive_message(status_sid).unwrap(); From 7eecf2b1ceea0dc74d8826dd26dc92469a88646a Mon Sep 17 00:00:00 2001 From: bunnie Date: Sun, 6 Nov 2022 03:07:35 +0800 Subject: [PATCH 5/8] remove the initial wait from PDDB; move the pop-up modal location The initial wait message is now rendered by the first app that owns the screen (currently shellchat). The location where the pop-up modal is rendered is also now bracketed directly around the mount call to avoid interference with other edge cases that may pop up modals. --- services/pddb/locales/i18n.json | 7 +++++ services/pddb/src/main.rs | 47 +++++---------------------------- 2 files changed, 14 insertions(+), 40 deletions(-) diff --git a/services/pddb/locales/i18n.json b/services/pddb/locales/i18n.json index f24517070..d7d59450e 100644 --- a/services/pddb/locales/i18n.json +++ b/services/pddb/locales/i18n.json @@ -13,6 +13,13 @@ "ja": "パスワードを認証失敗でした。\n\nもう一度実行しください。", "zh": "密码错误。" }, + "pddb.waitmount": { + "en": "Mounting PDDB, please wait...", + "en-tts": "Mounting PDDB, please wait...", + "fr": "Montage de PDDB, veuillez patienter...*MT*", + "ja": "PDDB をマウントしています。お待ちください...", + "zh": "正在挂载 PDDB,请稍候..." + }, "pddb.basisname": { "en": "Basis Name:", "en-tts": "Enter name of Basis", diff --git a/services/pddb/src/main.rs b/services/pddb/src/main.rs index 2f31e039b..6e8773aee 100644 --- a/services/pddb/src/main.rs +++ b/services/pddb/src/main.rs @@ -394,7 +394,7 @@ use std::collections::{HashMap, BTreeSet}; use std::io::ErrorKind; use core::fmt::Write; use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use locales::t; @@ -490,34 +490,6 @@ fn wrapped_main() -> ! { } }); - let hide_startingup_notif = Arc::new(Mutex::new(false)); - let hide_startingup_notif_clone = hide_startingup_notif.clone(); - - std::thread::spawn(move || { - // For some weird reason spawning a dynamic notification without waiting 800ms in a separate thread - // makes it impossible to read, because it gets covered by hundreds of those modal security lines (???). - // This thread waits on hide_startingup_notif to become true, then disimsses the dynamic notification that it created - // previously. - // To allow other threads to do work, yield to kernel every time the variable is read as false. - - let xns = xous_names::XousNames::new().unwrap(); - let modals = modals::Modals::new(&xns).expect("can't connect to Modals server"); - - std::thread::sleep(std::time::Duration::from_millis(1000)); - - modals.dynamic_notification(Some("Starting up..."), Some("Precursor is booting up, please wait.")).unwrap(); - - loop { - if *hide_startingup_notif_clone.lock().unwrap() { - modals.dynamic_notification_close().unwrap(); - break; - } - - xous::yield_slice(); - }; - }); - - // OS-specific PDDB driver let mut pddb_os = PddbOs::new(Rc::clone(&entropy), pw_cid); // storage for the basis cache @@ -684,8 +656,6 @@ fn wrapped_main() -> ! { // - code = 2 -> mount failed, because too many PINs were retried. `count` is the number of retries. // If we need more nuance out of this routine, consider creating a custom public enum type to help marshall this. Opcode::TryMount => xous::msg_blocking_scalar_unpack!(msg, _, _, _, _, { - *hide_startingup_notif.lock().unwrap() = true; - if basis_cache.basis_count() > 0 { xous::return_scalar2(msg.sender, 0, 0).expect("couldn't return scalar"); } else { @@ -699,8 +669,6 @@ fn wrapped_main() -> ! { } else { match ensure_password(&modals, &mut pddb_os, pw_cid) { PasswordState::Correct => { - modals.dynamic_notification(Some("Starting up..."), Some("Mounting PDDB, please wait.")).unwrap(); - if try_mount_or_format(&modals, &mut pddb_os, &mut basis_cache, PasswordState::Correct, time_resetter) { is_mounted.store(true, Ordering::SeqCst); for requester in mount_notifications.drain(..) { @@ -712,12 +680,8 @@ fn wrapped_main() -> ! { } else { xous::return_scalar2(msg.sender, 1, 0).expect("couldn't return scalar"); } - - modals.dynamic_notification_close().unwrap(); }, PasswordState::Uninit => { - modals.dynamic_notification(Some("Starting up..."), Some("Mounting PDDB, please wait.")).unwrap(); - if try_mount_or_format(&modals, &mut pddb_os, &mut basis_cache, PasswordState::Uninit, time_resetter) { for requester in mount_notifications.drain(..) { xous::return_scalar2(requester, 0, 0).expect("couldn't return scalar"); @@ -729,8 +693,6 @@ fn wrapped_main() -> ! { } else { xous::return_scalar2(msg.sender, 1, 0).expect("couldn't return scalar"); } - - modals.dynamic_notification_close().unwrap(); }, PasswordState::ForcedAbort(failcount) => { xous::return_scalar2(msg.sender, 2, @@ -1965,11 +1927,14 @@ fn ensure_password(modals: &modals::Modals, pddb_os: &mut PddbOs, _pw_cid: xous: fn try_mount_or_format(modals: &modals::Modals, pddb_os: &mut PddbOs, basis_cache: &mut BasisCache, pw_state: PasswordState, time_resetter: xous::CID) -> bool { log::info!("Attempting to mount the PDDB"); if pw_state == PasswordState::Correct { + modals.dynamic_notification(Some(t!("pddb.waitmount", xous::LANG)), None).unwrap(); if let Some(sys_basis) = pddb_os.pddb_mount() { log::info!("PDDB mount operation finished successfully"); basis_cache.basis_add(sys_basis); + modals.dynamic_notification_close().unwrap(); return true } + modals.dynamic_notification_close().unwrap(); } // correct password but no mount -> offer to format; uninit -> offer to format if pw_state == PasswordState::Correct || pw_state == PasswordState::Uninit { @@ -2026,12 +1991,14 @@ fn try_mount_or_format(modals: &modals::Modals, pddb_os: &mut PddbOs, basis_cach 0, 0, 0, 0 ) ).expect("couldn't reset time"); - + modals.dynamic_notification(Some(t!("pddb.waitmount", xous::LANG)), None).unwrap(); if let Some(sys_basis) = pddb_os.pddb_mount() { log::info!("PDDB mount operation finished successfully"); basis_cache.basis_add(sys_basis); + modals.dynamic_notification_close().unwrap(); true } else { + modals.dynamic_notification_close().unwrap(); log::error!("Despite formatting, no PDDB was found!"); let mut err = String::from(t!("pddb.internalerror", xous::LANG)); err.push_str(" #1"); // punt and leave an error code, because this "should" be rare From e240ca64992ab0e805ae53f391ae37f558271ca3 Mon Sep 17 00:00:00 2001 From: bunnie Date: Sun, 6 Nov 2022 03:10:00 +0800 Subject: [PATCH 6/8] refactor the hardware boot screen - remove a blanking operation. this makes the transision from loader to runtime almost imperceptably smoother - add the ability to summon the logo screen earlier in the process Note that only GAM can call GFX, so, it's alright to expose that API, since GAM should gate-keep and prevent abuse of that function. --- services/graphics-server/src/api.rs | 3 +++ services/graphics-server/src/backend/betrusted.rs | 3 ++- services/graphics-server/src/lib.rs | 8 ++++++++ services/graphics-server/src/main.rs | 8 ++++++-- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/services/graphics-server/src/api.rs b/services/graphics-server/src/api.rs index b83abe479..9fc8232c5 100644 --- a/services/graphics-server/src/api.rs +++ b/services/graphics-server/src/api.rs @@ -119,6 +119,9 @@ pub(crate) enum Opcode { /// SuspendResume callback SuspendResume, + /// draw the boot logo (for continuity as apps initialize) + DrawBootLogo, + Quit, } diff --git a/services/graphics-server/src/backend/betrusted.rs b/services/graphics-server/src/backend/betrusted.rs index fe0125510..120c87571 100644 --- a/services/graphics-server/src/backend/betrusted.rs +++ b/services/graphics-server/src/backend/betrusted.rs @@ -68,7 +68,6 @@ impl XousDisplay { display .susres .push(RegOrField::Field(utra::memlcd::PRESCALER_PRESCALER), None); - display.sync_clear(); /* use log::{error, info}; @@ -255,6 +254,7 @@ impl XousDisplay { /// "synchronous clear" -- must be called on init, so that the state of the LCD /// internal memory is consistent with the state of the frame buffer + /* fn sync_clear(&mut self) { let framebuffer = self.fb.as_mut_ptr() as *mut u32; for words in 0..FB_SIZE { @@ -267,6 +267,7 @@ impl XousDisplay { self.update_all(); // because we force an all update here while self.busy() {} } + */ fn busy(&self) -> bool { self.csr.rf(utra::memlcd::BUSY_BUSY) == 1 diff --git a/services/graphics-server/src/lib.rs b/services/graphics-server/src/lib.rs index f895b230c..e98db6bbc 100644 --- a/services/graphics-server/src/lib.rs +++ b/services/graphics-server/src/lib.rs @@ -108,6 +108,14 @@ impl Gfx { .map(|_| ()) } + pub fn draw_boot_logo(&self) -> Result<(), xous::Error> { + send_message( + self.conn, + Message::new_scalar(Opcode::DrawBootLogo.to_usize().unwrap(), 0, 0, 0, 0), + ) + .map(|_| ()) + } + pub fn screen_size(&self) -> Result { let response = send_message( self.conn, diff --git a/services/graphics-server/src/main.rs b/services/graphics-server/src/main.rs index 00029f6cc..a0bb3181f 100644 --- a/services/graphics-server/src/main.rs +++ b/services/graphics-server/src/main.rs @@ -112,6 +112,7 @@ fn wrapped_main() -> ! { log::info!("my PID is {}", xous::process::id()); let mut display = XousDisplay::new(); + draw_boot_logo(&mut display); // bring this up as soon as possible let fontregion = map_fonts(); // install the graphical panic handler. It won't catch really early panics, or panics in this crate, @@ -139,8 +140,6 @@ fn wrapped_main() -> ! { .register_name(api::SERVER_NAME_GFX, Some(1)) .expect("can't register server"); - draw_boot_logo(&mut display); - let screen_clip = Rectangle::new(Point::new(0, 0), display.screen_size()); display.redraw(); @@ -459,6 +458,11 @@ fn wrapped_main() -> ! { display.update(); display.redraw(); }), + Some(Opcode::DrawBootLogo) => msg_scalar_unpack!(msg, _, _, _, _, { + display.blit_screen(&poweron::LOGO_MAP); + display.update(); + display.redraw(); + }), Some(Opcode::Devboot) => msg_scalar_unpack!(msg, ena, _, _, _, { if ena != 0 { display.set_devboot(true); From a56b8c802fc804b464036823b8f3a979b8ab1894 Mon Sep 17 00:00:00 2001 From: bunnie Date: Sun, 6 Nov 2022 03:11:23 +0800 Subject: [PATCH 7/8] add automounter to shellchat, and initial wait message The initial wait message is drawn directly under where the modals would appear, so the message "goes away" when modals pop up. There's still a bit of trickiness around the timing of some of the calls. Attempting to mount the PDDB too early before all the contexts have been registered leads to a lot of needless defacing. Also, the final redraw needs a short delay to allow the system to foreground shellchat again after closing the modals. --- services/shellchat/locales/i18n.json | 7 +++ services/shellchat/src/main.rs | 82 +++++++++++++++++++++++++--- 2 files changed, 82 insertions(+), 7 deletions(-) diff --git a/services/shellchat/locales/i18n.json b/services/shellchat/locales/i18n.json index 7560abb66..8854bab5d 100644 --- a/services/shellchat/locales/i18n.json +++ b/services/shellchat/locales/i18n.json @@ -12,5 +12,12 @@ "fr": "", "ja": "", "zh": "" + }, + "shellchat.bootwait": { + "en": "Please wait...", + "en-tts": "Please wait...", + "fr": "S'il vous plaît, attendez*MT*", + "ja": "お待ちください...", + "zh": "请稍等..." } } diff --git a/services/shellchat/src/main.rs b/services/shellchat/src/main.rs index 85e5d5bc6..11ab93350 100644 --- a/services/shellchat/src/main.rs +++ b/services/shellchat/src/main.rs @@ -32,6 +32,7 @@ Check for more detailed docs under Modules/cmds "Shell Chat" below use log::info; use core::fmt::Write; +use core::sync::atomic::{AtomicBool, Ordering}; use gam::UxRegistration; use graphics_server::{Gid, Point, Rectangle, TextBounds, TextView, DrawStyle, PixelColor}; @@ -39,6 +40,10 @@ use graphics_server::api::GlyphStyle; use xous::MessageEnvelope; use xous_ipc::Buffer; +use locales::t; +use std::thread; +use std::sync::Arc; + #[doc = include_str!("../README.md")] mod cmds; use cmds::*; @@ -202,7 +207,7 @@ impl Repl{ } /// update the loop, in response to various inputs - fn update(&mut self, was_callback: bool) -> Result<(), xous::Error> { + fn update(&mut self, was_callback: bool, init_done: bool) -> Result<(), xous::Error> { let debug1 = false; // if we had an input string, do something if let Some(local) = &self.input { @@ -219,7 +224,7 @@ impl Repl{ // redraw UI once upon accepting all input if !was_callback { // don't need to redraw on a callback, save some cycles - self.redraw().expect("can't redraw"); + self.redraw(init_done).expect("can't redraw"); } let mut dirty = true; @@ -265,7 +270,7 @@ impl Repl{ self.msg = None; // redraw UI now that we've responded if dirty { - self.redraw().expect("can't redraw"); + self.redraw(init_done).expect("can't redraw"); } if debug1 { @@ -286,10 +291,28 @@ impl Repl{ } )).expect("can't clear content area"); } - fn redraw(&mut self) -> Result<(), xous::Error> { + fn redraw(&mut self, init_done: bool) -> Result<(), xous::Error> { log::trace!("going into redraw"); self.clear_area(); + if !init_done { + let mut init_tv = TextView::new( + self.content, + TextBounds::CenteredTop( + Rectangle::new( + Point::new(0, self.screensize.y / 3 - 64), + Point::new(self.screensize.x, self.screensize.y / 3) + ) + ) + ); + init_tv.style = GlyphStyle::Bold; + init_tv.draw_border = false; + write!(init_tv.text, "{}", t!("shellchat.bootwait", xous::LANG)).ok(); + self.gam.post_textview(&mut init_tv).expect("couldn't render wait text"); + self.gam.redraw().expect("couldn't redraw screen"); + return Ok(()) + } + // this defines the bottom border of the text bubbles as they stack up wards let mut bubble_baseline = self.screensize.y - self.margin.y; @@ -393,8 +416,53 @@ fn wrapped_main() -> ! { let mut was_callback = false; let mut allow_redraw = true; - log::trace!("starting main loop"); + let pddb_init_done = Arc::new(AtomicBool::new(false)); + + // spawn a thread to auto-mount the PDDB. It's important that this spawn happens after + // our GAM context has been registered (which happened in the `Repl::new()` call above) + repl.redraw(false).ok(); + let _ = thread::spawn({ + let pddb_init_done = pddb_init_done.clone(); + let main_conn = xous::connect(shch_sid).unwrap(); + move || { + let tt = ticktimer_server::Ticktimer::new().unwrap(); + tt.sleep_ms(500).ok(); // give some time for the system to finish booting + loop { + let (no_retry_failure, count) = pddb::Pddb::new().try_mount(); + pddb_init_done.store(true, Ordering::SeqCst); + if no_retry_failure { + // this includes both successfully mounted, and user abort of mount attempt + break; + } else { + // this indicates system was guttered due to a retry failure + let xns = xous_names::XousNames::new().unwrap(); + let susres = susres::Susres::new_without_hook(&xns).unwrap(); + let llio = llio::Llio::new(&xns); + if ((llio.adc_vbus().unwrap() as u32) * 503) < 150_000 { + // try to force suspend if possible, so that users who are just playing around with + // the device don't run the battery down accidentally. + susres.initiate_suspend().ok(); + tt.sleep_ms(1000).unwrap(); + let modals = modals::Modals::new(&xns).unwrap(); + modals.show_notification( + &t!("login.fail", xous::LANG).replace("{fails}", &count.to_string()), + None + ).ok(); + } else { + // otherwise force a reboot cycle to slow down guessers + susres.reboot(true).expect("Couldn't reboot after too many failed password attempts"); + tt.sleep_ms(5000).unwrap(); + } + } + } + tt.sleep_ms(100).ok(); // this allows the shellchat context to foreground before calling the redraw + xous::send_message(main_conn, + xous::Message::new_scalar(ShellOpcode::Redraw.to_usize().unwrap(), 0, 0, 0, 0) + ).ok(); + } + }); + log::trace!("starting main loop"); #[cfg(feature = "autobasis-ci")] { log::info!("starting autobasis CI launcher"); @@ -420,7 +488,7 @@ fn wrapped_main() -> ! { } Some(ShellOpcode::Redraw) => { if allow_redraw { - repl.redraw().expect("REPL couldn't redraw"); + repl.redraw(pddb_init_done.load(Ordering::SeqCst)).expect("REPL couldn't redraw"); } } Some(ShellOpcode::ChangeFocus) => xous::msg_scalar_unpack!(msg, new_state_code, _, _, _, { @@ -446,7 +514,7 @@ fn wrapped_main() -> ! { } } if update_repl { - repl.update(was_callback).expect("REPL had problems updating"); + repl.update(was_callback, pddb_init_done.load(Ordering::SeqCst)).expect("REPL had problems updating"); update_repl = false; } log::trace!("reached bottom of main loop"); From 817e758f7c5e4dc2ad389e752d9e4aa3789ce1f0 Mon Sep 17 00:00:00 2001 From: bunnie Date: Sun, 6 Nov 2022 03:36:43 +0800 Subject: [PATCH 8/8] remove the dead-wait before the PDDB is mounted the "right" way to do this is to poll to see if trusted init is done. once that is done, you can go ahead and try to mount the PDDB. --- services/shellchat/src/main.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/services/shellchat/src/main.rs b/services/shellchat/src/main.rs index 11ab93350..061d31fc3 100644 --- a/services/shellchat/src/main.rs +++ b/services/shellchat/src/main.rs @@ -426,7 +426,11 @@ fn wrapped_main() -> ! { let main_conn = xous::connect(shch_sid).unwrap(); move || { let tt = ticktimer_server::Ticktimer::new().unwrap(); - tt.sleep_ms(500).ok(); // give some time for the system to finish booting + let xns = xous_names::XousNames::new().unwrap(); + let gam = gam::Gam::new(&xns).unwrap(); + while !gam.trusted_init_done().unwrap() { + tt.sleep_ms(50).ok(); + } loop { let (no_retry_failure, count) = pddb::Pddb::new().try_mount(); pddb_init_done.store(true, Ordering::SeqCst);