GCC Code Coverage Report


Directory: common/src/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 73.2% 52 / 0 / 71
Functions: 100.0% 1 / 0 / 1
Branches: 65.3% 49 / 0 / 75

lx_nor_flash_sector_write.c
Line Branch Exec Source
1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 * Copyright (c) 2026-present Eclipse ThreadX contributors
4 *
5 * This program and the accompanying materials are made available under the
6 * terms of the MIT License which is available at
7 * https://opensource.org/licenses/MIT.
8 *
9 * SPDX-License-Identifier: MIT
10 **************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** LevelX Component */
17 /** */
18 /** NOR Flash */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23 #define LX_SOURCE_CODE
24
25
26 /* Disable ThreadX error checking. */
27
28 #ifndef LX_DISABLE_ERROR_CHECKING
29 #define LX_DISABLE_ERROR_CHECKING
30 #endif
31
32
33 /* Include necessary system files. */
34
35 #include "lx_api.h"
36
37
38 /**************************************************************************/
39 /* */
40 /* FUNCTION RELEASE */
41 /* */
42 /* _lx_nor_flash_sector_write PORTABLE C */
43 /* 6.3.0 */
44 /* AUTHOR */
45 /* */
46 /* William E. Lamie, Microsoft Corporation */
47 /* */
48 /* DESCRIPTION */
49 /* */
50 /* This function writes a logical sector to the NOR flash. */
51 /* */
52 /* INPUT */
53 /* */
54 /* nor_flash NOR flash instance */
55 /* logical_sector Logical sector number */
56 /* buffer Pointer to buffer to write */
57 /* (the size is 512 bytes) */
58 /* */
59 /* OUTPUT */
60 /* */
61 /* return status */
62 /* */
63 /* CALLS */
64 /* */
65 /* _lx_nor_flash_driver_write Driver flash sector write */
66 /* _lx_nor_flash_driver_read Driver flash sector read */
67 /* _lx_nor_flash_block_reclaim Reclaim one flash block */
68 /* _lx_nor_flash_logical_sector_find Find logical sector */
69 /* _lx_nor_flash_physical_sector_allocate */
70 /* Allocate new physical sector */
71 /* _lx_nor_flash_sector_mapping_cache_invalidate */
72 /* Invalidate cache entry */
73 /* _lx_nor_flash_system_error Internal system error handler */
74 /* tx_mutex_get Get thread protection */
75 /* tx_mutex_put Release thread protection */
76 /* */
77 /* CALLED BY */
78 /* */
79 /* Application Code */
80 /* */
81 /**************************************************************************/
82 27560 UINT _lx_nor_flash_sector_write(LX_NOR_FLASH *nor_flash, ULONG logical_sector, VOID *buffer)
83 {
84
85 ULONG *old_mapping_address;
86 ULONG *old_sector_address;
87 ULONG old_mapping_entry;
88 ULONG *new_mapping_address;
89 ULONG *new_sector_address;
90 ULONG new_mapping_entry;
91 ULONG i;
92 LX_NOR_SECTOR_MAPPING_CACHE_ENTRY *sector_mapping_cache_entry_ptr;
93 UINT status;
94 #ifdef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
95 ULONG block;
96 #endif
97
98 #ifdef LX_THREAD_SAFE_ENABLE
99
100 /* Obtain the thread safe mutex. */
101 2756 tx_mutex_get(&nor_flash -> lx_nor_flash_mutex, TX_WAIT_FOREVER);
102 #endif
103
104 /* Determine if there are less than two block's worth of free sectors. */
105 27560 i = 0;
106
4/4
✓ Branch 7 → 3 taken 10260 times.
✓ Branch 7 → 8 taken 24804 times.
✓ Branch 8 → 4 taken 1140 times.
✓ Branch 8 → 9 taken 2756 times.
38960 while (nor_flash -> lx_nor_flash_free_physical_sectors <= nor_flash -> lx_nor_flash_physical_sectors_per_block)
107 {
108
109 /* Attempt to reclaim one physical block. */
110 11400 _lx_nor_flash_block_reclaim(nor_flash);
111
112 /* Increment the block count. */
113 11400 i++;
114
115 /* Have we exceeded the number of blocks in the system? */
116
2/4
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 10260 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 1140 times.
11400 if (i >= nor_flash -> lx_nor_flash_total_blocks)
117 {
118
119 /* Yes, break out of the loop. */
120 ✗ break;
121 }
122 }
123
124 /* Increment the number of write requests. */
125 27560 nor_flash -> lx_nor_flash_write_requests++;
126
127 /* See if we can find the sector in the current mapping. */
128 27560 _lx_nor_flash_logical_sector_find(nor_flash, logical_sector, LX_FALSE, &old_mapping_address, &old_sector_address);
129
130 /* Allocate a new physical sector for this write. */
131 27560 _lx_nor_flash_physical_sector_allocate(nor_flash, logical_sector, &new_mapping_address, &new_sector_address);
132
133 /* Determine if the new sector allocation was successful. */
134
2/7
✓ Branch 10 → 11 taken 24804 times.
✗ Branch 10 → 37 not taken.
✗ Branch 10 → 41 not taken.
✗ Branch 10 → 43 not taken.
✗ Branch 10 → 45 not taken.
✓ Branch 11 → 12 taken 2756 times.
✗ Branch 11 → 43 not taken.
27560 if (new_mapping_address)
135 {
136
137 /* Yes, we were able to allocate a new physical sector. */
138
139 /* Update the number of free physical sectors. */
140 27560 nor_flash -> lx_nor_flash_free_physical_sectors--;
141
142 /* Write the sector data to the new physical sector. */
143 27560 status = _lx_nor_flash_driver_write(nor_flash, new_sector_address, buffer, LX_NOR_SECTOR_SIZE);
144
145 /* Check for an error from flash driver. Drivers should never return an error.. */
146
2/4
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 15 taken 24804 times.
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 17 taken 2756 times.
27560 if (status)
147 {
148
149 /* Call system error handler. */
150 ✗ _lx_nor_flash_system_error(nor_flash, status);
151
152 #ifdef LX_THREAD_SAFE_ENABLE
153
154 /* Release the thread safe mutex. */
155 ✗ tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
156 #endif
157
158 /* Return status. */
159 ✗ return(LX_ERROR);
160 }
161
162 /* Was there a previously mapped sector? */
163
5/5
✓ Branch 15 → 16 taken 20142 times.
✓ Branch 15 → 20 taken 518 times.
✓ Branch 15 → 24 taken 4144 times.
✓ Branch 17 → 18 taken 2238 times.
✓ Branch 17 → 23 taken 518 times.
27560 if (old_mapping_address)
164 {
165
166 /* Now deprecate the old sector mapping. */
167
168 /* Read in the old sector mapping. */
169 #ifdef LX_DIRECT_READ
170
171 /* Read the word directly. */
172 4476 old_mapping_entry = *(old_mapping_address);
173 #else
174 17904 status = _lx_nor_flash_driver_read(nor_flash, old_mapping_address, &old_mapping_entry, 1);
175
176 /* Check for an error from flash driver. Drivers should never return an error.. */
177
1/2
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 20 taken 17904 times.
17904 if (status)
178 {
179
180 /* Call system error handler. */
181 ✗ _lx_nor_flash_system_error(nor_flash, status);
182
183 #ifdef LX_THREAD_SAFE_ENABLE
184
185 /* Release the thread safe mutex. */
186 tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
187 #endif
188
189 /* Return status. */
190 ✗ return(LX_ERROR);
191 }
192 #endif
193
194 /* Clear bit 30, which indicates this sector is superceded. */
195 22380 old_mapping_entry = old_mapping_entry & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_SUPERCEDED);
196
197 /* Write the value back to the flash to clear bit 30. */
198 22380 status = _lx_nor_flash_driver_write(nor_flash, old_mapping_address, &old_mapping_entry, 1);
199
200 /* Check for an error from flash driver. Drivers should never return an error.. */
201
3/6
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 20 taken 2238 times.
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 23 taken 2238 times.
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 24 taken 17904 times.
22380 if (status)
202 {
203
204 /* Call system error handler. */
205 ✗ _lx_nor_flash_system_error(nor_flash, status);
206
207 #ifdef LX_THREAD_SAFE_ENABLE
208
209 /* Release the thread safe mutex. */
210 ✗ tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
211 #endif
212
213 /* Return status. */
214 ✗ return(LX_ERROR);
215 }
216 }
217
218 /* Now build the new mapping entry - with the not valid bit set initially. */
219 27560 new_mapping_entry = ((ULONG) LX_NOR_PHYSICAL_SECTOR_VALID) | ((ULONG) LX_NOR_PHYSICAL_SECTOR_SUPERCEDED) | ((ULONG) LX_NOR_PHYSICAL_SECTOR_MAPPING_NOT_VALID) | logical_sector;
220
221 /* Write out the new mapping entry. */
222 27560 status = _lx_nor_flash_driver_write(nor_flash, new_mapping_address, &new_mapping_entry, 1);
223
224 /* Check for an error from flash driver. Drivers should never return an error.. */
225
3/6
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 24 taken 2756 times.
✗ Branch 24 → 25 not taken.
✓ Branch 24 → 28 taken 2756 times.
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 28 taken 22048 times.
27560 if (status)
226 {
227
228 /* Call system error handler. */
229 ✗ _lx_nor_flash_system_error(nor_flash, status);
230
231 #ifdef LX_THREAD_SAFE_ENABLE
232
233 /* Release the thread safe mutex. */
234 ✗ tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
235 #endif
236
237 /* Return status. */
238 ✗ return(LX_ERROR);
239 }
240
241 /* Now clear the not valid bit to make this sector mapping valid. This is done because the writing of the extra bytes itself can
242 be interrupted and we need to make sure this can be detected when the flash is opened again. */
243 27560 new_mapping_entry = new_mapping_entry & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_MAPPING_NOT_VALID);
244
245 /* Clear the not valid bit. */
246 27560 status = _lx_nor_flash_driver_write(nor_flash, new_mapping_address, &new_mapping_entry, 1);
247
248 /* Check for an error from flash driver. Drivers should never return an error.. */
249
3/5
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 28 taken 2756 times.
✗ Branch 29 → 30 not taken.
✓ Branch 29 → 32 taken 22048 times.
✓ Branch 29 → 33 taken 2756 times.
27560 if (status)
250 {
251
252 /* Call system error handler. */
253 ✗ _lx_nor_flash_system_error(nor_flash, status);
254
255 #ifdef LX_THREAD_SAFE_ENABLE
256
257 /* Release the thread safe mutex. */
258 ✗ tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
259 #endif
260
261 /* Return status. */
262 ✗ return(LX_ERROR);
263 }
264 #ifndef LX_NOR_DISABLE_EXTENDED_CACHE
265 #ifdef LX_NOR_ENABLE_MAPPING_BITMAP
266
267 /* Determine if the logical sector is within the mapping bitmap. */
268
2/2
✓ Branch 32 → 33 taken 2856 times.
✓ Branch 32 → 34 taken 2656 times.
5512 if (logical_sector < nor_flash -> lx_nor_flash_extended_cache_mapping_bitmap_max_logical_sector)
269 {
270
271 /* Set the bit in the mapping bitmap. */
272 2856 nor_flash -> lx_nor_flash_extended_cache_mapping_bitmap[logical_sector >> 5] |= (ULONG)(1 << (logical_sector & 31));
273 }
274 #endif
275 #endif
276
277 /* Increment the number of mapped physical sectors. */
278 27560 nor_flash -> lx_nor_flash_mapped_physical_sectors++;
279
280 /* Was there a previously mapped sector? */
281
10/10
✓ Branch 28 → 29 taken 2238 times.
✓ Branch 28 → 34 taken 518 times.
✓ Branch 32 → 33 taken 13428 times.
✓ Branch 32 → 38 taken 2590 times.
✓ Branch 32 → 40 taken 518 times.
✓ Branch 33 → 34 taken 2238 times.
✓ Branch 33 → 40 taken 518 times.
✓ Branch 34 → 35 taken 4476 times.
✓ Branch 34 → 40 taken 518 times.
✓ Branch 34 → 42 taken 518 times.
27560 if (old_mapping_address)
282 {
283
284 /* Now clear bit 31, which indicates this sector is now obsoleted. */
285 22380 old_mapping_entry = old_mapping_entry & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_VALID);
286
287 /* Write the value back to the flash to clear bit 31. */
288 22380 status = _lx_nor_flash_driver_write(nor_flash, old_mapping_address, &old_mapping_entry, 1);
289
290 /* Check for an error from flash driver. Drivers should never return an error.. */
291
4/8
✗ Branch 30 → 31 not taken.
✓ Branch 30 → 33 taken 2238 times.
✗ Branch 34 → 35 not taken.
✓ Branch 34 → 37 taken 13428 times.
✗ Branch 35 → 36 not taken.
✓ Branch 35 → 39 taken 2238 times.
✗ Branch 36 → 37 not taken.
✓ Branch 36 → 39 taken 4476 times.
22380 if (status)
292 {
293
294 /* Call system error handler. */
295 ✗ _lx_nor_flash_system_error(nor_flash, status);
296
297 #ifdef LX_THREAD_SAFE_ENABLE
298
299 /* Release the thread safe mutex. */
300 ✗ tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
301 #endif
302
303 /* Return status. */
304 ✗ return(LX_ERROR);
305 }
306
307 /* Increment the number of obsolete physical sectors. */
308 22380 nor_flash -> lx_nor_flash_obsolete_physical_sectors++;
309
310 #ifdef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
311
312 /* Get the block number from mapping address. */
313 4476 block = (ULONG)(old_mapping_address - nor_flash -> lx_nor_flash_base_address) / nor_flash -> lx_nor_flash_words_per_block;
314
315 /* Determine if this block is within the range of the obsolete count cache. */
316
4/4
✓ Branch 37 → 38 taken 1119 times.
✓ Branch 37 → 39 taken 1119 times.
✓ Branch 39 → 40 taken 1119 times.
✓ Branch 39 → 41 taken 1119 times.
4476 if (block < nor_flash -> lx_nor_flash_extended_cache_obsolete_count_max_block)
317 {
318
319 /* Increment the obsolete count for this block. */
320 2238 nor_flash -> lx_nor_flash_extended_cache_obsolete_count[block] ++;
321 }
322 #endif
323
324 /* Decrement the number of mapped physical sectors. */
325 22380 nor_flash -> lx_nor_flash_mapped_physical_sectors--;
326
327 /* Invalidate the old sector mapping cache entry. */
328 22380 _lx_nor_flash_sector_mapping_cache_invalidate(nor_flash, logical_sector);
329 }
330
331 /* Determine if the sector mapping cache is enabled. */
332
4/8
✓ Branch 34 → 35 taken 2756 times.
✗ Branch 34 → 36 not taken.
✓ Branch 38 → 39 taken 13780 times.
✗ Branch 38 → 40 not taken.
✓ Branch 40 → 41 taken 8268 times.
✗ Branch 40 → 42 not taken.
✓ Branch 42 → 43 taken 2756 times.
✗ Branch 42 → 44 not taken.
27560 if (nor_flash -> lx_nor_flash_sector_mapping_cache_enabled)
333 {
334
335 /* Yes, sector mapping cache is enabled, place this sector information in the cache. */
336
337 /* Calculate the starting index of the sector mapping cache for this sector entry. */
338 27560 i = (logical_sector & LX_NOR_SECTOR_MAPPING_CACHE_HASH_MASK) * LX_NOR_SECTOR_MAPPING_CACHE_DEPTH;
339
340 /* Build a pointer to the cache entry. */
341 27560 sector_mapping_cache_entry_ptr = &nor_flash -> lx_nor_flash_sector_mapping_cache[i];
342
343 /* Move all the cache entries down so the oldest is at the bottom. */
344 27560 *(sector_mapping_cache_entry_ptr + 3) = *(sector_mapping_cache_entry_ptr + 2);
345 27560 *(sector_mapping_cache_entry_ptr + 2) = *(sector_mapping_cache_entry_ptr + 1);
346 27560 *(sector_mapping_cache_entry_ptr + 1) = *(sector_mapping_cache_entry_ptr);
347
348 /* Setup the new sector information in the cache. */
349 27560 sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_logical_sector = (logical_sector | LX_NOR_SECTOR_MAPPING_CACHE_ENTRY_VALID);
350 27560 sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_physical_sector_map_entry = new_mapping_address;
351 27560 sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_physical_sector_address = new_sector_address;
352 }
353
354 /* Indicate the write was successful. */
355 27560 status = LX_SUCCESS;
356 }
357 else
358 {
359
360 /* Indicate the write was unsuccessful. */
361 ✗ status = LX_NO_SECTORS;
362 }
363
364 #ifdef LX_THREAD_SAFE_ENABLE
365
366 /* Release the thread safe mutex. */
367 2756 tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
368 #endif
369
370 /* Return the completion status. */
371 27560 return(status);
372 }
373
374
375