GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lx_nor_flash_sector_write.c Lines: 44 58 75.9 %
Date: 2026-03-06 18:45:40 Branches: 15 24 62.5 %

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
2756
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
    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
2756
    i =  0;
106
3896
    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
1140
        _lx_nor_flash_block_reclaim(nor_flash);
111
112
        /* Increment the block count.  */
113
1140
        i++;
114
115
        /* Have we exceeded the number of blocks in the system?  */
116
1140
        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
2756
    nor_flash -> lx_nor_flash_write_requests++;
126
127
    /* See if we can find the sector in the current mapping.  */
128
2756
    _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
2756
    _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
2756
    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
2756
        nor_flash -> lx_nor_flash_free_physical_sectors--;
141
142
        /* Write the sector data to the new physical sector.  */
143
2756
        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
2756
        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
2756
        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
            old_mapping_entry =  *(old_mapping_address);
173
#else
174
2238
            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
2238
            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
2238
            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
2238
            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
2238
            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
2756
        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
2756
        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
2756
        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
2756
        new_mapping_entry =  new_mapping_entry & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_MAPPING_NOT_VALID);
244
245
        /* Clear the not valid bit.  */
246
2756
        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
2756
        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
        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
            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
2756
        nor_flash -> lx_nor_flash_mapped_physical_sectors++;
279
280
        /* Was there a previously mapped sector?  */
281
2756
        if (old_mapping_address)
282
        {
283
284
            /* Now clear bit 31, which indicates this sector is now obsoleted.  */
285
2238
            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
2238
            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
2238
            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
2238
            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
            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
            if (block < nor_flash -> lx_nor_flash_extended_cache_obsolete_count_max_block)
317
            {
318
319
                /* Increment the obsolete count for this block.  */
320
                nor_flash -> lx_nor_flash_extended_cache_obsolete_count[block] ++;
321
            }
322
#endif
323
324
            /* Decrement the number of mapped physical sectors.  */
325
2238
            nor_flash -> lx_nor_flash_mapped_physical_sectors--;
326
327
            /* Invalidate the old sector mapping cache entry.  */
328
2238
            _lx_nor_flash_sector_mapping_cache_invalidate(nor_flash, logical_sector);
329
        }
330
331
        /* Determine if the sector mapping cache is enabled.  */
332
2756
        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
2756
            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
2756
            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
2756
            *(sector_mapping_cache_entry_ptr + 3) =  *(sector_mapping_cache_entry_ptr + 2);
345
2756
            *(sector_mapping_cache_entry_ptr + 2) =  *(sector_mapping_cache_entry_ptr + 1);
346
2756
            *(sector_mapping_cache_entry_ptr + 1) =  *(sector_mapping_cache_entry_ptr);
347
348
            /* Setup the new sector information in the cache.  */
349
2756
            sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_logical_sector =             (logical_sector | LX_NOR_SECTOR_MAPPING_CACHE_ENTRY_VALID);
350
2756
            sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_physical_sector_map_entry =  new_mapping_address;
351
2756
            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
2756
        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
    tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
368
#endif
369
370
    /* Return the completion status.  */
371
2756
    return(status);
372
}
373
374