@@ -176,6 +176,62 @@ ZTEST_F(zms, test_zms_write)
176176 execute_long_pattern_write (TEST_DATA_ID , & fixture -> fs );
177177}
178178
179+ /*
180+ * zms_recover_last_ate() scans allocation table slots downwards from the end
181+ * of a sector. As it finds external-data ATEs, their offset and aligned data
182+ * length establish the lower bound of that scan: slots below this boundary
183+ * belong to the data area and must not be interpreted as ATEs.
184+ *
185+ * An inline-data ATE following an external-data ATE must preserve that lower
186+ * bound. This test creates that sequence, embeds a CRC-valid ATE-shaped
187+ * pattern in the payload, and verifies that recovery does not scan far enough
188+ * to let the payload alter the recovered data write address.
189+ */
190+ ZTEST_F (zms , test_zms_mount_fake_ate )
191+ {
192+ struct zms_ate fake_ate ;
193+ uint8_t data [64 ];
194+ uint32_t inline_data = 0 ;
195+ int err ;
196+ ssize_t len ;
197+
198+ err = zms_mount (& fixture -> fs );
199+ zassert_ok (err , "zms_mount failed: %d" , err );
200+
201+ /* Fill the data record with erased bytes, then embed a valid-looking ATE. */
202+ memset (data , fixture -> fs .flash_parameters -> erase_value , sizeof (data ));
203+ memset (& fake_ate , 0 , sizeof (fake_ate ));
204+ fake_ate .cycle_cnt = fixture -> fs .sector_cycle ;
205+ fake_ate .len = 256 ;
206+ fake_ate .id = 0x01000100 ;
207+ fake_ate .offset = UINT32_MAX ;
208+ fake_ate .crc8 = crc8_ccitt (0xff ,
209+ (uint8_t * )& fake_ate + SIZEOF_FIELD (struct zms_ate , crc8 ),
210+ sizeof (fake_ate ) - SIZEOF_FIELD (struct zms_ate , crc8 ));
211+ memcpy (data + sizeof (fake_ate ), & fake_ate , sizeof (fake_ate ));
212+
213+ len = zms_write (& fixture -> fs , TEST_DATA_ID , data , sizeof (data ));
214+ zassert_equal (len , sizeof (data ), "zms_write failed: %zd" , len );
215+
216+ /*
217+ * The newer inline-data ATE is visited after the external-data ATE during
218+ * the downward scan. It verifies that this inline ATE preserves the data
219+ * boundary established by the external-data ATE.
220+ */
221+ len = zms_write (& fixture -> fs , TEST_DATA_ID + 1 , & inline_data , sizeof (inline_data ));
222+ zassert_equal (len , sizeof (inline_data ), "zms_write of inline data failed: %zd" , len );
223+
224+ /* Simulate a reboot so recovery, rather than the live cursors, is used. */
225+ memset (& fixture -> fs , 0 , sizeof (fixture -> fs ));
226+ (void )setup ();
227+ err = zms_mount (& fixture -> fs );
228+ zassert_ok (err , "zms_mount after reboot failed: %d" , err );
229+
230+ zassert_equal (fixture -> fs .data_wra , sizeof (data ),
231+ "data payload was mistaken for an ATE: data_wra=%llx" ,
232+ fixture -> fs .data_wra );
233+ }
234+
179235#ifdef CONFIG_TEST_ZMS_SIMULATOR
180236static int flash_sim_write_calls_find (struct stats_hdr * hdr , void * arg , const char * name ,
181237 uint16_t off )
0 commit comments