@@ -2745,6 +2745,169 @@ status_scan_flash_usage(ra_device_t *dev, uint32_t sad, uint32_t ead, uint32_t r
27452745 return used ;
27462746}
27472747
2748+ /*
2749+ * MCUboot image header structure
2750+ * See: https://docs.mcuboot.com/design.html#image-format
2751+ */
2752+ #define MCUBOOT_IMAGE_MAGIC 0x96f3b83d
2753+ #define MCUBOOT_HEADER_SIZE 32
2754+
2755+ typedef struct {
2756+ uint32_t ih_magic ;
2757+ uint32_t ih_load_addr ;
2758+ uint16_t ih_hdr_size ;
2759+ uint16_t ih_protect_tlv_size ;
2760+ uint32_t ih_img_size ;
2761+ uint32_t ih_flags ;
2762+ uint8_t iv_major ;
2763+ uint8_t iv_minor ;
2764+ uint16_t iv_revision ;
2765+ uint32_t iv_build_num ;
2766+ } mcuboot_image_header_t ;
2767+
2768+ /* Detected MCUboot partition info */
2769+ typedef struct {
2770+ uint32_t start ;
2771+ uint32_t end ;
2772+ bool has_image ;
2773+ uint8_t ver_major ;
2774+ uint8_t ver_minor ;
2775+ uint16_t ver_rev ;
2776+ uint32_t ver_build ;
2777+ uint32_t img_size ;
2778+ } mcuboot_partition_t ;
2779+
2780+ #define MAX_MCUBOOT_PARTITIONS 8
2781+
2782+ /*
2783+ * Read a small chunk of flash (for header detection)
2784+ * Returns 0 on success, -1 on error
2785+ */
2786+ static int
2787+ status_read_flash_chunk (ra_device_t * dev , uint32_t addr , uint8_t * buf , size_t len ) {
2788+ uint8_t pkt [MAX_PKT_LEN ];
2789+ uint8_t resp [CHUNK_SIZE + 6 ];
2790+ uint8_t data [8 ];
2791+ ssize_t pkt_len , n ;
2792+
2793+ if (len > CHUNK_SIZE )
2794+ len = CHUNK_SIZE ;
2795+
2796+ uint32_to_be (addr , & data [0 ]);
2797+ uint32_to_be (addr + len - 1 , & data [4 ]);
2798+
2799+ pkt_len = ra_pack_pkt (pkt , sizeof (pkt ), REA_CMD , data , 8 , false);
2800+ if (pkt_len < 0 )
2801+ return -1 ;
2802+
2803+ if (ra_send (dev , pkt , pkt_len ) < 0 )
2804+ return -1 ;
2805+
2806+ n = ra_recv (dev , resp , len + 6 , 2000 );
2807+ if (n < 7 )
2808+ return -1 ;
2809+
2810+ size_t chunk_len ;
2811+ uint8_t cmd ;
2812+ if (ra_unpack_pkt (resp , n , buf , & chunk_len , & cmd ) < 0 )
2813+ return -1 ;
2814+ if (cmd & STATUS_ERR )
2815+ return -1 ;
2816+
2817+ return 0 ;
2818+ }
2819+
2820+ /*
2821+ * Check if address contains MCUboot image header
2822+ * Returns 1 if valid MCUboot header found, 0 otherwise
2823+ */
2824+ static int
2825+ status_check_mcuboot_header (ra_device_t * dev , uint32_t addr , mcuboot_partition_t * part ) {
2826+ uint8_t buf [MCUBOOT_HEADER_SIZE ];
2827+
2828+ if (status_read_flash_chunk (dev , addr , buf , MCUBOOT_HEADER_SIZE ) < 0 )
2829+ return 0 ;
2830+
2831+ /* MCUboot uses little-endian format */
2832+ uint32_t magic = buf [0 ] | (buf [1 ] << 8 ) | (buf [2 ] << 16 ) | (buf [3 ] << 24 );
2833+
2834+ if (magic != MCUBOOT_IMAGE_MAGIC )
2835+ return 0 ;
2836+
2837+ /* Parse header fields (little-endian) */
2838+ part -> start = addr ;
2839+ part -> has_image = true;
2840+ part -> img_size = buf [12 ] | (buf [13 ] << 8 ) | (buf [14 ] << 16 ) | (buf [15 ] << 24 );
2841+ part -> ver_major = buf [20 ];
2842+ part -> ver_minor = buf [21 ];
2843+ part -> ver_rev = buf [22 ] | (buf [23 ] << 8 );
2844+ part -> ver_build = buf [24 ] | (buf [25 ] << 8 ) | (buf [26 ] << 16 ) | (buf [27 ] << 24 );
2845+
2846+ /* Calculate end address: header + protected TLV + image + TLV area */
2847+ uint16_t hdr_size = buf [8 ] | (buf [9 ] << 8 );
2848+ part -> end = addr + hdr_size + part -> img_size ;
2849+
2850+ return 1 ;
2851+ }
2852+
2853+ /*
2854+ * Scan flash region to find last non-0xFF byte (actual used size)
2855+ * Returns the used size in bytes, or 0 if region is empty
2856+ */
2857+ static uint32_t
2858+ status_scan_region_usage (ra_device_t * dev , uint32_t start , uint32_t end ) {
2859+ uint8_t buf [CHUNK_SIZE ];
2860+ uint32_t last_used = 0 ;
2861+ uint32_t size = end - start + 1 ;
2862+ uint32_t nr_chunks = (size + CHUNK_SIZE - 1 ) / CHUNK_SIZE ;
2863+
2864+ for (uint32_t i = 0 ; i < nr_chunks ; i ++ ) {
2865+ uint32_t chunk_start = start + i * CHUNK_SIZE ;
2866+ uint32_t remaining = end - chunk_start + 1 ;
2867+ uint32_t chunk_size = (remaining > CHUNK_SIZE ) ? CHUNK_SIZE : remaining ;
2868+
2869+ if (status_read_flash_chunk (dev , chunk_start , buf , chunk_size ) < 0 )
2870+ continue ;
2871+
2872+ /* Find last non-0xFF byte in this chunk */
2873+ for (uint32_t j = chunk_size ; j > 0 ; j -- ) {
2874+ if (buf [j - 1 ] != 0xFF ) {
2875+ uint32_t offset = chunk_start - start + j ;
2876+ if (offset > last_used )
2877+ last_used = offset ;
2878+ break ;
2879+ }
2880+ }
2881+ }
2882+
2883+ return last_used ;
2884+ }
2885+
2886+ /*
2887+ * Scan code flash for MCUboot images
2888+ * Scans at 4KB boundaries (common minimum slot alignment)
2889+ * Returns number of images found
2890+ */
2891+ static int
2892+ status_scan_mcuboot_images (
2893+ ra_device_t * dev , uint32_t sad , uint32_t ead , mcuboot_partition_t * parts , int max_parts ) {
2894+ int count = 0 ;
2895+ uint32_t scan_step = 4096 ; /* 4KB alignment */
2896+
2897+ fprintf (stderr , "Scanning for MCUboot images...\n" );
2898+
2899+ for (uint32_t addr = sad ; addr < ead && count < max_parts ; addr += scan_step ) {
2900+ if (status_check_mcuboot_header (dev , addr , & parts [count ])) {
2901+ count ++ ;
2902+ /* Skip past this image to avoid finding overlapping headers */
2903+ if (parts [count - 1 ].end > addr )
2904+ addr = ((parts [count - 1 ].end + scan_step - 1 ) / scan_step ) * scan_step - scan_step ;
2905+ }
2906+ }
2907+
2908+ return count ;
2909+ }
2910+
27482911/*
27492912 * Get CPU core name from product series
27502913 */
@@ -3216,6 +3379,34 @@ ra_status(ra_device_t *dev) {
32163379 * reads undefined values (not 0xFF) per Renesas RA hardware spec.
32173380 * The bootloader protocol does not expose a reliable blank-check method. */
32183381
3382+ /* Scan for MCUboot images in code flash */
3383+ mcuboot_partition_t mcuboot_parts [MAX_MCUBOOT_PARTITIONS ];
3384+ int mcuboot_count = 0 ;
3385+ uint32_t bl_used = 0 , storage_used = 0 ;
3386+ uint32_t storage_start = 0 , storage_size = 0 ;
3387+
3388+ if (code_size > 0 )
3389+ mcuboot_count =
3390+ status_scan_mcuboot_images (dev , code_sad , code_ead , mcuboot_parts , MAX_MCUBOOT_PARTITIONS );
3391+
3392+ /* Scan bootloader and storage regions if MCUboot images found */
3393+ if (mcuboot_count > 0 ) {
3394+ /* Scan bootloader region */
3395+ if (mcuboot_parts [0 ].start > code_sad ) {
3396+ fprintf (stderr , "Scanning bootloader region...\n" );
3397+ bl_used = status_scan_region_usage (dev , code_sad , mcuboot_parts [0 ].start - 1 );
3398+ }
3399+
3400+ /* Scan storage region (last 48KB) */
3401+ uint32_t storage_reserve = 48 * 1024 ;
3402+ storage_start = code_ead - storage_reserve + 1 ;
3403+ if (storage_start > mcuboot_parts [mcuboot_count - 1 ].start ) {
3404+ storage_size = code_ead - storage_start + 1 ;
3405+ fprintf (stderr , "Scanning storage region...\n" );
3406+ storage_used = status_scan_region_usage (dev , storage_start , code_ead );
3407+ }
3408+ }
3409+
32193410 /* Print status display */
32203411 printf ("\n" );
32213412 status_print_hline (BOX_TL , BOX_H , BOX_TR , STATUS_WIDTH );
@@ -3327,6 +3518,97 @@ ra_status(ra_device_t *dev) {
33273518 status_format_inner (line , sizeof (line ), content , INNER_WIDTH );
33283519 status_print_line (line , STATUS_WIDTH );
33293520
3521+ /* MCUboot partitions display */
3522+ if (mcuboot_count > 0 ) {
3523+ status_format_inner (line , sizeof (line ), "" , INNER_WIDTH );
3524+ status_print_line (line , STATUS_WIDTH );
3525+ status_format_inner (line , sizeof (line ), " MCUboot Partitions:" , INNER_WIDTH );
3526+ status_print_line (line , STATUS_WIDTH );
3527+
3528+ /* Display bootloader region (before first MCUboot image) */
3529+ if (mcuboot_parts [0 ].start > code_sad ) {
3530+ uint32_t bl_region_size = mcuboot_parts [0 ].start - code_sad ;
3531+ int bl_pct = (bl_region_size > 0 ) ? (int )((uint64_t )bl_used * 100 / bl_region_size ) : 0 ;
3532+ char used_str [16 ];
3533+ format_size (bl_region_size , size_str , sizeof (size_str ));
3534+ format_size (bl_used , used_str , sizeof (used_str ));
3535+ snprintf (content ,
3536+ sizeof (content ),
3537+ " 0x%08X %6s bootloader (%s used, %d%%)" ,
3538+ code_sad ,
3539+ size_str ,
3540+ used_str ,
3541+ bl_pct );
3542+ status_format_inner (line , sizeof (line ), content , INNER_WIDTH );
3543+ status_print_line (line , STATUS_WIDTH );
3544+ }
3545+
3546+ /* Display detected MCUboot images */
3547+ for (int i = 0 ; i < mcuboot_count ; i ++ ) {
3548+ /* Determine slot boundaries based on next image or flash layout */
3549+ uint32_t slot_start = mcuboot_parts [i ].start ;
3550+ uint32_t slot_end ;
3551+ if (i + 1 < mcuboot_count ) {
3552+ slot_end = mcuboot_parts [i + 1 ].start - 1 ;
3553+ } else {
3554+ /* Last image: estimate slot end based on typical storage reservation
3555+ * Common layouts reserve 48-64KB at end for storage/settings */
3556+ uint32_t storage_reserve = 48 * 1024 ;
3557+ if (code_ead > storage_reserve + mcuboot_parts [i ].start )
3558+ slot_end = code_ead - storage_reserve ;
3559+ else
3560+ slot_end = code_ead ;
3561+ }
3562+
3563+ uint32_t slot_size = slot_end - slot_start + 1 ;
3564+ uint32_t img_used = mcuboot_parts [i ].img_size ;
3565+ int slot_pct = (slot_size > 0 ) ? (int )((uint64_t )img_used * 100 / slot_size ) : 0 ;
3566+
3567+ /* Determine slot label based on position */
3568+ const char * slot_label ;
3569+ if (i == 0 && mcuboot_count >= 2 )
3570+ slot_label = "Bank0" ;
3571+ else if (i == 1 )
3572+ slot_label = "Bank1" ;
3573+ else
3574+ slot_label = "Image" ;
3575+
3576+ char used_str [16 ];
3577+ format_size (slot_size , size_str , sizeof (size_str ));
3578+ format_size (img_used , used_str , sizeof (used_str ));
3579+ snprintf (content ,
3580+ sizeof (content ),
3581+ " 0x%08X %6s v%u.%u.%u [%s] (%s used, %d%%)" ,
3582+ mcuboot_parts [i ].start ,
3583+ size_str ,
3584+ mcuboot_parts [i ].ver_major ,
3585+ mcuboot_parts [i ].ver_minor ,
3586+ mcuboot_parts [i ].ver_rev ,
3587+ slot_label ,
3588+ used_str ,
3589+ slot_pct );
3590+ status_format_inner (line , sizeof (line ), content , INNER_WIDTH );
3591+ status_print_line (line , STATUS_WIDTH );
3592+ }
3593+
3594+ /* Display storage region at end of flash */
3595+ if (storage_size > 0 ) {
3596+ int rem_pct = (storage_size > 0 ) ? (int )((uint64_t )storage_used * 100 / storage_size ) : 0 ;
3597+ char used_str [16 ];
3598+ format_size (storage_size , size_str , sizeof (size_str ));
3599+ format_size (storage_used , used_str , sizeof (used_str ));
3600+ snprintf (content ,
3601+ sizeof (content ),
3602+ " 0x%08X %6s storage (%s used, %d%%)" ,
3603+ storage_start ,
3604+ size_str ,
3605+ used_str ,
3606+ rem_pct );
3607+ status_format_inner (line , sizeof (line ), content , INNER_WIDTH );
3608+ status_print_line (line , STATUS_WIDTH );
3609+ }
3610+ }
3611+
33303612 /* Data Flash */
33313613 if (data_size > 0 ) {
33323614 /* Separator */
0 commit comments