Skip to content

Commit 8ac6e17

Browse files
authored
Merge pull request #840 from betrusted-io/ux
Add progress bar to loader on baosec targets
2 parents 54ed7a1 + df0fd57 commit 8ac6e17

File tree

16 files changed

+338
-17
lines changed

16 files changed

+338
-17
lines changed

libs/bao1x-hal/src/sh1107.rs

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ pub const PAGE: u8 = ROW as u8 / 8;
1414
// IFRAM space reserved for UDMA channel commands
1515
const SIDEBAND_LEN: usize = 256;
1616

17+
// 0x4f is a bit too bright
18+
pub const DEFAULT_BRIGHTNESS: u8 = 0x3f;
19+
1720
pub struct MainThreadToken(());
1821
impl MainThreadToken {
1922
pub fn new() -> Self { MainThreadToken(()) }
@@ -465,7 +468,7 @@ impl<'a> Oled128x128<'a> {
465468
SetDCDCSettings(0x0),
466469
SetStartLine(0),
467470
SetDisplayOffset(0),
468-
SetContrastControl(0x3f), // was 0x4f, was a bit too bright
471+
SetContrastControl(DEFAULT_BRIGHTNESS),
469472
SetAddressMode(AddressMode::Column),
470473
SetSegmentReMap(false),
471474
SetCOMScanDirection(Direction::Inverted),
@@ -512,6 +515,61 @@ impl<'a> Oled128x128<'a> {
512515
crate::board::assert_periph_reset(self.iox, false);
513516
self.powerdown = false;
514517
}
518+
519+
pub fn brightness(&mut self, level: u8) {
520+
let bytes = Command::SetContrastControl(level).encode();
521+
self.send_command(bytes);
522+
}
523+
524+
#[cfg(feature = "std")]
525+
pub fn render_bitmap(&mut self, bitmap: ux_api::service::api::BaosecBitmap) {
526+
const W: isize = WIDTH as _;
527+
const H: isize = LINES as _;
528+
529+
// Clamp bounding box to valid bitmap dimensions.
530+
// If br > 128, truncate. If tl < 0, clamp to 0.
531+
let src_x0 = bitmap.bounding_box.tl.x.max(0);
532+
let src_y0 = bitmap.bounding_box.tl.y.max(0);
533+
let src_x1 = bitmap.bounding_box.br.x.min(W);
534+
let src_y1 = bitmap.bounding_box.br.y.min(H);
535+
536+
for src_y in src_y0..src_y1 {
537+
// Map this bitmap row to its destination row in the framebuffer.
538+
let dst_y = src_y + bitmap.top_left.y;
539+
540+
// Skip rows that land outside the framebuffer.
541+
if dst_y < 0 || dst_y >= H {
542+
continue;
543+
}
544+
545+
for src_x in src_x0..src_x1 {
546+
// Map this bitmap column to its destination column.
547+
let dst_x = src_x + bitmap.top_left.x;
548+
549+
// Skip columns that land outside the framebuffer.
550+
if dst_x < 0 || dst_x >= W {
551+
continue;
552+
}
553+
554+
// --- read source bit ---
555+
let src_linear = (src_x + src_y * W) as usize;
556+
let src_word = src_linear >> 5; // / 32
557+
let src_shift = src_linear & 0x1F; // % 32
558+
let on = (bitmap.bits[src_word] >> src_shift) & 1;
559+
560+
// --- write destination bit ---
561+
let dst_linear = (dst_x + dst_y * W) as usize;
562+
let dst_word = dst_linear >> 5;
563+
let dst_shift = dst_linear & 0x1F;
564+
565+
if on != 0 {
566+
self.buffer[dst_word] |= 1 << dst_shift;
567+
} else {
568+
self.buffer[dst_word] &= !(1 << dst_shift);
569+
}
570+
}
571+
}
572+
}
515573
}
516574

517575
impl<'a> FrameBuffer for Oled128x128<'a> {

libs/keystore-api/src/gen2_api.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub enum Opcode {
2121
// ----- below are non-cryptographic opcodes but used to manipulate sensitive state -----
2222
/// Set bootwait parameters
2323
Bootwait = 4096,
24+
IsDeveloper = 4097,
2425

2526
/// Used to map unknown opcodes
2627
InvalidCall = 65535,

libs/ux-api/src/minigfx/mod.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use crate::platform;
3636
/// Abstract trait for a FrameBuffer. Slower than native manipulation
3737
/// of the [u8] contents of a frame buffer, but more portable.
3838
pub trait FrameBuffer {
39-
/// Puts a pixel of ColorNative at x, y. (0, 0) is defined as the lower left corner.
39+
/// Puts a pixel of ColorNative at x, y. (0, 0) is defined as the top left corner.
4040
fn put_pixel(&mut self, p: Point, color: ColorNative);
4141
/// For higher-performance loops that have guaranteed bounds checking in the point location.
4242
unsafe fn put_pixel_unchecked(&mut self, p: Point, on: ColorNative);
@@ -56,6 +56,27 @@ pub trait FrameBuffer {
5656
unsafe fn raw_mut(&mut self) -> &mut platform::FbRaw;
5757
}
5858

59+
// Newtype wrapping the FrameBuffer, to allow for sized passing of the object around
60+
pub struct DynFb<'a>(pub &'a mut dyn FrameBuffer);
61+
62+
impl FrameBuffer for DynFb<'_> {
63+
fn put_pixel(&mut self, p: Point, c: ColorNative) { self.0.put_pixel(p, c) }
64+
65+
fn xor_pixel(&mut self, p: Point) { self.0.xor_pixel(p) }
66+
67+
unsafe fn put_pixel_unchecked(&mut self, p: Point, on: ColorNative) { self.0.put_pixel_unchecked(p, on); }
68+
69+
fn get_pixel(&self, p: Point) -> Option<ColorNative> { self.0.get_pixel(p) }
70+
71+
fn draw(&mut self) { self.0.draw(); }
72+
73+
fn clear(&mut self) { self.0.clear(); }
74+
75+
fn dimensions(&self) -> Point { self.0.dimensions() }
76+
77+
unsafe fn raw_mut(&mut self) -> &mut platform::FbRaw { self.0.raw_mut() }
78+
}
79+
5980
/// A TypesetWord is a Word that has beet turned into sprites and placed at a specific location on the canvas,
6081
/// defined by its `bb` record. The intention is that this abstract representation can be passed directly to
6182
/// a rasterizer for rendering.

libs/ux-api/src/service/api.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,11 @@ pub enum GfxOpcode {
107107
PowerDown,
108108
#[cfg(feature = "board-baosec")]
109109
PowerUp,
110+
#[cfg(feature = "board-baosec")]
111+
/// This call is specific and highly optimized to the display on Baosec
112+
BaosecBitmap,
113+
#[cfg(feature = "board-baosec")]
114+
Brightness,
110115

111116
/// Gutter for invalid calls
112117
InvalidCall,
@@ -154,3 +159,14 @@ pub struct KeyboardRegistration {
154159
pub server_name: String,
155160
pub listener_op_id: usize,
156161
}
162+
163+
#[cfg(feature = "board-baosec")]
164+
#[derive(Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Clone)]
165+
pub struct BaosecBitmap {
166+
// exactly enough for a 128x128 black and white display = 2048 bytes
167+
pub bits: [u32; 512],
168+
// top left corner of the bitmap
169+
pub top_left: crate::minigfx::Point,
170+
// bounding box of the bitmap - if we want only a portion of the bitmap to be drawn
171+
pub bounding_box: crate::minigfx::Rectangle,
172+
}

libs/ux-api/src/service/gfx.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,38 @@ impl Gfx {
769769
}
770770
}
771771

772+
#[cfg(feature = "board-baosec")]
773+
pub fn bitmap(
774+
&self,
775+
bitmap: &[u32],
776+
top_left: Option<Point>,
777+
bounding_box: Option<Rectangle>,
778+
) -> Result<(), xous::Error> {
779+
let mut bmp = BaosecBitmap {
780+
bits: [0u32; 512],
781+
top_left: top_left.unwrap_or(Point::new(0, 0)),
782+
bounding_box: bounding_box.unwrap_or(Rectangle {
783+
tl: Point::new(0, 0),
784+
// br is *exclusive*
785+
br: Point::new(128, 128),
786+
style: DrawStyle { fill_color: None, stroke_color: None, stroke_width: 0 },
787+
}),
788+
};
789+
bmp.bits[..bitmap.len().min(512)].copy_from_slice(&bitmap[..bitmap.len().min(512)]);
790+
let mut buf = Buffer::into_buf(bmp).unwrap();
791+
buf.lend_mut(self.conn, GfxOpcode::BaosecBitmap.to_u32().unwrap())?;
792+
Ok(())
793+
}
794+
795+
#[cfg(feature = "board-baosec")]
796+
pub fn brightness(&self, level: u8) -> Result<(), xous::Error> {
797+
send_message(
798+
self.conn,
799+
Message::new_blocking_scalar(GfxOpcode::Brightness.to_usize().unwrap(), level as usize, 0, 0, 0),
800+
)
801+
.map(|_| ())
802+
}
803+
772804
#[cfg(feature = "hosted-baosec")]
773805
pub fn acquire_qr(&self) -> Result<QrAcquisition, xous::Error> {
774806
let dummy = "otpauth://totp/ACME%20Co:john.doe@email.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME%20Co&algorithm=SHA1&digits=6&period=30".to_string();

loader/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,12 @@ pub const APP_UART_IFRAM_ADDR: usize = bao1x_hal::board::APP_UART_IFRAM_ADDR;
4343
pub const GUARD_MEMORY_BYTES: usize = 3 * crate::PAGE_SIZE;
4444
/// Amount of space for loader stack only, with swap
4545
#[cfg(all(feature = "swap", not(feature = "resume"), not(feature = "bao1x")))]
46-
pub const GUARD_MEMORY_BYTES: usize = 7 * crate::PAGE_SIZE;
46+
pub const GUARD_MEMORY_BYTES: usize = 8 * crate::PAGE_SIZE;
4747
#[cfg(all(feature = "swap", not(feature = "resume"), feature = "bao1x"))]
48-
pub const GUARD_MEMORY_BYTES: usize = 7 * crate::PAGE_SIZE;
49-
/// Amount of space for loader stack plus clean suspend, with swap
48+
pub const GUARD_MEMORY_BYTES: usize = 8 * crate::PAGE_SIZE;
49+
/// Amount of space for loader stack plus clean suspend, with swap. +1 page cost for the loading bar graphics
5050
#[cfg(all(feature = "swap", feature = "resume"))]
51-
pub const GUARD_MEMORY_BYTES: usize = 8 * crate::PAGE_SIZE; // 1 extra page for clean suspend
51+
pub const GUARD_MEMORY_BYTES: usize = 9 * crate::PAGE_SIZE; // 1 extra page for clean suspend
5252

5353
#[cfg(feature = "swap")]
5454
pub const SWAPPER_PID: u8 = 2;

loader/src/main.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,15 @@ fn boot_sequence(
470470
_perclk_freq: u32,
471471
detached_app: bool,
472472
) -> ! {
473+
#[cfg(feature = "board-baosec")]
474+
let mut iox = bao1x_hal::iox::Iox::new(utralib::utra::iox::HW_IOX_BASE as *mut u32);
475+
#[cfg(feature = "board-baosec")]
476+
let mut udma_global = bao1x_hal::udma::GlobalConfig::new();
477+
#[cfg(feature = "board-baosec")]
478+
let mut oled = crate::platform::oled_init(&mut iox, &mut udma_global, _perclk_freq);
479+
#[cfg(feature = "board-baosec")]
480+
crate::platform::progress_bar(&mut oled, 0);
481+
473482
// Store the initial boot config on the stack. We don't know
474483
// where in heap this memory will go.
475484
#[allow(clippy::cast_ptr_alignment)] // This test only works on 32-bit systems
@@ -525,8 +534,19 @@ fn boot_sequence(
525534
// cold boot path
526535
println!("No suspend marker found, doing a cold boot!");
527536
clear_ram(&mut cfg);
528-
phase_1(&mut cfg, detached_app);
529-
phase_2(&mut cfg, env_variables);
537+
538+
#[cfg(feature = "board-baosec")]
539+
{
540+
phase_1(&mut cfg, detached_app, Some(&mut oled));
541+
phase_2(&mut cfg, env_variables, Some(&mut oled));
542+
crate::platform::progress_bar(&mut oled, 100);
543+
}
544+
#[cfg(not(feature = "board-baosec"))]
545+
{
546+
phase_1(&mut cfg, detached_app, None);
547+
phase_2(&mut cfg, env_variables, None);
548+
}
549+
530550
#[cfg(any(feature = "debug-print", feature = "swap"))]
531551
if VDBG || SDBG {
532552
check_load(&mut cfg);

loader/src/minielf.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ impl MiniElf {
9292
let mut current_page_addr: usize = 0;
9393
let mut previous_addr: usize = 0;
9494
let mut last_mapped_xip = 0;
95+
#[cfg(feature = "swap")]
9596
let mut last_mapped_swap_virt = 0; // track the last virtual address mapped to swap, to catch gaps
9697
let image_phys_base = allocator.base_addr as usize + self.load_offset as usize;
9798
// It is a requirement that the image generator lay out the artifacts on disk such that

loader/src/phase1.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
use core::{mem::size_of, slice};
22

3+
#[cfg(any(feature = "board-baosec", feature = "board-baosor"))]
4+
use ux_api::minigfx::FrameBuffer;
5+
36
#[cfg(feature = "atsama5d27")]
47
pub use crate::platform::atsama5d27::load::InitialProcess;
58
use crate::*;
9+
// define an uninhabited stub type for boards without framebuffers
10+
#[cfg(not(any(feature = "board-baosec", feature = "board-baosor")))]
11+
pub trait FrameBuffer {}
612

713
#[repr(C)]
814
#[cfg(not(feature = "atsama5d27"))]
@@ -30,7 +36,7 @@ pub struct InitialProcess {
3036
/// We don't memorize the allocated results (in part because we don't have malloc/alloc to stick
3137
/// the table, and we don't know a priori how big it will be); we simply memorize the maximum extent,
3238
/// after which we allocate the book-keeping tables.
33-
pub fn phase_1(cfg: &mut BootConfig, detached_app: bool) {
39+
pub fn phase_1(cfg: &mut BootConfig, detached_app: bool, fb: Option<&mut dyn FrameBuffer>) {
3440
// Allocate space for the stack pointer.
3541
// The bootloader should have placed the stack pointer at the end of RAM
3642
// prior to jumping to our program. Reserve space for the stack, so that it does not smash
@@ -161,7 +167,7 @@ pub fn phase_1(cfg: &mut BootConfig, detached_app: bool) {
161167
// Copy the processes to RAM, if requested.
162168
if !cfg.no_copy {
163169
println!("Copying processes");
164-
copy_processes(cfg);
170+
copy_processes(cfg, fb);
165171
}
166172
// activate this to debug stack-smashing during copy_process(). The RPT is the first structure that gets
167173
// smashed if the stack overflows! It should be all 0's if the stack did not overrun.
@@ -499,9 +505,11 @@ impl TagType {
499505

500506
/// Copy program data from the SPI flash into newly-allocated RAM
501507
/// located at the end of memory space.
502-
fn copy_processes(cfg: &mut BootConfig) {
508+
fn copy_processes(cfg: &mut BootConfig, mut _fb: Option<&mut dyn FrameBuffer>) {
503509
let mut _pid = 1;
504-
for tag in cfg.args.iter() {
510+
#[cfg(feature = "board-baosec")]
511+
let arg_len = cfg.args.iter().count();
512+
for (_i, tag) in cfg.args.iter().enumerate() {
505513
let tag_type = TagType::from(tag.name);
506514
match tag_type {
507515
TagType::IniF | TagType::IniE => {
@@ -879,6 +887,14 @@ fn copy_processes(cfg: &mut BootConfig) {
879887
}
880888
_ => {}
881889
}
890+
#[cfg(feature = "board-baosec")]
891+
if let Some(ref mut fb) = _fb {
892+
let start = 5;
893+
let end = 70;
894+
let increment = (end - start) / arg_len;
895+
let percentage = start + increment * _i;
896+
crate::platform::progress_bar(*fb, percentage);
897+
}
882898
}
883899
}
884900

loader/src/phase2.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
1+
#[cfg(any(feature = "board-baosec", feature = "board-baosor"))]
2+
use ux_api::minigfx::FrameBuffer;
13
#[cfg(feature = "swap")]
24
use xous::arch::{SWAP_CFG_VADDR, SWAP_COUNT_VADDR, SWAP_PT_VADDR};
35

46
#[cfg(feature = "swap")]
57
use crate::swap::*;
68
use crate::{env::EnvVariables, *};
9+
// define an uninhabited stub type for boards without framebuffers
10+
#[cfg(not(any(feature = "board-baosec", feature = "board-baosor")))]
11+
pub trait FrameBuffer {}
712

813
/// Phase 2 bootloader
914
///
1015
/// Set up all the page tables, allocating new root page tables for SATPs and corresponding
1116
/// sub-pages starting from the base of previously copied process data.
12-
pub fn phase_2(cfg: &mut BootConfig, env_variables: EnvVariables) {
17+
pub fn phase_2(cfg: &mut BootConfig, env_variables: EnvVariables, mut _fb: Option<&mut dyn FrameBuffer>) {
1318
let args = cfg.args;
1419

1520
// This is the offset in RAM where programs are loaded from.
@@ -41,7 +46,9 @@ pub fn phase_2(cfg: &mut BootConfig, env_variables: EnvVariables) {
4146
#[cfg(feature = "bao1x")]
4247
trng.setup_raw_generation(32); // this is safe to call multiple times to affirm the TRNG state
4348

44-
for tag in args.iter() {
49+
#[cfg(feature = "board-baosec")]
50+
let arg_len = args.iter().count();
51+
for (_i, tag) in args.iter().enumerate() {
4552
let mut env_header = crate::env::EnvHeader::default();
4653
#[allow(unused_mut)]
4754
let mut pid_env = env_variables.clone();
@@ -104,6 +111,14 @@ pub fn phase_2(cfg: &mut BootConfig, env_variables: EnvVariables) {
104111
}
105112
process_offset -= load_size_rounded;
106113
}
114+
#[cfg(feature = "board-baosec")]
115+
if let Some(ref mut fb) = _fb {
116+
let start = 70;
117+
let end = 95;
118+
let increment = (end - start) / arg_len;
119+
let percentage = start + increment * _i;
120+
crate::platform::progress_bar(*fb, percentage);
121+
}
107122
}
108123

109124
println!("Done loading.");

0 commit comments

Comments
 (0)