From 03d3cc50f08b227cd17e55a086fd3023ddb824db Mon Sep 17 00:00:00 2001
From: Benjamin Koch <bbbsnowball@gmail.com>
Date: Sun, 11 Jun 2023 00:25:22 +0200
Subject: [PATCH] add extra layer of pointers for program info -> program name
 is displayed in `picotool info`

---
 firmware/rust1-bootloader/src/main.rs |  10 ++-
 firmware/rust1/src/bin/heizung.rs     | 115 ++++++++++++++++++++++----
 2 files changed, 108 insertions(+), 17 deletions(-)

diff --git a/firmware/rust1-bootloader/src/main.rs b/firmware/rust1-bootloader/src/main.rs
index 73e995e..e62b5b8 100644
--- a/firmware/rust1-bootloader/src/main.rs
+++ b/firmware/rust1-bootloader/src/main.rs
@@ -104,6 +104,10 @@ fn panic(_info: &core::panic::PanicInfo) -> ! {
 // the predefined linker script is .Reset so let's add it to that.
 const BINARY_INFO_MARKER_START: u32 = 0x7188ebf2;
 const BINARY_INFO_MARKER_END: u32 = 0xe71aa390;
+const PROGRAM_INFO_FLASH_OFFSET: u32 = 0x10087000 - PROGRAM_INFO_TOTAL_SIZE;  // last 4k of active partition
+const PROGRAM_INFO_TOTAL_SIZE: u32 = 4096;
+const PROGRAM_INFO_TABLE_SIZE: u32 = 128;  // one pointer (4 bytes) for each piece of data, all must be valid pointers
+const PROGRAM_INFO_COPY_TABLE_SIZE: u32 = 128;  // 3*u32 for each entry, picotool stops after 10 entries
 #[used]
 #[link_section = ".Reset"]
 pub static PROGRAM_INFO: [u32; 5] = {
@@ -115,9 +119,9 @@ pub static PROGRAM_INFO: [u32; 5] = {
         BINARY_INFO_MARKER_START,
         //&__bootloader_active_program_info_start as *const u32 as u32,
         //&__bootloader_active_program_info_end as *const u32 as u32,
-        0x10086000,
-        0x10087000,
-        0x10087000 - 128,  // copy table can have up to 10 entries of 3*u32 each
+        PROGRAM_INFO_FLASH_OFFSET,
+        PROGRAM_INFO_FLASH_OFFSET + PROGRAM_INFO_TABLE_SIZE,
+        PROGRAM_INFO_FLASH_OFFSET + PROGRAM_INFO_TOTAL_SIZE - PROGRAM_INFO_COPY_TABLE_SIZE,
         BINARY_INFO_MARKER_END
     ]
 };
diff --git a/firmware/rust1/src/bin/heizung.rs b/firmware/rust1/src/bin/heizung.rs
index cd9d730..1845fe3 100644
--- a/firmware/rust1/src/bin/heizung.rs
+++ b/firmware/rust1/src/bin/heizung.rs
@@ -707,10 +707,18 @@ struct ProgramInfoBuilder {
     buf: [u8; 4096],
     info_pos: usize,
     data_pos: usize,
+    info_table_size: usize,
+    data_end_offset: usize,
 }
 
 impl ProgramInfoBuilder {
-    const fn new(addr: u32, copy_table_size: usize) -> Self {
+    const fn new(addr: u32, info_table_size: u32, copy_table_size: u32) -> Self {
+        let copy_table_size = copy_table_size as usize;
+        let dummy_item_ptr = addr + info_table_size;
+        let dummy_item_size = 4;
+
+        core::assert!(info_table_size % 4 == 0);
+
         ProgramInfoBuilder {
             addr,
             buf: {
@@ -723,23 +731,86 @@ impl ProgramInfoBuilder {
                 x
             },
             info_pos: 0,
-            data_pos: 4096 - copy_table_size,
+            data_pos: info_table_size as usize + dummy_item_size,
+            data_end_offset: 4096 - copy_table_size as usize,
+            info_table_size: info_table_size as usize,
         }
     }
 
-    const fn build(self: Self) -> [u8; 4096] {
+    const fn build(mut self: Self) -> [u8; 4096] {
+        if self.info_pos < self.info_table_size {
+            self = self.align();
+            let addr = self.addr + self.data_pos as u32;
+            self = self.push_u32(0xffffffff).fill_info_table(addr);
+        }
         self.buf
     }
 
-    const fn push(mut self: Self, value: u8) -> Self {
+    const fn push_info_u8(mut self: Self, value: u8) -> Self {
         self.buf[self.info_pos] = value;
         self.info_pos += 1;
-        if self.info_pos > self.data_pos {
+        if self.info_pos > self.info_table_size {
+            core::panic!("ProgramInfoBuilder: too much data for info table")
+        }
+        self
+    }
+
+    const fn push_info_ptr(mut self: Self, value: u32) -> Self {
+        self
+            .push_info_u8((value & 0xff) as u8)
+            .push_info_u8(((value >> 8) & 0xff) as u8)
+            .push_info_u8(((value >> 16) & 0xff) as u8)
+            .push_info_u8(((value >> 24) & 0xff) as u8)
+    }
+
+    const fn push_current_info_ptr(mut self: Self) -> Self {
+        self = self.align();
+        let addr = self.addr + self.data_pos as u32;
+        self.push_info_ptr(addr)
+    }
+
+    const fn fill_info_table(mut self: Self, value: u32) -> Self {
+        if self.info_pos < self.info_table_size {
+            self = self.push_info_ptr(value);
+        }
+        if self.info_pos < self.info_table_size {
+            self = self.push_info_ptr(value);
+        }
+        if self.info_pos < self.info_table_size {
+            self = self.push_info_ptr(value);
+        }
+        if self.info_pos < self.info_table_size {
+            self = self.push_info_ptr(value);
+        }
+        if self.info_pos < self.info_table_size {
+            self.fill_info_table(value)
+        } else {
+            self
+        }
+    }
+
+    const fn push(mut self: Self, value: u8) -> Self {
+        self.buf[self.data_pos] = value;
+        self.data_pos += 1;
+        if self.data_pos > self.data_end_offset {
             core::panic!("ProgramInfoBuilder: too much data")
         }
         self
     }
 
+    const fn align(mut self: Self) -> Self {
+        if self.data_pos % 4 != 0 {
+            self = self.push(0xff);
+        }
+        if self.data_pos % 4 != 0 {
+            self = self.push(0xff);
+        }
+        if self.data_pos % 4 != 0 {
+            self = self.push(0xff);
+        }
+        self
+    }
+
     const fn push_u16(self: Self, value: u16) -> Self {
         self
             .push((value & 0xff) as u8)
@@ -763,7 +834,7 @@ impl ProgramInfoBuilder {
         if self.data_pos - self.info_pos < value.len() {
             core::panic!("ProgramInfoBuilder: too much data")
         }
-        let offset = self.data_pos - value.len();
+        let offset = self.data_pos;
         //self.buf[offset..self.data_pos].copy_from_slice(value);
         //for i in 0..value.len() {
         //    self.buf[offset+i] = value[i];
@@ -778,7 +849,7 @@ impl ProgramInfoBuilder {
         if value.len() > 7 { self.buf[offset+7] = value[7]; }
         if value.len() > 8 { core::panic!("too long") }
 
-        self.data_pos -= value.len();
+        self.data_pos += value.len();
         let addr = self.addr + offset as u32;
         (self, addr)
     }
@@ -787,9 +858,19 @@ impl ProgramInfoBuilder {
         if self.data_pos - self.info_pos < value.len() {
             core::panic!("ProgramInfoBuilder: too much data")
         }
-        (self, _) = self.push_extra_data(&[0]);
+        let x1 = self.data_pos;
+        self = self.push_u32(0);
+
         let (self2, addr) = self.push_extra_data(value.as_bytes());
-        self2.push_u32(addr)
+        self = self2;
+        (self, _) = self.push_extra_data(&[0]);
+        
+        let x2 = self.data_pos;
+        self.data_pos = x1;
+        self = self.push_u32(addr);
+        self.data_pos = x2;
+        
+        self
     }
 
     const BINARY_INFO_TYPE_ID_AND_INT: u16 = 5;
@@ -798,25 +879,31 @@ impl ProgramInfoBuilder {
     const BINARY_INFO_ID_RP_BINARY_END: u32 = 0x68f465de;
 
     const fn push_program_name(self: Self, value: &str) -> Self {
-        self.push_raspberry_tag()
+        self.push_current_info_ptr()
             .push_u16(Self::BINARY_INFO_TYPE_ID_AND_STRING)
+            .push_raspberry_tag()
             .push_u32(Self::BINARY_INFO_ID_RP_PROGRAM_NAME)
             .push_string(value)
     }
 
+    #[allow(unused)]
     const fn push_binary_end(self: Self, value: &str) -> Self {
-        self.push_raspberry_tag()
+        self.push_current_info_ptr()
             .push_u16(Self::BINARY_INFO_TYPE_ID_AND_INT)
+            .push_raspberry_tag()
             .push_u32(Self::BINARY_INFO_ID_RP_BINARY_END)
             .push_string(value)
     }
 }
 
 const fn make_program_info() -> [u8; 4096] {
-    const PROGRAM_INFO_START: u32 = 0x10086000;
-    const COPY_TABLE_SIZE: usize = 128;  // must match bootloader
+    // all of these must match the values in the bootloader
+    const PROGRAM_INFO_FLASH_OFFSET: u32 = 0x10087000 - PROGRAM_INFO_TOTAL_SIZE;  // last 4k of active partition
+    const PROGRAM_INFO_TOTAL_SIZE: u32 = 4096;
+    const PROGRAM_INFO_TABLE_SIZE: u32 = 128;  // one pointer (4 bytes) for each piece of data, all must be valid pointers
+    const PROGRAM_INFO_COPY_TABLE_SIZE: u32 = 128;  // 3*u32 for each entry, picotool stops after 10 entries
 
-    ProgramInfoBuilder::new(PROGRAM_INFO_START, COPY_TABLE_SIZE)
+    ProgramInfoBuilder::new(PROGRAM_INFO_FLASH_OFFSET, PROGRAM_INFO_TABLE_SIZE, PROGRAM_INFO_COPY_TABLE_SIZE)
         .push_program_name("Test 123")
         .build()
 }
-- 
GitLab