23
23
#include <string.h>
24
24
#include "bootutil/bootutil.h"
25
25
#include "bootutil_priv.h"
26
+ #include "bootutil_misc.h"
26
27
#include "swap_priv.h"
27
28
#include "bootutil/bootutil_log.h"
28
29
@@ -68,6 +69,123 @@ find_last_idx(struct boot_loader_state *state, uint32_t swap_size)
68
69
return last_idx ;
69
70
}
70
71
72
+ /**
73
+ * Returns the index of the sector containing the fallback trailer in the primary slot.
74
+ *
75
+ * The fallback trailer is needed during a revert process, in case a reboot occurs between the time
76
+ * the primary slot's trailer is erased and the time it is fully rewritten. When this happens, the
77
+ * bootloader will be able to detect that a revert process was in progress by the looking at the
78
+ * fallback trailer. The fallback trailer is located in the last sector of the primary slot that
79
+ * doesn't contain part of the slot's trailer, so in other words, in the sector right before the
80
+ * first sector holding part of the slot's trailer. It is written at the end of the upgrade process.
81
+ *
82
+ * Example:
83
+ * PRIMARY
84
+ * | ... |
85
+ * +-----------------------+
86
+ * | Firmware (3968 bytes) | Sector N-2
87
+ * | Padding (128 bytes) | <---- Fallback trailer stored here
88
+ * +-----------------------+
89
+ * | Padding (3968 bytes) | Sector N-1
90
+ * | Trailer (128 bytes) |
91
+ * +-----------------------+
92
+ * | Trailer (4096 bytes) | Sector N
93
+ * | . |
94
+ * +-----------------------+
95
+ *
96
+ * @param state Current bootloader's state.
97
+ *
98
+ * @return The index of the sector containg the fallback trailer in the primary slot.
99
+ */
100
+ static size_t
101
+ get_fallback_trailer_sector (struct boot_loader_state * state )
102
+ {
103
+ size_t first_trailer_sector = boot_get_first_trailer_sector (state , BOOT_PRIMARY_SLOT );
104
+
105
+ return first_trailer_sector - 1 ;
106
+ }
107
+
108
+ /**
109
+ * Returns the offset of the fallback trailer in the primary slot.
110
+ *
111
+ * The fallback trailer is composed only of the magic field. When computing the maximum image size,
112
+ * it is ensured at least BOOT_MAGIC_ALIGN_SIZE bytes are available at the end of the firmware image
113
+ * to write the fallback trailer.
114
+ *
115
+ * @param state Current bootloader's state.
116
+ *
117
+ * @return The offset of the fallback trailer in the primary slot.
118
+ */
119
+ static uint32_t
120
+ get_fallback_trailer_off (struct boot_loader_state * state )
121
+ {
122
+ size_t fallback_trailer_sector = get_fallback_trailer_sector (state );
123
+ size_t end_off = boot_img_sector_off (state , BOOT_PRIMARY_SLOT , fallback_trailer_sector + 1 );
124
+
125
+ return end_off - BOOT_MAGIC_ALIGN_SIZE ;
126
+ }
127
+
128
+ /**
129
+ * Writes the fallback trailer in the primary slot.
130
+ *
131
+ * @param state Current bootloader's state.
132
+ * @param need_erase True if the sector has to be erased before writing, false otherwise.
133
+ */
134
+ static void
135
+ write_fallback_trailer (struct boot_loader_state * state , bool need_erase )
136
+ {
137
+ int rc ;
138
+ uint32_t fallback_trailer_off ;
139
+ const struct flash_area * fap_pri ;
140
+
141
+ fap_pri = BOOT_IMG_AREA (state , BOOT_PRIMARY_SLOT );
142
+ assert (fap_pri != NULL );
143
+
144
+ if (need_erase ) {
145
+ size_t fallback_trailer_sector = get_fallback_trailer_sector (state );
146
+ uint32_t sector_off = boot_img_sector_off (state , BOOT_PRIMARY_SLOT , fallback_trailer_sector );
147
+ uint32_t sector_sz = boot_img_sector_size (state , BOOT_PRIMARY_SLOT , 0 );
148
+
149
+ rc = boot_erase_region (fap_pri , sector_off , sector_sz );
150
+ assert (rc == 0 );
151
+ }
152
+
153
+ fallback_trailer_off = get_fallback_trailer_off (state );
154
+
155
+ rc = boot_write_magic_at_off (fap_pri , fallback_trailer_off );
156
+ assert (rc == 0 );
157
+ }
158
+
159
+ /**
160
+ * Reads the magic field of the fallback trailer.
161
+ *
162
+ * @param state Current bootloader's state.
163
+ *
164
+ * @return BOOT_MAGIC_GOOD if the magic is valid, BOOT_MAGIC_BAD otherwise.
165
+ */
166
+ static int
167
+ read_fallback_trailer_magic (struct boot_loader_state * state )
168
+ {
169
+ int rc ;
170
+ const struct flash_area * fap_pri ;
171
+ uint32_t fallback_trailer_off ;
172
+ uint32_t magic_off ;
173
+ uint8_t magic [BOOT_MAGIC_SZ ];
174
+
175
+ fap_pri = BOOT_IMG_AREA (state , BOOT_PRIMARY_SLOT );
176
+ assert (fap_pri != NULL );
177
+
178
+ fallback_trailer_off = get_fallback_trailer_off (state );
179
+
180
+ /* The magic has to be read without including the padding */
181
+ magic_off = fallback_trailer_off + BOOT_MAGIC_ALIGN_SIZE - BOOT_MAGIC_SZ ;
182
+
183
+ rc = flash_area_read (fap_pri , magic_off , magic , BOOT_MAGIC_SZ );
184
+ assert (rc == 0 );
185
+
186
+ return boot_magic_decode (magic );
187
+ }
188
+
71
189
int
72
190
boot_read_image_header (struct boot_loader_state * state , int slot ,
73
191
struct image_header * out_hdr , struct boot_status * bs )
@@ -337,6 +455,8 @@ boot_slots_compatible(struct boot_loader_state *state)
337
455
int
338
456
swap_status_source (struct boot_loader_state * state )
339
457
{
458
+ const struct flash_area * fap_pri ;
459
+ const struct flash_area * fap_sec ;
340
460
struct boot_swap_state state_primary_slot ;
341
461
struct boot_swap_state state_secondary_slot ;
342
462
int rc ;
@@ -349,14 +469,18 @@ swap_status_source(struct boot_loader_state *state)
349
469
350
470
image_index = BOOT_CURR_IMG (state );
351
471
352
- rc = boot_read_swap_state (state -> imgs [image_index ][BOOT_PRIMARY_SLOT ].area ,
353
- & state_primary_slot );
472
+ fap_pri = BOOT_IMG_AREA (state , BOOT_PRIMARY_SLOT );
473
+ assert (fap_pri != NULL );
474
+
475
+ fap_sec = BOOT_IMG_AREA (state , BOOT_SECONDARY_SLOT );
476
+ assert (fap_sec != NULL );
477
+
478
+ rc = boot_read_swap_state (fap_pri , & state_primary_slot );
354
479
assert (rc == 0 );
355
480
356
481
BOOT_LOG_SWAP_STATE ("Primary image" , & state_primary_slot );
357
482
358
- rc = boot_read_swap_state (state -> imgs [image_index ][BOOT_SECONDARY_SLOT ].area ,
359
- & state_secondary_slot );
483
+ rc = boot_read_swap_state (fap_sec , & state_secondary_slot );
360
484
assert (rc == 0 );
361
485
362
486
BOOT_LOG_SWAP_STATE ("Secondary image" , & state_secondary_slot );
@@ -376,6 +500,31 @@ swap_status_source(struct boot_loader_state *state)
376
500
return source ;
377
501
}
378
502
503
+ /* If both primary and secondary trailers are absent and the fallback trailer is present, it
504
+ * means a revert process was interrupted in the middle of rewriting of the primary trailer.
505
+ * This can only happen at the very beggining of the revert process.
506
+ */
507
+ if (state_primary_slot .magic != BOOT_MAGIC_GOOD &&
508
+ state_secondary_slot .magic != BOOT_MAGIC_GOOD &&
509
+ read_fallback_trailer_magic (state ) == BOOT_MAGIC_GOOD ) {
510
+ /* In that case, the primary trailer is rewritten with just enough data to allow to the
511
+ * revert process to be resumed. Only the swap-type and the magic are needed since we are at
512
+ * the beginning of the revert process so the process has to be restarted from scratch,
513
+ * which will rewrite the primary trailer with all required data (swap size, encryption
514
+ * keys, ...).
515
+ */
516
+ rc = swap_scramble_trailer_sectors (state , fap_pri );
517
+ assert (rc == 0 );
518
+
519
+ rc = boot_write_swap_info (fap_pri , BOOT_SWAP_TYPE_REVERT , image_index );
520
+ assert (rc == 0 );
521
+
522
+ rc = boot_write_magic (fap_pri );
523
+ assert (rc == 0 );
524
+
525
+ return BOOT_STATUS_SOURCE_PRIMARY_SLOT ;
526
+ }
527
+
379
528
BOOT_LOG_INF ("Boot source: none" );
380
529
return BOOT_STATUS_SOURCE_NONE ;
381
530
}
@@ -460,10 +609,28 @@ boot_swap_sectors(size_t idx, size_t last_idx, uint32_t sz, struct boot_loader_s
460
609
sec_off = boot_img_sector_off (state , BOOT_SECONDARY_SLOT , idx - 1 );
461
610
462
611
if (bs -> state == BOOT_STATUS_STATE_0 ) {
612
+ uint32_t copy_sz = sz ;
613
+ size_t fallback_trailer_sector = get_fallback_trailer_sector (state );
614
+
463
615
rc = boot_erase_region (fap_pri , pri_off , sz );
464
616
assert (rc == 0 );
465
617
466
- rc = boot_copy_region (state , fap_sec , fap_pri , sec_off , pri_off , sz );
618
+ /* The last sector containing part of the firmware image is about to be written to the
619
+ * primary slot. If we are not reverting, a fallback trailer must be written in case a
620
+ * revert is performed later and is interrupted. The fallback trailer is located in the last
621
+ * sector not containing part of the slot's trailer. This sector can be the one being
622
+ * written at this step, so in that case write the fallback trailer now. Otherwise, it will
623
+ * be written at the very end of the swap.
624
+ */
625
+ if (fallback_trailer_sector == idx - 1 && bs -> swap_type != BOOT_SWAP_TYPE_REVERT ) {
626
+ /* The sector has already been erased, no need to erase twice */
627
+ write_fallback_trailer (state , false);
628
+
629
+ /* Adjust the copy size to ensure the fallback trailer won't be rewritten. */
630
+ copy_sz = bs -> swap_size % sz ;
631
+ }
632
+
633
+ rc = boot_copy_region (state , fap_sec , fap_pri , sec_off , pri_off , copy_sz );
467
634
assert (rc == 0 );
468
635
469
636
rc = boot_write_status (state , bs );
@@ -518,55 +685,6 @@ boot_swap_sectors(size_t idx, size_t last_idx, uint32_t sz, struct boot_loader_s
518
685
}
519
686
}
520
687
521
- /*
522
- * When starting a revert the swap status exists in the primary slot, and
523
- * the status in the secondary slot is erased. To start the swap, the status
524
- * area in the primary slot must be re-initialized; if during the small
525
- * window of time between re-initializing it and writing the first metadata
526
- * a reset happens, the swap process is broken and cannot be resumed.
527
- *
528
- * This function handles the issue by making the revert look like a permanent
529
- * upgrade (by initializing the secondary slot).
530
- */
531
- void
532
- fixup_revert (const struct boot_loader_state * state , struct boot_status * bs ,
533
- const struct flash_area * fap_sec )
534
- {
535
- struct boot_swap_state swap_state ;
536
- int rc ;
537
-
538
- #if (BOOT_IMAGE_NUMBER == 1 )
539
- (void )state ;
540
- #endif
541
-
542
- /* No fixup required */
543
- if (bs -> swap_type != BOOT_SWAP_TYPE_REVERT ||
544
- bs -> op != BOOT_STATUS_OP_MOVE ||
545
- bs -> idx != BOOT_STATUS_IDX_0 ) {
546
- return ;
547
- }
548
-
549
- rc = boot_read_swap_state (fap_sec , & swap_state );
550
- assert (rc == 0 );
551
-
552
- BOOT_LOG_SWAP_STATE ("Secondary image" , & swap_state );
553
-
554
- if (swap_state .magic == BOOT_MAGIC_UNSET ) {
555
- /* Remove trailer and prepare area for write on devices requiring erase */
556
- rc = swap_scramble_trailer_sectors (state , fap_sec );
557
- assert (rc == 0 );
558
-
559
- rc = boot_write_image_ok (fap_sec );
560
- assert (rc == 0 );
561
-
562
- rc = boot_write_swap_size (fap_sec , bs -> swap_size );
563
- assert (rc == 0 );
564
-
565
- rc = boot_write_magic (fap_sec );
566
- assert (rc == 0 );
567
- }
568
- }
569
-
570
688
void
571
689
swap_run (struct boot_loader_state * state , struct boot_status * bs ,
572
690
uint32_t copy_size )
@@ -577,6 +695,7 @@ swap_run(struct boot_loader_state *state, struct boot_status *bs,
577
695
uint32_t trailer_sz ;
578
696
uint32_t first_trailer_idx ;
579
697
uint32_t last_idx ;
698
+ size_t fallback_trailer_sector ;
580
699
const struct flash_area * fap_pri ;
581
700
const struct flash_area * fap_sec ;
582
701
@@ -617,8 +736,6 @@ swap_run(struct boot_loader_state *state, struct boot_status *bs,
617
736
fap_sec = BOOT_IMG_AREA (state , BOOT_SECONDARY_SLOT );
618
737
assert (fap_sec != NULL );
619
738
620
- fixup_revert (state , bs , fap_sec );
621
-
622
739
if (bs -> op == BOOT_STATUS_OP_MOVE ) {
623
740
idx = last_idx ;
624
741
while (idx > 0 ) {
@@ -639,6 +756,18 @@ swap_run(struct boot_loader_state *state, struct boot_status *bs,
639
756
}
640
757
idx ++ ;
641
758
}
759
+
760
+ /* The swap is done, if we are upgrading and the fallback trailer has not been written during
761
+ * the swap, write it now. This is necessary if the fallback trailer sector is not part of the
762
+ * sectors that have been swapped, either because the images are not large enough to include
763
+ * that sector, or because the trailer is sector-aligned and the fallback trailer is therefore
764
+ * stored at the end of the padding sector.
765
+ */
766
+ fallback_trailer_sector = get_fallback_trailer_sector (state );
767
+
768
+ if (last_idx <= fallback_trailer_sector && bs -> swap_type != BOOT_SWAP_TYPE_REVERT ) {
769
+ write_fallback_trailer (state , true);
770
+ }
642
771
}
643
772
644
773
int app_max_size (struct boot_loader_state * state )
0 commit comments