mirror of
https://github.com/eclipse-threadx/levelx.git
synced 2026-09-14 20:48:51 +08:00
Compare commits
13
Commits
v6.5.0.202601_rel
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9be61b19fd | ||
|
|
9f1cfdc181 | ||
|
|
37dd169031 | ||
|
|
45984203fa | ||
|
|
309d2bd91b | ||
|
|
6122a080be | ||
|
|
3729d2f2c2 | ||
|
|
c232f9f8e3 | ||
|
|
4005a425b7 | ||
|
|
123218cc51 | ||
|
|
b9f54b87bb | ||
|
|
2e061ba319 | ||
|
|
bfb39676df |
+30
-11
@@ -1,20 +1,39 @@
|
|||||||
# Security Policy
|
# Security Policy
|
||||||
|
|
||||||
|
This Eclipse Foundation Project adheres to the [Eclipse Foundation Vulnerability Reporting Policy](https://www.eclipse.org/security/policy/).
|
||||||
|
|
||||||
|
## How To Report a Vulnerability
|
||||||
|
|
||||||
|
If you think you have found a vulnerability in this repository, please report it to us through coordinated disclosure.
|
||||||
|
|
||||||
|
**Please do not report security vulnerabilities through public issues, discussions, or change requests.**
|
||||||
|
|
||||||
|
Instead, [report it privately here](https://github.com/eclipse-threadx/levelx/security/advisories/new) on GitHub
|
||||||
|
|
||||||
|
You can find more information about reporting and disclosure at the [Eclipse Foundation Security page](https://www.eclipse.org/security/).
|
||||||
|
|
||||||
|
Please include as much of the information listed below as you can to help us better understand and resolve the issue:
|
||||||
|
|
||||||
|
* The type of issue (e.g., buffer overflow, SQL injection, or cross-site scripting)
|
||||||
|
* Affected version(s)
|
||||||
|
* Impact of the issue, including how an attacker might exploit the issue
|
||||||
|
* Step-by-step instructions to reproduce the issue
|
||||||
|
* The location of the affected source code (tag/branch/commit or direct URL)
|
||||||
|
* Full paths of source file(s) related to the manifestation of the issue
|
||||||
|
* Configuration required to reproduce the issue
|
||||||
|
* Log files that are related to this issue (if possible)
|
||||||
|
* Proof-of-concept or exploit code (if possible)
|
||||||
|
|
||||||
|
This information will help us triage your report more quickly.
|
||||||
|
|
||||||
## Supported Versions
|
## Supported Versions
|
||||||
|
|
||||||
| Version | Supported |
|
| Version | Supported |
|
||||||
| ------- | ------------------ |
|
| ------- | ------------------ |
|
||||||
| 6.4.x | :white_check_mark: |
|
| 6.5.x | :white_check_mark: |
|
||||||
|
|
||||||
## Reporting a Vulnerability
|
Eclipse ThreadX publishes a release every quarter. There are no long-term support branches or backports to older releases.
|
||||||
|
|
||||||
If you think you have found a vulnerability in <project> you can report it using one of the following ways:
|
Normally, fixes for non-critical vulnerabilities will ship in a regularly scheduled quarterly release. If fixes for an urgent or critical vulnerability must ship quickly, then the project will publish a hotfix release of the affected component(s) without waiting for the next quarterly release.
|
||||||
|
|
||||||
* Contact the [Eclipse Foundation Security Team](mailto:security@eclipse-foundation.org)
|
You can learn more about the [project's release cadence in this blog post](https://blogs.eclipse.org/post/fr%C3%A9d%C3%A9ric-desbiens/eclipse-threadx-more-predictable-more-open).
|
||||||
* [Report a Vulnerability](https://github.com/eclipse-threadx/levelx/security/advisories/new)
|
|
||||||
|
|
||||||
You can find more information about reporting and disclosure at the [Eclipse Foundation Security page](https://www.eclipse.org/security/).
|
|
||||||
|
|
||||||
## Security Policy
|
|
||||||
|
|
||||||
This project follows [Eclipse Foundation Vulnerability Reporting Policy](https://www.eclipse.org/security/policy/).
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ target_sources(${PROJECT_NAME} PRIVATE
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_format_extended.c
|
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_format_extended.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_free_block_list_add.c
|
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_free_block_list_add.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_initialize.c
|
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_initialize.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_logical_group_compact.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_mapped_block_list_add.c
|
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_mapped_block_list_add.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_mapped_block_list_get.c
|
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_mapped_block_list_get.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_mapped_block_list_remove.c
|
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_mapped_block_list_remove.c
|
||||||
|
|||||||
+30
-3
@@ -10,6 +10,8 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
|
// Some portions generated by Codex (GPT-5).
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
@@ -149,8 +151,8 @@ typedef unsigned long long ULONG64;
|
|||||||
#define AZURE_RTOS_LEVELX
|
#define AZURE_RTOS_LEVELX
|
||||||
#define LEVELX_MAJOR_VERSION 6
|
#define LEVELX_MAJOR_VERSION 6
|
||||||
#define LEVELX_MINOR_VERSION 5
|
#define LEVELX_MINOR_VERSION 5
|
||||||
#define LEVELX_PATCH_VERSION 0
|
#define LEVELX_PATCH_VERSION 1
|
||||||
#define LEVELX_BUILD_VERSION 202601
|
#define LEVELX_BUILD_VERSION 202602
|
||||||
#define LEVELX_HOTFIX_VERSION ' '
|
#define LEVELX_HOTFIX_VERSION ' '
|
||||||
|
|
||||||
|
|
||||||
@@ -274,6 +276,17 @@ typedef unsigned long long ULONG64;
|
|||||||
#define LX_NAND_FLASH_MAX_METADATA_BLOCKS 4
|
#define LX_NAND_FLASH_MAX_METADATA_BLOCKS 4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* When LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE is defined, sector releases from full blocks
|
||||||
|
are deferred when free block count exceeds the threshold below (opt-in, default: off).
|
||||||
|
Requires pages_per_block <= 4095 (bit 12 is reserved for COMPACTION_PENDING flag). */
|
||||||
|
/* #define LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE */
|
||||||
|
|
||||||
|
#ifdef LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE
|
||||||
|
#ifndef LX_NAND_FLASH_SECTOR_RELEASE_LAZY_THRESHOLD
|
||||||
|
#define LX_NAND_FLASH_SECTOR_RELEASE_LAZY_THRESHOLD 10u
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef LX_UTILITY_SHORT_SET
|
#ifndef LX_UTILITY_SHORT_SET
|
||||||
#define LX_UTILITY_SHORT_SET(address, value) *((USHORT*)(address)) = (USHORT)(value)
|
#define LX_UTILITY_SHORT_SET(address, value) *((USHORT*)(address)) = (USHORT)(value)
|
||||||
#endif
|
#endif
|
||||||
@@ -328,6 +341,11 @@ typedef unsigned long long ULONG64;
|
|||||||
#define LX_NAND_BLOCK_STATUS_FULL 0x4000u
|
#define LX_NAND_BLOCK_STATUS_FULL 0x4000u
|
||||||
#define LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL 0x2000u
|
#define LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL 0x2000u
|
||||||
#define LX_NAND_BLOCK_STATUS_MAPPING_PRESENT 0x1000u
|
#define LX_NAND_BLOCK_STATUS_MAPPING_PRESENT 0x1000u
|
||||||
|
#ifdef LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE
|
||||||
|
/* Repurpose the otherwise-unused MAPPING_PRESENT bit to signal a block whose compaction
|
||||||
|
has been deferred. Only valid when pages_per_block <= 4095. */
|
||||||
|
#define LX_NAND_BLOCK_STATUS_COMPACTION_PENDING LX_NAND_BLOCK_STATUS_MAPPING_PRESENT
|
||||||
|
#endif
|
||||||
#define LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK 0x0FFFu
|
#define LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK 0x0FFFu
|
||||||
#define LX_NAND_BLOCK_STATUS_FREE 0xFFFFu
|
#define LX_NAND_BLOCK_STATUS_FREE 0xFFFFu
|
||||||
#define LX_NAND_BLOCK_STATUS_BAD 0xFF00u
|
#define LX_NAND_BLOCK_STATUS_BAD 0xFF00u
|
||||||
@@ -402,6 +420,12 @@ typedef struct LX_NAND_FLASH_STRUCT
|
|||||||
USHORT *lx_nand_flash_block_list;
|
USHORT *lx_nand_flash_block_list;
|
||||||
ULONG lx_nand_flash_block_list_size;
|
ULONG lx_nand_flash_block_list_size;
|
||||||
ULONG lx_nand_flash_free_block_list_tail;
|
ULONG lx_nand_flash_free_block_list_tail;
|
||||||
|
#ifdef LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE
|
||||||
|
/* Parallel to block_mapping_table: physical block with pending compaction for a group,
|
||||||
|
or LX_NAND_BLOCK_UNMAPPED when no compaction is pending. */
|
||||||
|
USHORT *lx_nand_flash_block_compaction_table;
|
||||||
|
ULONG lx_nand_flash_block_compaction_table_size;
|
||||||
|
#endif
|
||||||
ULONG lx_nand_flash_mapped_block_list_head;
|
ULONG lx_nand_flash_mapped_block_list_head;
|
||||||
|
|
||||||
ULONG lx_nand_flash_metadata_block_number;
|
ULONG lx_nand_flash_metadata_block_number;
|
||||||
@@ -515,6 +539,7 @@ typedef struct LX_NOR_FLASH_EXTENDED_CACHE_ENTRY_STRUCT
|
|||||||
ULONG *lx_nor_flash_extended_cache_entry_sector_address;
|
ULONG *lx_nor_flash_extended_cache_entry_sector_address;
|
||||||
ULONG *lx_nor_flash_extended_cache_entry_sector_memory;
|
ULONG *lx_nor_flash_extended_cache_entry_sector_memory;
|
||||||
ULONG lx_nor_flash_extended_cache_entry_access_count;
|
ULONG lx_nor_flash_extended_cache_entry_access_count;
|
||||||
|
UINT lx_nor_flash_extended_cache_entry_valid;
|
||||||
} LX_NOR_FLASH_EXTENDED_CACHE_ENTRY;
|
} LX_NOR_FLASH_EXTENDED_CACHE_ENTRY;
|
||||||
|
|
||||||
|
|
||||||
@@ -771,6 +796,9 @@ UINT _lx_nand_flash_metadata_write(LX_NAND_FLASH *nand_flash, UCHAR* main_buf
|
|||||||
VOID _lx_nand_flash_system_error(LX_NAND_FLASH *nand_flash, UINT error_code, ULONG block, ULONG page);
|
VOID _lx_nand_flash_system_error(LX_NAND_FLASH *nand_flash, UINT error_code, ULONG block, ULONG page);
|
||||||
UINT _lx_nand_flash_256byte_ecc_check(UCHAR *page_buffer, UCHAR *ecc_buffer);
|
UINT _lx_nand_flash_256byte_ecc_check(UCHAR *page_buffer, UCHAR *ecc_buffer);
|
||||||
UINT _lx_nand_flash_256byte_ecc_compute(UCHAR *page_buffer, UCHAR *ecc_buffer);
|
UINT _lx_nand_flash_256byte_ecc_compute(UCHAR *page_buffer, UCHAR *ecc_buffer);
|
||||||
|
#ifdef LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE
|
||||||
|
UINT _lx_nand_flash_logical_group_compact(LX_NAND_FLASH *nand_flash, ULONG logical_group);
|
||||||
|
#endif
|
||||||
|
|
||||||
UINT _lx_nor_flash_block_reclaim(LX_NOR_FLASH *nor_flash);
|
UINT _lx_nor_flash_block_reclaim(LX_NOR_FLASH *nor_flash);
|
||||||
UINT _lx_nor_flash_driver_block_erase(LX_NOR_FLASH *nor_flash, ULONG block, ULONG erase_count);
|
UINT _lx_nor_flash_driver_block_erase(LX_NOR_FLASH *nor_flash, ULONG block, ULONG erase_count);
|
||||||
@@ -789,4 +817,3 @@ VOID _lx_nor_flash_system_error(LX_NOR_FLASH *nor_flash, UINT error_code);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
|
// Some portions generated by Copilot (Sonnet 4.6).
|
||||||
|
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
@@ -75,6 +76,43 @@ UINT _lx_nand_flash_block_allocate(LX_NAND_FLASH* nand_flash, ULONG* block)
|
|||||||
if (nand_flash -> lx_nand_flash_free_block_list_tail == 0)
|
if (nand_flash -> lx_nand_flash_free_block_list_tail == 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#ifdef LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE
|
||||||
|
{
|
||||||
|
|
||||||
|
ULONG lg;
|
||||||
|
UINT compact_status;
|
||||||
|
|
||||||
|
/* Emergency compaction: find any pending compaction and execute it to
|
||||||
|
reclaim the old full block. */
|
||||||
|
for (lg = 0; lg < nand_flash -> lx_nand_flash_total_blocks; lg++)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (nand_flash -> lx_nand_flash_block_compaction_table[lg] != (USHORT)LX_NAND_BLOCK_UNMAPPED)
|
||||||
|
{
|
||||||
|
|
||||||
|
compact_status = _lx_nand_flash_logical_group_compact(nand_flash, lg);
|
||||||
|
|
||||||
|
if (compact_status == LX_SUCCESS)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Retry the allocation after compaction freed a block. */
|
||||||
|
if (nand_flash -> lx_nand_flash_free_block_list_tail > 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
nand_flash -> lx_nand_flash_free_block_list_tail--;
|
||||||
|
*block = nand_flash -> lx_nand_flash_block_list[nand_flash -> lx_nand_flash_free_block_list_tail];
|
||||||
|
return(LX_SUCCESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Attempt only one compaction per allocate call. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif /* LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE */
|
||||||
|
|
||||||
/* Empty list, return error. */
|
/* Empty list, return error. */
|
||||||
return(LX_NO_BLOCKS);
|
return(LX_NO_BLOCKS);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
|
// Some portions generated by Copilot (Sonnet 4.6).
|
||||||
|
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
@@ -111,6 +112,33 @@ ULONG block_mapping_index;
|
|||||||
return(LX_ERROR);
|
return(LX_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE
|
||||||
|
/* If this logical group has a pending compaction source, redirect the
|
||||||
|
data move to a full logical-group compact to correctly merge data from
|
||||||
|
both source blocks. */
|
||||||
|
if (nand_flash -> lx_nand_flash_block_compaction_table[block_mapping_index] != (USHORT)LX_NAND_BLOCK_UNMAPPED)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Return the pre-allocated new_block to the free list. */
|
||||||
|
status = _lx_nand_flash_block_status_set(nand_flash, new_block, LX_NAND_BLOCK_STATUS_FREE);
|
||||||
|
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
_lx_nand_flash_system_error(nand_flash, status, new_block, 0);
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
_lx_nand_flash_free_block_list_add(nand_flash, new_block);
|
||||||
|
|
||||||
|
/* Restore block_mapping_index to the mapped list; mapped_block_list_get
|
||||||
|
already removed it before this function was called. */
|
||||||
|
_lx_nand_flash_mapped_block_list_add(nand_flash, block_mapping_index);
|
||||||
|
|
||||||
|
/* Perform full compaction merge of both source blocks. */
|
||||||
|
return(_lx_nand_flash_logical_group_compact(nand_flash, block_mapping_index));
|
||||||
|
}
|
||||||
|
#endif /* LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE */
|
||||||
|
|
||||||
/* Set new block status to allocated for now. */
|
/* Set new block status to allocated for now. */
|
||||||
new_block_status = LX_NAND_BLOCK_STATUS_ALLOCATED;
|
new_block_status = LX_NAND_BLOCK_STATUS_ALLOCATED;
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
|
// Some portions generated by Copilot (Sonnet 4.6).
|
||||||
|
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
@@ -72,10 +73,38 @@
|
|||||||
UINT _lx_nand_flash_defragment(LX_NAND_FLASH *nand_flash)
|
UINT _lx_nand_flash_defragment(LX_NAND_FLASH *nand_flash)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#ifdef LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE
|
||||||
|
|
||||||
|
UINT status;
|
||||||
|
ULONG lg;
|
||||||
|
|
||||||
|
/* Compact every logical group that has a deferred compaction pending. */
|
||||||
|
for (lg = 0; lg < nand_flash -> lx_nand_flash_total_blocks; lg++)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (nand_flash -> lx_nand_flash_block_compaction_table[lg] != (USHORT)LX_NAND_BLOCK_UNMAPPED)
|
||||||
|
{
|
||||||
|
|
||||||
|
status = _lx_nand_flash_logical_group_compact(nand_flash, lg);
|
||||||
|
|
||||||
|
/* On error, continue to compact remaining groups. */
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
_lx_nand_flash_system_error(nand_flash, status, lg, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(LX_SUCCESS);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
LX_PARAMETER_NOT_USED(nand_flash);
|
LX_PARAMETER_NOT_USED(nand_flash);
|
||||||
|
|
||||||
/* Return not supported. */
|
/* Return not supported. */
|
||||||
return(LX_NOT_SUPPORTED);
|
return(LX_NOT_SUPPORTED);
|
||||||
|
|
||||||
|
#endif /* LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,447 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (c) 2026-present Eclipse ThreadX contributors
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the MIT License which is available at
|
||||||
|
* https://opensource.org/licenses/MIT.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
// Some portions generated by Copilot (Sonnet 4.6).
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/**************************************************************************/
|
||||||
|
/** */
|
||||||
|
/** LevelX Component */
|
||||||
|
/** */
|
||||||
|
/** NAND Flash */
|
||||||
|
/** */
|
||||||
|
/**************************************************************************/
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#define LX_SOURCE_CODE
|
||||||
|
|
||||||
|
|
||||||
|
/* Disable ThreadX error checking. */
|
||||||
|
|
||||||
|
#ifndef LX_DISABLE_ERROR_CHECKING
|
||||||
|
#define LX_DISABLE_ERROR_CHECKING
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Include necessary system files. */
|
||||||
|
|
||||||
|
#include "lx_api.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* FUNCTION RELEASE */
|
||||||
|
/* */
|
||||||
|
/* _lx_nand_sector_find_in_block PORTABLE C */
|
||||||
|
/* 6.5.0 */
|
||||||
|
/* AUTHOR */
|
||||||
|
/* */
|
||||||
|
/* Eclipse ThreadX contributors */
|
||||||
|
/* */
|
||||||
|
/* DESCRIPTION */
|
||||||
|
/* */
|
||||||
|
/* This helper scans a block for a specific logical sector and returns */
|
||||||
|
/* the page number and kind (data / released / not found). */
|
||||||
|
/* */
|
||||||
|
/* INPUT */
|
||||||
|
/* */
|
||||||
|
/* nand_flash NAND flash instance */
|
||||||
|
/* block Physical block number */
|
||||||
|
/* block_status Block status word */
|
||||||
|
/* logical_sector Logical sector to search for */
|
||||||
|
/* found_page Destination: page index found */
|
||||||
|
/* sector_kind Destination: kind (see below) */
|
||||||
|
/* */
|
||||||
|
/* OUTPUT */
|
||||||
|
/* */
|
||||||
|
/* LX_SUCCESS Sector found; outputs set */
|
||||||
|
/* LX_NO_BLOCKS Sector not present in block */
|
||||||
|
/* LX_ERROR Driver error */
|
||||||
|
/* */
|
||||||
|
/* SECTOR KIND VALUES (written to *sector_kind) */
|
||||||
|
/* */
|
||||||
|
/* LX_NAND_PAGE_TYPE_USER_DATA Sector contains live data */
|
||||||
|
/* LX_NAND_PAGE_TYPE_USER_DATA_RELEASED Sector is tombstoned */
|
||||||
|
/* */
|
||||||
|
/**************************************************************************/
|
||||||
|
static UINT _lx_nand_sector_find_in_block(LX_NAND_FLASH *nand_flash,
|
||||||
|
ULONG block,
|
||||||
|
USHORT block_status,
|
||||||
|
ULONG logical_sector,
|
||||||
|
LONG *found_page,
|
||||||
|
ULONG *sector_kind)
|
||||||
|
{
|
||||||
|
|
||||||
|
ULONG available_pages;
|
||||||
|
LONG page;
|
||||||
|
ULONG spare_data1;
|
||||||
|
UINT status;
|
||||||
|
UCHAR *spare_buffer_ptr;
|
||||||
|
|
||||||
|
|
||||||
|
/* Use page buffer as scratch for spare-only reads (per existing LevelX convention). */
|
||||||
|
spare_buffer_ptr = nand_flash -> lx_nand_flash_page_buffer;
|
||||||
|
|
||||||
|
/* Determine page count. */
|
||||||
|
available_pages = (block_status & LX_NAND_BLOCK_STATUS_FULL) ?
|
||||||
|
nand_flash -> lx_nand_flash_pages_per_block :
|
||||||
|
(block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK);
|
||||||
|
|
||||||
|
if (block_status & LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Scan newest-to-oldest so the first match is the authoritative version. */
|
||||||
|
for (page = (LONG)available_pages - 1; page >= 0; page--)
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
||||||
|
status = (nand_flash -> lx_nand_flash_driver_pages_read)(nand_flash, block, (ULONG)page, LX_NULL, spare_buffer_ptr, 1);
|
||||||
|
#else
|
||||||
|
status = (nand_flash -> lx_nand_flash_driver_pages_read)(block, (ULONG)page, LX_NULL, spare_buffer_ptr, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Check for an error from flash driver. */
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
_lx_nand_flash_system_error(nand_flash, status, block, 0);
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
spare_data1 = LX_UTILITY_LONG_GET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset]);
|
||||||
|
|
||||||
|
if ((spare_data1 & LX_NAND_PAGE_TYPE_USER_DATA_MASK) == logical_sector)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Sector found; return its page index and kind. */
|
||||||
|
*found_page = page;
|
||||||
|
*sector_kind = spare_data1 & (~LX_NAND_PAGE_TYPE_USER_DATA_MASK);
|
||||||
|
return(LX_SUCCESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Sequential block: page index == sector offset within group. */
|
||||||
|
page = (LONG)(logical_sector % nand_flash -> lx_nand_flash_pages_per_block);
|
||||||
|
if ((ULONG)page < available_pages)
|
||||||
|
{
|
||||||
|
*found_page = page;
|
||||||
|
*sector_kind = LX_NAND_PAGE_TYPE_USER_DATA;
|
||||||
|
return(LX_SUCCESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*found_page = -1L;
|
||||||
|
return(LX_NO_BLOCKS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* FUNCTION RELEASE */
|
||||||
|
/* */
|
||||||
|
/* _lx_nand_flash_logical_group_compact PORTABLE C */
|
||||||
|
/* 6.5.0 */
|
||||||
|
/* AUTHOR */
|
||||||
|
/* */
|
||||||
|
/* Eclipse ThreadX contributors */
|
||||||
|
/* */
|
||||||
|
/* DESCRIPTION */
|
||||||
|
/* */
|
||||||
|
/* This function completes a deferred full-block compaction created by */
|
||||||
|
/* the lazy sector-release path. It merges the tombstone block */
|
||||||
|
/* (current mapping) and the compaction-pending old block into a fresh */
|
||||||
|
/* destination block, then erases both source blocks. */
|
||||||
|
/* */
|
||||||
|
/* The tombstone block takes priority: if a sector appears in both */
|
||||||
|
/* blocks the tombstone block's version is used (newer). */
|
||||||
|
/* */
|
||||||
|
/* INPUT */
|
||||||
|
/* */
|
||||||
|
/* nand_flash NAND flash instance */
|
||||||
|
/* logical_group Logical group index */
|
||||||
|
/* */
|
||||||
|
/* OUTPUT */
|
||||||
|
/* */
|
||||||
|
/* LX_SUCCESS Compaction completed */
|
||||||
|
/* LX_ERROR / LX_NO_BLOCKS Error during compaction */
|
||||||
|
/* */
|
||||||
|
/* CALLS */
|
||||||
|
/* */
|
||||||
|
/* _lx_nand_sector_find_in_block Find sector in a block */
|
||||||
|
/* _lx_nand_flash_block_allocate Allocate a free block */
|
||||||
|
/* _lx_nand_flash_block_status_set Set block status */
|
||||||
|
/* _lx_nand_flash_block_mapping_set Update logical-to-physical map*/
|
||||||
|
/* _lx_nand_flash_mapped_block_list_remove Remove from mapped list */
|
||||||
|
/* _lx_nand_flash_mapped_block_list_add Add to mapped list */
|
||||||
|
/* _lx_nand_flash_free_block_list_add Return block to free list */
|
||||||
|
/* _lx_nand_flash_driver_block_erase Erase a block */
|
||||||
|
/* _lx_nand_flash_erase_count_set Record new erase count */
|
||||||
|
/* _lx_nand_flash_block_data_move Wear-level an over-erased blk */
|
||||||
|
/* _lx_nand_flash_system_error Internal system error handler */
|
||||||
|
/* lx_nand_flash_driver_pages_copy Copy a page between blocks */
|
||||||
|
/* */
|
||||||
|
/* CALLED BY */
|
||||||
|
/* */
|
||||||
|
/* _lx_nand_flash_sector_release Lazy release pre-compact */
|
||||||
|
/* _lx_nand_flash_sector_write Pre-compact before block copy */
|
||||||
|
/* _lx_nand_flash_block_data_move Wear-level with pending compact*/
|
||||||
|
/* _lx_nand_flash_defragment Explicit defragment pass */
|
||||||
|
/* _lx_nand_flash_block_allocate Emergency compaction */
|
||||||
|
/* */
|
||||||
|
/**************************************************************************/
|
||||||
|
UINT _lx_nand_flash_logical_group_compact(LX_NAND_FLASH *nand_flash, ULONG logical_group)
|
||||||
|
{
|
||||||
|
|
||||||
|
UINT status;
|
||||||
|
ULONG tombstone_block;
|
||||||
|
ULONG compaction_block;
|
||||||
|
ULONG dest_block;
|
||||||
|
USHORT tombstone_block_status;
|
||||||
|
USHORT compaction_block_status;
|
||||||
|
USHORT dest_block_status;
|
||||||
|
ULONG sector;
|
||||||
|
ULONG base_sector;
|
||||||
|
LONG source_page;
|
||||||
|
ULONG dest_page;
|
||||||
|
ULONG sector_kind;
|
||||||
|
UINT find_status;
|
||||||
|
|
||||||
|
|
||||||
|
/* Retrieve the two source blocks. */
|
||||||
|
tombstone_block = nand_flash -> lx_nand_flash_block_mapping_table[logical_group];
|
||||||
|
compaction_block = nand_flash -> lx_nand_flash_block_compaction_table[logical_group];
|
||||||
|
tombstone_block_status = nand_flash -> lx_nand_flash_block_status_table[tombstone_block];
|
||||||
|
compaction_block_status = nand_flash -> lx_nand_flash_block_status_table[compaction_block];
|
||||||
|
|
||||||
|
/* Allocate a fresh destination block. */
|
||||||
|
status = _lx_nand_flash_block_allocate(nand_flash, &dest_block);
|
||||||
|
if (status != LX_SUCCESS)
|
||||||
|
{
|
||||||
|
return(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
dest_block_status = LX_NAND_BLOCK_STATUS_ALLOCATED;
|
||||||
|
dest_page = 0;
|
||||||
|
base_sector = logical_group * nand_flash -> lx_nand_flash_pages_per_block;
|
||||||
|
|
||||||
|
/* Merge loop: iterate every sector in the logical group.
|
||||||
|
The tombstone block (current mapping) supersedes the compaction block. */
|
||||||
|
for (sector = base_sector;
|
||||||
|
sector < base_sector + nand_flash -> lx_nand_flash_pages_per_block;
|
||||||
|
sector++)
|
||||||
|
{
|
||||||
|
|
||||||
|
source_page = -1L;
|
||||||
|
sector_kind = 0;
|
||||||
|
|
||||||
|
/* Search the tombstone block first (newer data). */
|
||||||
|
find_status = _lx_nand_sector_find_in_block(nand_flash, tombstone_block,
|
||||||
|
tombstone_block_status, sector,
|
||||||
|
&source_page, §or_kind);
|
||||||
|
if (find_status == LX_ERROR)
|
||||||
|
{
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (find_status == LX_NO_BLOCKS)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Not in tombstone block; try the compaction block (older data). */
|
||||||
|
find_status = _lx_nand_sector_find_in_block(nand_flash, compaction_block,
|
||||||
|
compaction_block_status, sector,
|
||||||
|
&source_page, §or_kind);
|
||||||
|
if (find_status == LX_ERROR)
|
||||||
|
{
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((find_status == LX_SUCCESS) && (sector_kind == LX_NAND_PAGE_TYPE_USER_DATA))
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Copy live data from compaction block to destination. */
|
||||||
|
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
||||||
|
status = (nand_flash -> lx_nand_flash_driver_pages_copy)(nand_flash, compaction_block, (ULONG)source_page, dest_block, dest_page, 1, nand_flash -> lx_nand_flash_page_buffer);
|
||||||
|
#else
|
||||||
|
status = (nand_flash -> lx_nand_flash_driver_pages_copy)(compaction_block, (ULONG)source_page, dest_block, dest_page, 1, nand_flash -> lx_nand_flash_page_buffer);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
_lx_nand_flash_system_error(nand_flash, status, dest_block, 0);
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dest_page != (sector % nand_flash -> lx_nand_flash_pages_per_block))
|
||||||
|
{
|
||||||
|
dest_block_status |= LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest_page++;
|
||||||
|
}
|
||||||
|
/* RELEASED or NOT_FOUND in compaction block: sector no longer exists, skip. */
|
||||||
|
}
|
||||||
|
else if ((find_status == LX_SUCCESS) && (sector_kind == LX_NAND_PAGE_TYPE_USER_DATA))
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Copy live data from tombstone block to destination. */
|
||||||
|
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
||||||
|
status = (nand_flash -> lx_nand_flash_driver_pages_copy)(nand_flash, tombstone_block, (ULONG)source_page, dest_block, dest_page, 1, nand_flash -> lx_nand_flash_page_buffer);
|
||||||
|
#else
|
||||||
|
status = (nand_flash -> lx_nand_flash_driver_pages_copy)(tombstone_block, (ULONG)source_page, dest_block, dest_page, 1, nand_flash -> lx_nand_flash_page_buffer);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
_lx_nand_flash_system_error(nand_flash, status, dest_block, 0);
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dest_page != (sector % nand_flash -> lx_nand_flash_pages_per_block))
|
||||||
|
{
|
||||||
|
dest_block_status |= LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest_page++;
|
||||||
|
}
|
||||||
|
/* RELEASED (tombstone found in tombstone block): sector is gone, skip. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Encode page count into dest_block_status. */
|
||||||
|
dest_block_status = (USHORT)((dest_block_status & ~(USHORT)LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK) |
|
||||||
|
(dest_page & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK));
|
||||||
|
|
||||||
|
/* Commit destination block or discard it if the entire group was released. */
|
||||||
|
if (dest_page == 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* All sectors released; destination block is unused. */
|
||||||
|
status = _lx_nand_flash_block_status_set(nand_flash, dest_block, LX_NAND_BLOCK_STATUS_FREE);
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
_lx_nand_flash_system_error(nand_flash, status, dest_block, 0);
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
_lx_nand_flash_free_block_list_add(nand_flash, dest_block);
|
||||||
|
dest_block = (ULONG)LX_NAND_BLOCK_UNMAPPED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status = _lx_nand_flash_block_status_set(nand_flash, dest_block, dest_block_status);
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
_lx_nand_flash_system_error(nand_flash, status, dest_block, 0);
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove tombstone block from the mapped list. */
|
||||||
|
_lx_nand_flash_mapped_block_list_remove(nand_flash, logical_group);
|
||||||
|
|
||||||
|
/* Persist the new mapping (or UNMAPPED if all sectors were released). */
|
||||||
|
_lx_nand_flash_block_mapping_set(nand_flash, logical_group * nand_flash -> lx_nand_flash_pages_per_block, dest_block);
|
||||||
|
|
||||||
|
/* Clear the in-RAM compaction table entry. */
|
||||||
|
nand_flash -> lx_nand_flash_block_compaction_table[logical_group] = (USHORT)LX_NAND_BLOCK_UNMAPPED;
|
||||||
|
|
||||||
|
/* Add destination block to the mapped list if it holds data. */
|
||||||
|
if (dest_block != (ULONG)LX_NAND_BLOCK_UNMAPPED)
|
||||||
|
{
|
||||||
|
_lx_nand_flash_mapped_block_list_add(nand_flash, logical_group);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- Erase tombstone block ---- */
|
||||||
|
status = _lx_nand_flash_driver_block_erase(nand_flash, tombstone_block,
|
||||||
|
nand_flash -> lx_nand_flash_base_erase_count +
|
||||||
|
nand_flash -> lx_nand_flash_erase_count_table[tombstone_block] + 1);
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
_lx_nand_flash_system_error(nand_flash, status, tombstone_block, 0);
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
status = _lx_nand_flash_erase_count_set(nand_flash, tombstone_block,
|
||||||
|
(UCHAR)(nand_flash -> lx_nand_flash_erase_count_table[tombstone_block] + 1));
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
_lx_nand_flash_system_error(nand_flash, status, tombstone_block, 0);
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nand_flash -> lx_nand_flash_erase_count_table[tombstone_block] > LX_NAND_FLASH_MAX_ERASE_COUNT_DELTA)
|
||||||
|
{
|
||||||
|
status = _lx_nand_flash_block_data_move(nand_flash, tombstone_block);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status = _lx_nand_flash_block_status_set(nand_flash, tombstone_block, LX_NAND_BLOCK_STATUS_FREE);
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
_lx_nand_flash_system_error(nand_flash, status, tombstone_block, 0);
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
status = _lx_nand_flash_free_block_list_add(nand_flash, tombstone_block);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- Clear COMPACTION_PENDING flag on the old block, then erase it ---- */
|
||||||
|
status = _lx_nand_flash_block_status_set(nand_flash, compaction_block,
|
||||||
|
(USHORT)(nand_flash -> lx_nand_flash_block_status_table[compaction_block] &
|
||||||
|
~(USHORT)LX_NAND_BLOCK_STATUS_COMPACTION_PENDING));
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
_lx_nand_flash_system_error(nand_flash, status, compaction_block, 0);
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
status = _lx_nand_flash_driver_block_erase(nand_flash, compaction_block,
|
||||||
|
nand_flash -> lx_nand_flash_base_erase_count +
|
||||||
|
nand_flash -> lx_nand_flash_erase_count_table[compaction_block] + 1);
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
_lx_nand_flash_system_error(nand_flash, status, compaction_block, 0);
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
status = _lx_nand_flash_erase_count_set(nand_flash, compaction_block,
|
||||||
|
(UCHAR)(nand_flash -> lx_nand_flash_erase_count_table[compaction_block] + 1));
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
_lx_nand_flash_system_error(nand_flash, status, compaction_block, 0);
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nand_flash -> lx_nand_flash_erase_count_table[compaction_block] > LX_NAND_FLASH_MAX_ERASE_COUNT_DELTA)
|
||||||
|
{
|
||||||
|
status = _lx_nand_flash_block_data_move(nand_flash, compaction_block);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status = _lx_nand_flash_block_status_set(nand_flash, compaction_block, LX_NAND_BLOCK_STATUS_FREE);
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
_lx_nand_flash_system_error(nand_flash, status, compaction_block, 0);
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
status = _lx_nand_flash_free_block_list_add(nand_flash, compaction_block);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE */
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
|
// Some portions generated by Copilot (Sonnet 4.6).
|
||||||
|
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
@@ -181,6 +182,48 @@ UINT buffer_size;
|
|||||||
return(LX_NO_MEMORY);
|
return(LX_NO_MEMORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE
|
||||||
|
{
|
||||||
|
|
||||||
|
ULONG i;
|
||||||
|
ULONG compaction_table_entries;
|
||||||
|
|
||||||
|
/* Set memory size for block compaction table. Same element type as block_mapping_table. */
|
||||||
|
buffer_size = nand_flash -> lx_nand_flash_total_blocks * sizeof(*nand_flash -> lx_nand_flash_block_compaction_table);
|
||||||
|
|
||||||
|
/* Make sure the size is at least one page size. */
|
||||||
|
if (buffer_size < nand_flash -> lx_nand_flash_bytes_per_page)
|
||||||
|
{
|
||||||
|
buffer_size = nand_flash -> lx_nand_flash_bytes_per_page;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assign memory for block compaction table. */
|
||||||
|
nand_flash -> lx_nand_flash_block_compaction_table = (USHORT*)(((UCHAR*)memory_ptr) + memory_offset);
|
||||||
|
|
||||||
|
/* Update block compaction table size. */
|
||||||
|
nand_flash -> lx_nand_flash_block_compaction_table_size = buffer_size;
|
||||||
|
|
||||||
|
/* Update memory offset. */
|
||||||
|
memory_offset += buffer_size;
|
||||||
|
|
||||||
|
/* Check if there is enough memory. */
|
||||||
|
if (memory_offset > memory_size)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* No enough memory, return error. */
|
||||||
|
return(LX_NO_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize all compaction table entries to unmapped. (LX_MEMSET zero-fills the buffer
|
||||||
|
above, but LX_NAND_BLOCK_UNMAPPED is 0xFFFF, so explicit initialisation is required.) */
|
||||||
|
compaction_table_entries = buffer_size / sizeof(*nand_flash -> lx_nand_flash_block_compaction_table);
|
||||||
|
for (i = 0; i < compaction_table_entries; i++)
|
||||||
|
{
|
||||||
|
nand_flash -> lx_nand_flash_block_compaction_table[i] = (USHORT)LX_NAND_BLOCK_UNMAPPED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Assign memory for page buffer. */
|
/* Assign memory for page buffer. */
|
||||||
nand_flash -> lx_nand_flash_page_buffer = ((UCHAR*)memory_ptr) + memory_offset;
|
nand_flash -> lx_nand_flash_page_buffer = ((UCHAR*)memory_ptr) + memory_offset;
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
|
// Some portions generated by Copilot (Sonnet 4.6).
|
||||||
|
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
@@ -460,6 +461,161 @@ LX_INTERRUPT_SAVE_AREA
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE
|
||||||
|
{
|
||||||
|
|
||||||
|
ULONG blk;
|
||||||
|
ULONG lg;
|
||||||
|
USHORT blk_status;
|
||||||
|
|
||||||
|
/* Phase 1: Rebuild compaction table and recover from mid-release crashes.
|
||||||
|
Scan all blocks for COMPACTION_PENDING. */
|
||||||
|
for (blk = 0; blk < nand_flash -> lx_nand_flash_total_blocks; blk++)
|
||||||
|
{
|
||||||
|
|
||||||
|
blk_status = nand_flash -> lx_nand_flash_block_status_table[blk];
|
||||||
|
|
||||||
|
/* FREE (0xFFFF) and BAD (0xFF00) both have COMPACTION_PENDING bit set; skip them. */
|
||||||
|
if ((blk_status == LX_NAND_BLOCK_STATUS_FREE) || (blk_status == LX_NAND_BLOCK_STATUS_BAD))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blk_status & LX_NAND_BLOCK_STATUS_COMPACTION_PENDING)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Check if any logical group still maps to this physical block.
|
||||||
|
If so, the mapping update didn't happen — abort the lazy release. */
|
||||||
|
lg = nand_flash -> lx_nand_flash_total_blocks;
|
||||||
|
{
|
||||||
|
ULONG search_lg;
|
||||||
|
for (search_lg = 0; search_lg < nand_flash -> lx_nand_flash_total_blocks; search_lg++)
|
||||||
|
{
|
||||||
|
if (nand_flash -> lx_nand_flash_block_mapping_table[search_lg] == (USHORT)blk)
|
||||||
|
{
|
||||||
|
lg = search_lg;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lg != nand_flash -> lx_nand_flash_total_blocks)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Scenario A: crash after COMPACTION_PENDING set, before mapping updated.
|
||||||
|
Clear COMPACTION_PENDING to restore the block to its normal state. */
|
||||||
|
blk_status = (USHORT)(blk_status & (USHORT)(~LX_NAND_BLOCK_STATUS_COMPACTION_PENDING));
|
||||||
|
(void)_lx_nand_flash_block_status_set(nand_flash, blk, blk_status);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Scenario B: deferred compaction — scan block pages to find the LG. */
|
||||||
|
ULONG page;
|
||||||
|
ULONG spare_word;
|
||||||
|
ULONG found_lg;
|
||||||
|
UCHAR *spare_ptr;
|
||||||
|
|
||||||
|
spare_ptr = (UCHAR*)nand_flash -> lx_nand_flash_page_buffer;
|
||||||
|
found_lg = nand_flash -> lx_nand_flash_total_blocks;
|
||||||
|
|
||||||
|
for (page = 0; page < nand_flash -> lx_nand_flash_pages_per_block; page++)
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
||||||
|
status = (nand_flash -> lx_nand_flash_driver_pages_read)(nand_flash, blk, page, (UCHAR*)NULL, spare_ptr, 1);
|
||||||
|
#else
|
||||||
|
status = (nand_flash -> lx_nand_flash_driver_pages_read)(blk, page, (UCHAR*)NULL, spare_ptr, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
spare_word = LX_UTILITY_LONG_GET(&spare_ptr[nand_flash -> lx_nand_flash_spare_data1_offset]);
|
||||||
|
|
||||||
|
if ((spare_word & (~LX_NAND_PAGE_TYPE_USER_DATA_MASK)) == LX_NAND_PAGE_TYPE_USER_DATA)
|
||||||
|
{
|
||||||
|
found_lg = (spare_word & LX_NAND_PAGE_TYPE_USER_DATA_MASK) /
|
||||||
|
nand_flash -> lx_nand_flash_pages_per_block;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((found_lg != nand_flash -> lx_nand_flash_total_blocks) &&
|
||||||
|
(found_lg < nand_flash -> lx_nand_flash_total_blocks))
|
||||||
|
{
|
||||||
|
nand_flash -> lx_nand_flash_block_compaction_table[found_lg] = (USHORT)blk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Phase 2: Orphan block recovery — erase ALLOCATED blocks not referenced
|
||||||
|
by any mapping entry and not marked COMPACTION_PENDING. */
|
||||||
|
for (blk = 0; blk < nand_flash -> lx_nand_flash_total_blocks; blk++)
|
||||||
|
{
|
||||||
|
|
||||||
|
ULONG found;
|
||||||
|
|
||||||
|
blk_status = nand_flash -> lx_nand_flash_block_status_table[blk];
|
||||||
|
|
||||||
|
if ((blk_status == LX_NAND_BLOCK_STATUS_FREE) || (blk_status == LX_NAND_BLOCK_STATUS_BAD))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blk_status & LX_NAND_BLOCK_STATUS_COMPACTION_PENDING)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(blk_status & LX_NAND_BLOCK_STATUS_ALLOCATED))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search for this block in the mapping table. */
|
||||||
|
found = LX_FALSE;
|
||||||
|
for (lg = 0; lg < nand_flash -> lx_nand_flash_total_blocks; lg++)
|
||||||
|
{
|
||||||
|
if (nand_flash -> lx_nand_flash_block_mapping_table[lg] == (USHORT)blk)
|
||||||
|
{
|
||||||
|
found = LX_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Orphan block: erase and reclaim. */
|
||||||
|
status = _lx_nand_flash_driver_block_erase(nand_flash, blk,
|
||||||
|
nand_flash -> lx_nand_flash_base_erase_count +
|
||||||
|
nand_flash -> lx_nand_flash_erase_count_table[blk] + 1);
|
||||||
|
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
_lx_nand_flash_system_error(nand_flash, status, blk, 0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = _lx_nand_flash_erase_count_set(nand_flash, blk,
|
||||||
|
(UCHAR)(nand_flash -> lx_nand_flash_erase_count_table[blk] + 1));
|
||||||
|
|
||||||
|
if (!status)
|
||||||
|
{
|
||||||
|
(void)_lx_nand_flash_block_status_set(nand_flash, blk, LX_NAND_BLOCK_STATUS_FREE);
|
||||||
|
_lx_nand_flash_free_block_list_add(nand_flash, blk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif /* LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE */
|
||||||
|
|
||||||
|
|
||||||
#ifdef LX_THREAD_SAFE_ENABLE
|
#ifdef LX_THREAD_SAFE_ENABLE
|
||||||
|
|
||||||
/* If the thread safe option is enabled, create a ThreadX mutex that will be used in all external APIs
|
/* If the thread safe option is enabled, create a ThreadX mutex that will be used in all external APIs
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
|
// Some portions generated by Copilot (Sonnet 4.6).
|
||||||
|
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
@@ -231,6 +232,76 @@ LONG page;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE
|
||||||
|
{
|
||||||
|
|
||||||
|
ULONG logical_group;
|
||||||
|
ULONG old_block;
|
||||||
|
|
||||||
|
/* Check the compaction table for a deferred source block that might hold
|
||||||
|
the requested sector. The primary block (tombstone block) was already
|
||||||
|
scanned above; fall back to the old full block here. */
|
||||||
|
logical_group = logical_sector / nand_flash -> lx_nand_flash_pages_per_block;
|
||||||
|
|
||||||
|
if (nand_flash -> lx_nand_flash_block_compaction_table[logical_group] != (USHORT)LX_NAND_BLOCK_UNMAPPED)
|
||||||
|
{
|
||||||
|
|
||||||
|
old_block = nand_flash -> lx_nand_flash_block_compaction_table[logical_group];
|
||||||
|
|
||||||
|
/* Set spare buffer pointer. */
|
||||||
|
spare_buffer_ptr = (UCHAR*)nand_flash -> lx_nand_flash_page_buffer;
|
||||||
|
|
||||||
|
/* The compaction-pending block is always FULL; scan all pages in reverse. */
|
||||||
|
for (page = (LONG)nand_flash -> lx_nand_flash_pages_per_block - 1; page >= 0; page--)
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
||||||
|
status = (nand_flash -> lx_nand_flash_driver_pages_read)(nand_flash, old_block, (ULONG)page, (UCHAR*)NULL, spare_buffer_ptr, 1);
|
||||||
|
#else
|
||||||
|
status = (nand_flash -> lx_nand_flash_driver_pages_read)(old_block, (ULONG)page, (UCHAR*)NULL, spare_buffer_ptr, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Check for an error from flash driver. */
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
_lx_nand_flash_system_error(nand_flash, status, old_block, 0);
|
||||||
|
#ifdef LX_THREAD_SAFE_ENABLE
|
||||||
|
tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
|
||||||
|
#endif
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if this page matches the requested sector. */
|
||||||
|
if ((LX_UTILITY_LONG_GET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset]) & LX_NAND_PAGE_TYPE_USER_DATA_MASK) == logical_sector)
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
||||||
|
status = (nand_flash -> lx_nand_flash_driver_pages_read)(nand_flash, old_block, (ULONG)page, (UCHAR*)buffer, NULL, 1);
|
||||||
|
#else
|
||||||
|
status = (nand_flash -> lx_nand_flash_driver_pages_read)(old_block, (ULONG)page, (UCHAR*)buffer, NULL, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Check for an error from flash driver. */
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
_lx_nand_flash_system_error(nand_flash, status, old_block, 0);
|
||||||
|
#ifdef LX_THREAD_SAFE_ENABLE
|
||||||
|
tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
|
||||||
|
#endif
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LX_THREAD_SAFE_ENABLE
|
||||||
|
tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
|
||||||
|
#endif
|
||||||
|
return(LX_SUCCESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif /* LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE */
|
||||||
|
|
||||||
/* Sector hasn't been written. Simply fill the destination buffer with ones and return success. */
|
/* Sector hasn't been written. Simply fill the destination buffer with ones and return success. */
|
||||||
|
|
||||||
/* Setup pointer to users buffer. */
|
/* Setup pointer to users buffer. */
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
|
// Some portions generated by Copilot (Sonnet 4.6).
|
||||||
|
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
@@ -205,6 +206,119 @@ USHORT new_block_status;
|
|||||||
if (block_status & LX_NAND_BLOCK_STATUS_FULL)
|
if (block_status & LX_NAND_BLOCK_STATUS_FULL)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#ifdef LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE
|
||||||
|
/* Lazy path: defer the copy+erase when enough free blocks are available.
|
||||||
|
The old block is kept as a compaction source; a new block holds only
|
||||||
|
the tombstone for the released sector. */
|
||||||
|
if (nand_flash -> lx_nand_flash_free_block_list_tail >
|
||||||
|
(ULONG)LX_NAND_FLASH_SECTOR_RELEASE_LAZY_THRESHOLD)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Allocate a new block for the tombstone. */
|
||||||
|
status = _lx_nand_flash_block_allocate(nand_flash, &new_block);
|
||||||
|
|
||||||
|
/* Check return status. */
|
||||||
|
if (status != LX_SUCCESS)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Call system error handler. */
|
||||||
|
_lx_nand_flash_system_error(nand_flash, status, new_block, 0);
|
||||||
|
#ifdef LX_THREAD_SAFE_ENABLE
|
||||||
|
|
||||||
|
/* Release the thread safe mutex. */
|
||||||
|
tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
|
||||||
|
#endif
|
||||||
|
/* Return an error. */
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set page buffer to all 0xFF (data = erased, sector is released). */
|
||||||
|
LX_MEMSET(nand_flash -> lx_nand_flash_page_buffer, 0xFF,
|
||||||
|
nand_flash -> lx_nand_flash_bytes_per_page +
|
||||||
|
nand_flash -> lx_nand_flash_spare_total_length);
|
||||||
|
|
||||||
|
/* Setup spare buffer pointer. */
|
||||||
|
spare_buffer_ptr = nand_flash -> lx_nand_flash_page_buffer +
|
||||||
|
nand_flash -> lx_nand_flash_bytes_per_page;
|
||||||
|
|
||||||
|
/* Save metadata block number in spare bytes if space allows. */
|
||||||
|
if (nand_flash -> lx_nand_flash_spare_data2_length >= sizeof(USHORT))
|
||||||
|
{
|
||||||
|
LX_UTILITY_SHORT_SET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data2_offset],
|
||||||
|
nand_flash -> lx_nand_flash_metadata_block_number);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set page type to USER_DATA_RELEASED. */
|
||||||
|
LX_UTILITY_LONG_SET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset],
|
||||||
|
LX_NAND_PAGE_TYPE_USER_DATA_RELEASED | logical_sector);
|
||||||
|
|
||||||
|
/* Write the tombstone page to page 0 of the new block. */
|
||||||
|
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
||||||
|
status = (nand_flash -> lx_nand_flash_driver_pages_write)(nand_flash, new_block, 0,
|
||||||
|
(UCHAR*)nand_flash -> lx_nand_flash_page_buffer, spare_buffer_ptr, 1);
|
||||||
|
#else
|
||||||
|
status = (nand_flash -> lx_nand_flash_driver_pages_write)(new_block, 0,
|
||||||
|
(UCHAR*)nand_flash -> lx_nand_flash_page_buffer, spare_buffer_ptr, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Check for an error from flash driver. */
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
_lx_nand_flash_system_error(nand_flash, status, new_block, 0);
|
||||||
|
#ifdef LX_THREAD_SAFE_ENABLE
|
||||||
|
tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
|
||||||
|
#endif
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set new block status: allocated, non-sequential, 1 page written. */
|
||||||
|
new_block_status = (USHORT)(LX_NAND_BLOCK_STATUS_ALLOCATED |
|
||||||
|
LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL | 1u);
|
||||||
|
status = _lx_nand_flash_block_status_set(nand_flash, new_block, new_block_status);
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
_lx_nand_flash_system_error(nand_flash, status, new_block, 0);
|
||||||
|
#ifdef LX_THREAD_SAFE_ENABLE
|
||||||
|
tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
|
||||||
|
#endif
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mark old block as compaction-pending (persisted to flash).
|
||||||
|
Write order: tombstone written → new_block status set →
|
||||||
|
COMPACTION_PENDING set → mapping updated.
|
||||||
|
This ordering ensures safe crash recovery at open time. */
|
||||||
|
status = _lx_nand_flash_block_status_set(nand_flash, block,
|
||||||
|
(USHORT)(block_status | LX_NAND_BLOCK_STATUS_COMPACTION_PENDING));
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
_lx_nand_flash_system_error(nand_flash, status, block, 0);
|
||||||
|
#ifdef LX_THREAD_SAFE_ENABLE
|
||||||
|
tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
|
||||||
|
#endif
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove old mapping before updating to new block. */
|
||||||
|
_lx_nand_flash_mapped_block_list_remove(nand_flash,
|
||||||
|
logical_sector / nand_flash -> lx_nand_flash_pages_per_block);
|
||||||
|
|
||||||
|
/* Update logical-to-physical mapping to the new tombstone block. */
|
||||||
|
_lx_nand_flash_block_mapping_set(nand_flash, logical_sector, new_block);
|
||||||
|
|
||||||
|
/* Record the old block as the compaction source (RAM only; rebuilt at open). */
|
||||||
|
nand_flash -> lx_nand_flash_block_compaction_table[logical_sector / nand_flash -> lx_nand_flash_pages_per_block] = (USHORT)block;
|
||||||
|
|
||||||
|
/* Add new tombstone block to the mapped list. */
|
||||||
|
_lx_nand_flash_mapped_block_list_add(nand_flash,
|
||||||
|
logical_sector / nand_flash -> lx_nand_flash_pages_per_block);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif /* LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE */
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Eager path (existing): allocate a new block and copy + erase immediately. */
|
||||||
|
|
||||||
/* Allocate a new block. */
|
/* Allocate a new block. */
|
||||||
status = _lx_nand_flash_block_allocate(nand_flash, &new_block);
|
status = _lx_nand_flash_block_allocate(nand_flash, &new_block);
|
||||||
|
|
||||||
@@ -387,6 +501,7 @@ USHORT new_block_status;
|
|||||||
/* Add the new block to mapped block list. */
|
/* Add the new block to mapped block list. */
|
||||||
_lx_nand_flash_mapped_block_list_add(nand_flash, logical_sector / nand_flash -> lx_nand_flash_pages_per_block);
|
_lx_nand_flash_mapped_block_list_add(nand_flash, logical_sector / nand_flash -> lx_nand_flash_pages_per_block);
|
||||||
}
|
}
|
||||||
|
} /* end eager path else block */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
|
// Some portions generated by Copilot (Sonnet 4.6).
|
||||||
|
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
@@ -131,6 +132,42 @@ UINT copy_block = LX_FALSE;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE
|
||||||
|
/* If the block is full and has a pending compaction source, compact it now
|
||||||
|
before writing so the new data merges correctly with a single source block. */
|
||||||
|
if ((block != LX_NAND_BLOCK_UNMAPPED) && (block_status & LX_NAND_BLOCK_STATUS_FULL) &&
|
||||||
|
(nand_flash -> lx_nand_flash_block_compaction_table[logical_sector / nand_flash -> lx_nand_flash_pages_per_block] != (USHORT)LX_NAND_BLOCK_UNMAPPED))
|
||||||
|
{
|
||||||
|
|
||||||
|
status = _lx_nand_flash_logical_group_compact(nand_flash,
|
||||||
|
logical_sector / nand_flash -> lx_nand_flash_pages_per_block);
|
||||||
|
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
_lx_nand_flash_system_error(nand_flash, status, block, 0);
|
||||||
|
#ifdef LX_THREAD_SAFE_ENABLE
|
||||||
|
tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
|
||||||
|
#endif
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Refresh block and block_status after compaction. */
|
||||||
|
status = _lx_nand_flash_block_find(nand_flash, logical_sector, &block, &block_status);
|
||||||
|
|
||||||
|
if (status != LX_SUCCESS)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (status != LX_NAND_ERROR_CORRECTED)
|
||||||
|
{
|
||||||
|
#ifdef LX_THREAD_SAFE_ENABLE
|
||||||
|
tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
|
||||||
|
#endif
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE */
|
||||||
|
|
||||||
/* Check if block is unmapped or block is full. */
|
/* Check if block is unmapped or block is full. */
|
||||||
if (block == LX_NAND_BLOCK_UNMAPPED || block_status & LX_NAND_BLOCK_STATUS_FULL)
|
if (block == LX_NAND_BLOCK_UNMAPPED || block_status & LX_NAND_BLOCK_STATUS_FULL)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
|
// Some portions generated by Codex (GPT-5).
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
@@ -76,15 +78,19 @@ UINT status;
|
|||||||
#ifndef LX_NOR_DISABLE_EXTENDED_CACHE
|
#ifndef LX_NOR_DISABLE_EXTENDED_CACHE
|
||||||
|
|
||||||
UINT i;
|
UINT i;
|
||||||
ULONG *block_start_address;
|
ULONG block_start_address;
|
||||||
ULONG *block_end_address;
|
ULONG block_end_address;
|
||||||
ULONG *cache_entry_start;
|
ULONG *cache_entry_start;
|
||||||
ULONG *cache_entry_end;
|
ULONG cache_entry_start_value;
|
||||||
|
ULONG cache_entry_end_value;
|
||||||
|
|
||||||
|
|
||||||
/* Calculate the block starting address. */
|
/* Calculate the block starting address.
|
||||||
block_start_address = nor_flash -> lx_nor_flash_base_address + (block * nor_flash -> lx_nor_flash_words_per_block);
|
MISRA C:2012 Rule 11.4 deviation: NOR driver addresses may be logical
|
||||||
block_end_address = block_start_address + nor_flash -> lx_nor_flash_words_per_block;
|
address tokens, including zero, so compare address values without
|
||||||
|
dereferencing them. */
|
||||||
|
block_start_address = (ULONG)(nor_flash -> lx_nor_flash_base_address) + (block * nor_flash -> lx_nor_flash_words_per_block * sizeof(ULONG));
|
||||||
|
block_end_address = block_start_address + (nor_flash -> lx_nor_flash_words_per_block * sizeof(ULONG));
|
||||||
|
|
||||||
/* Loop through the cache entries to see if there is a sector in cache. */
|
/* Loop through the cache entries to see if there is a sector in cache. */
|
||||||
for (i = 0; i < nor_flash -> lx_nor_flash_extended_cache_entries; i++)
|
for (i = 0; i < nor_flash -> lx_nor_flash_extended_cache_entries; i++)
|
||||||
@@ -94,15 +100,21 @@ ULONG *cache_entry_end;
|
|||||||
|
|
||||||
/* Determine the cache entry addresses. */
|
/* Determine the cache entry addresses. */
|
||||||
cache_entry_start = nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_address;
|
cache_entry_start = nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_address;
|
||||||
cache_entry_end = cache_entry_start + LX_NOR_SECTOR_SIZE;
|
|
||||||
|
|
||||||
/* Determine if the flash address in in the cache entry. */
|
/* Determine if the cache entry is in the block being erased. */
|
||||||
if ((cache_entry_start) && (block_start_address <= cache_entry_start) && (block_end_address > cache_entry_end))
|
if (nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_valid)
|
||||||
|
{
|
||||||
|
cache_entry_start_value = (ULONG)cache_entry_start;
|
||||||
|
cache_entry_end_value = cache_entry_start_value + (LX_NOR_SECTOR_SIZE * sizeof(ULONG));
|
||||||
|
|
||||||
|
if ((block_start_address <= cache_entry_start_value) && (block_end_address >= cache_entry_end_value))
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Yes, this cache entry is in the block to be erased so invalidate it. */
|
/* Yes, this cache entry is in the block to be erased so invalidate it. */
|
||||||
nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_address = LX_NULL;
|
nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_address = LX_NULL;
|
||||||
nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_access_count = 0;
|
nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_access_count = 0;
|
||||||
|
nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_valid = LX_FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -117,5 +129,3 @@ ULONG *cache_entry_end;
|
|||||||
/* Return completion status. */
|
/* Return completion status. */
|
||||||
return(status);
|
return(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
|
// Some portions generated by Codex (GPT-5).
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
@@ -76,8 +78,11 @@ UINT _lx_nor_flash_driver_read(LX_NOR_FLASH *nor_flash, ULONG *flash_address, U
|
|||||||
UINT status;
|
UINT status;
|
||||||
UINT i;
|
UINT i;
|
||||||
ULONG *cache_entry_start;
|
ULONG *cache_entry_start;
|
||||||
ULONG *cache_entry_end;
|
ULONG cache_entry_start_value;
|
||||||
|
ULONG cache_entry_end_value;
|
||||||
ULONG cache_offset;
|
ULONG cache_offset;
|
||||||
|
ULONG flash_address_value;
|
||||||
|
ULONG base_address_value;
|
||||||
UINT least_used_cache_entry;
|
UINT least_used_cache_entry;
|
||||||
|
|
||||||
|
|
||||||
@@ -91,6 +96,11 @@ UINT least_used_cache_entry;
|
|||||||
/* Initialize the least used cache entry. */
|
/* Initialize the least used cache entry. */
|
||||||
least_used_cache_entry = 0;
|
least_used_cache_entry = 0;
|
||||||
|
|
||||||
|
/* MISRA C:2012 Rule 11.4 deviation: NOR driver addresses may be logical
|
||||||
|
address tokens, including zero, so compare address values without
|
||||||
|
dereferencing them. */
|
||||||
|
flash_address_value = (ULONG)flash_address;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -102,10 +112,14 @@ UINT least_used_cache_entry;
|
|||||||
|
|
||||||
/* Determine the cache entry addresses. */
|
/* Determine the cache entry addresses. */
|
||||||
cache_entry_start = nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_address;
|
cache_entry_start = nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_address;
|
||||||
cache_entry_end = cache_entry_start + LX_NOR_SECTOR_SIZE;
|
|
||||||
|
|
||||||
/* Determine if the flash address in in the cache entry. */
|
/* Determine if the flash address is in the cache entry. */
|
||||||
if ((cache_entry_start) && (flash_address >= cache_entry_start) && (flash_address < cache_entry_end))
|
if (nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_valid)
|
||||||
|
{
|
||||||
|
cache_entry_start_value = (ULONG)cache_entry_start;
|
||||||
|
cache_entry_end_value = cache_entry_start_value + (LX_NOR_SECTOR_SIZE * sizeof(ULONG));
|
||||||
|
|
||||||
|
if ((flash_address_value >= cache_entry_start_value) && (flash_address_value < cache_entry_end_value))
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Yes, we found the entry. */
|
/* Yes, we found the entry. */
|
||||||
@@ -114,7 +128,7 @@ UINT least_used_cache_entry;
|
|||||||
nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_access_count++;
|
nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_access_count++;
|
||||||
|
|
||||||
/* Calculate the offset into the cache entry. */
|
/* Calculate the offset into the cache entry. */
|
||||||
cache_offset = (ULONG)(flash_address - cache_entry_start);
|
cache_offset = (flash_address_value - cache_entry_start_value) / sizeof(ULONG);
|
||||||
|
|
||||||
/* Copy the word from the cache. */
|
/* Copy the word from the cache. */
|
||||||
*destination = *(nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_memory + cache_offset);
|
*destination = *(nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_memory + cache_offset);
|
||||||
@@ -125,8 +139,7 @@ UINT least_used_cache_entry;
|
|||||||
/* Return success. */
|
/* Return success. */
|
||||||
return(LX_SUCCESS);
|
return(LX_SUCCESS);
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
{
|
|
||||||
|
|
||||||
/* Determine if we have a new least used sector. */
|
/* Determine if we have a new least used sector. */
|
||||||
if (i != least_used_cache_entry)
|
if (i != least_used_cache_entry)
|
||||||
@@ -142,12 +155,12 @@ UINT least_used_cache_entry;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Now read in the sector into the cache. */
|
/* Now read in the sector into the cache. */
|
||||||
cache_offset = (ULONG)(flash_address - nor_flash -> lx_nor_flash_base_address);
|
base_address_value = (ULONG)(nor_flash -> lx_nor_flash_base_address);
|
||||||
|
cache_offset = (flash_address_value - base_address_value) / sizeof(ULONG);
|
||||||
cache_offset = cache_offset & ~((ULONG) (LX_NOR_SECTOR_SIZE-1));
|
cache_offset = cache_offset & ~((ULONG) (LX_NOR_SECTOR_SIZE-1));
|
||||||
cache_entry_start = nor_flash -> lx_nor_flash_base_address + cache_offset;
|
cache_entry_start = (ULONG *)(base_address_value + (cache_offset * sizeof(ULONG)));
|
||||||
|
|
||||||
/* Call the actual driver read function. */
|
/* Call the actual driver read function. */
|
||||||
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
||||||
@@ -171,6 +184,7 @@ UINT least_used_cache_entry;
|
|||||||
/* Setup the cache entry. */
|
/* Setup the cache entry. */
|
||||||
nor_flash -> lx_nor_flash_extended_cache[least_used_cache_entry].lx_nor_flash_extended_cache_entry_sector_address = cache_entry_start;
|
nor_flash -> lx_nor_flash_extended_cache[least_used_cache_entry].lx_nor_flash_extended_cache_entry_sector_address = cache_entry_start;
|
||||||
nor_flash -> lx_nor_flash_extended_cache[least_used_cache_entry].lx_nor_flash_extended_cache_entry_access_count = 0;
|
nor_flash -> lx_nor_flash_extended_cache[least_used_cache_entry].lx_nor_flash_extended_cache_entry_access_count = 0;
|
||||||
|
nor_flash -> lx_nor_flash_extended_cache[least_used_cache_entry].lx_nor_flash_extended_cache_entry_valid = LX_TRUE;
|
||||||
|
|
||||||
/* Increment the number of cache misses. */
|
/* Increment the number of cache misses. */
|
||||||
nor_flash -> lx_nor_flash_extended_cache_misses++;
|
nor_flash -> lx_nor_flash_extended_cache_misses++;
|
||||||
@@ -211,5 +225,3 @@ UINT status;
|
|||||||
return(status);
|
return(status);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
|
// Some portions generated by Codex (GPT-5).
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
@@ -77,8 +79,10 @@ UINT _lx_nor_flash_driver_write(LX_NOR_FLASH *nor_flash, ULONG *flash_address,
|
|||||||
UINT status;
|
UINT status;
|
||||||
UINT i;
|
UINT i;
|
||||||
ULONG *cache_entry_start;
|
ULONG *cache_entry_start;
|
||||||
ULONG *cache_entry_end;
|
ULONG cache_entry_start_value;
|
||||||
|
ULONG cache_entry_end_value;
|
||||||
ULONG cache_offset;
|
ULONG cache_offset;
|
||||||
|
ULONG flash_address_value;
|
||||||
|
|
||||||
|
|
||||||
/* Is the request a whole sector or a partial sector. */
|
/* Is the request a whole sector or a partial sector. */
|
||||||
@@ -87,6 +91,11 @@ ULONG cache_offset;
|
|||||||
|
|
||||||
/* One word request, which implies that it is a NOR flash metadata write. */
|
/* One word request, which implies that it is a NOR flash metadata write. */
|
||||||
|
|
||||||
|
/* MISRA C:2012 Rule 11.4 deviation: NOR driver addresses may be logical
|
||||||
|
address tokens, including zero, so compare address values without
|
||||||
|
dereferencing them. */
|
||||||
|
flash_address_value = (ULONG)flash_address;
|
||||||
|
|
||||||
/* Loop through the cache entries to see if there is a sector in cache. */
|
/* Loop through the cache entries to see if there is a sector in cache. */
|
||||||
for (i = 0; i < nor_flash -> lx_nor_flash_extended_cache_entries; i++)
|
for (i = 0; i < nor_flash -> lx_nor_flash_extended_cache_entries; i++)
|
||||||
{
|
{
|
||||||
@@ -95,16 +104,20 @@ ULONG cache_offset;
|
|||||||
|
|
||||||
/* Determine the cache entry addresses. */
|
/* Determine the cache entry addresses. */
|
||||||
cache_entry_start = nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_address;
|
cache_entry_start = nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_address;
|
||||||
cache_entry_end = cache_entry_start + LX_NOR_SECTOR_SIZE;
|
|
||||||
|
|
||||||
/* Determine if the flash address in in the cache entry. */
|
/* Determine if the flash address is in the cache entry. */
|
||||||
if ((cache_entry_start) && (flash_address >= cache_entry_start) && (flash_address < cache_entry_end))
|
if (nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_valid)
|
||||||
|
{
|
||||||
|
cache_entry_start_value = (ULONG)cache_entry_start;
|
||||||
|
cache_entry_end_value = cache_entry_start_value + (LX_NOR_SECTOR_SIZE * sizeof(ULONG));
|
||||||
|
|
||||||
|
if ((flash_address_value >= cache_entry_start_value) && (flash_address_value < cache_entry_end_value))
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Yes, we found the entry. */
|
/* Yes, we found the entry. */
|
||||||
|
|
||||||
/* Calculate the offset into the cache entry. */
|
/* Calculate the offset into the cache entry. */
|
||||||
cache_offset = (ULONG)(flash_address - cache_entry_start);
|
cache_offset = (flash_address_value - cache_entry_start_value) / sizeof(ULONG);
|
||||||
|
|
||||||
/* Copy the word into the cache. */
|
/* Copy the word into the cache. */
|
||||||
*(nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_memory + cache_offset) = *source;
|
*(nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_memory + cache_offset) = *source;
|
||||||
@@ -114,6 +127,7 @@ ULONG cache_offset;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* In any case, call the actual driver write function. */
|
/* In any case, call the actual driver write function. */
|
||||||
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
||||||
@@ -140,4 +154,3 @@ UINT status;
|
|||||||
return(status);
|
return(status);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
|
// Some portions generated by Codex (GPT-5).
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
@@ -93,8 +95,11 @@ ULONG block_word;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Calculate cache size in words. */
|
||||||
|
cache_size = size / sizeof(ULONG);
|
||||||
|
|
||||||
/* Determine if memory was specified but with an invalid size (less than one NOR sector). */
|
/* Determine if memory was specified but with an invalid size (less than one NOR sector). */
|
||||||
if ((memory) && (size < LX_NOR_SECTOR_SIZE))
|
if ((memory) && (cache_size < LX_NOR_SECTOR_SIZE))
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Error in memory size supplied. */
|
/* Error in memory size supplied. */
|
||||||
@@ -110,9 +115,6 @@ ULONG block_word;
|
|||||||
/* Initialize the internal NOR cache. */
|
/* Initialize the internal NOR cache. */
|
||||||
nor_flash -> lx_nor_flash_extended_cache_entries = 0;
|
nor_flash -> lx_nor_flash_extended_cache_entries = 0;
|
||||||
|
|
||||||
/* Calculate cache size in words. */
|
|
||||||
cache_size = size/sizeof(ULONG);
|
|
||||||
|
|
||||||
/* Setup cache memory pointer. */
|
/* Setup cache memory pointer. */
|
||||||
cache_memory = (ULONG *) memory;
|
cache_memory = (ULONG *) memory;
|
||||||
|
|
||||||
@@ -276,6 +278,7 @@ ULONG block_word;
|
|||||||
nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_address = LX_NULL;
|
nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_address = LX_NULL;
|
||||||
nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_memory = cache_memory;
|
nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_memory = cache_memory;
|
||||||
nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_access_count = 0;
|
nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_access_count = 0;
|
||||||
|
nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_valid = LX_FALSE;
|
||||||
|
|
||||||
/* Move the cache memory forward. */
|
/* Move the cache memory forward. */
|
||||||
cache_memory = cache_memory + LX_NOR_SECTOR_SIZE;
|
cache_memory = cache_memory + LX_NOR_SECTOR_SIZE;
|
||||||
@@ -317,5 +320,3 @@ ULONG block_word;
|
|||||||
return(LX_DISABLED);
|
return(LX_DISABLED);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
|
/***************************************************************************/
|
||||||
|
/* Copyright (c) 2024 Microsoft Corporation */
|
||||||
|
/* Copyright (c) 2026 Eclipse ThreadX contributors */
|
||||||
|
/* */
|
||||||
|
/* This program and the accompanying materials are made available under */
|
||||||
|
/* the terms of the MIT License which is available at */
|
||||||
|
/* https://opensource.org/licenses/MIT. */
|
||||||
|
/* */
|
||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
/***************************************************************************/
|
||||||
|
|
||||||
/* This is a small demo of the high-performance FileX FAT file system with LevelX
|
/* This is a small demo of the high-performance FileX FAT file system with LevelX
|
||||||
and the NAND simulated driver. */
|
and the NAND simulated driver. */
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
|
/***************************************************************************/
|
||||||
|
/* Copyright (c) 2024 Microsoft Corporation */
|
||||||
|
/* Copyright (c) 2026 Eclipse ThreadX contributors */
|
||||||
|
/* */
|
||||||
|
/* This program and the accompanying materials are made available under */
|
||||||
|
/* the terms of the MIT License which is available at */
|
||||||
|
/* https://opensource.org/licenses/MIT. */
|
||||||
|
/* */
|
||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
/***************************************************************************/
|
||||||
|
|
||||||
/* This is a small demo of the high-performance FileX FAT file system with LevelX
|
/* This is a small demo of the high-performance FileX FAT file system with LevelX
|
||||||
and the NOR simulated driver. */
|
and the NOR simulated driver. */
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,13 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
##############################################################################
|
||||||
|
# Copyright (c) 2024 Microsoft Corporation
|
||||||
|
# Copyright (c) 2026 Eclipse ThreadX contributors
|
||||||
|
#
|
||||||
|
# This program and the accompanying materials are made available under the
|
||||||
|
# terms of the MIT License which is available at
|
||||||
|
# https://opensource.org/licenses/MIT.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
$(dirname `realpath $0`)/../test/cmake/run.sh build all
|
$(dirname `realpath $0`)/../test/cmake/run.sh build all
|
||||||
@@ -1,4 +1,15 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
##############################################################################
|
||||||
|
# Copyright (c) 2024 Microsoft Corporation
|
||||||
|
# Copyright (c) 2026 Eclipse ThreadX contributors
|
||||||
|
#
|
||||||
|
# This program and the accompanying materials are made available under the
|
||||||
|
# terms of the MIT License which is available at
|
||||||
|
# https://opensource.org/licenses/MIT.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
||||||
# Remove large folder
|
# Remove large folder
|
||||||
|
|||||||
Executable
+132
@@ -0,0 +1,132 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# prepare_release.sh
|
||||||
|
# Prepares a LevelX release by updating version constants.
|
||||||
|
#
|
||||||
|
# Usage: prepare_release.sh <version>
|
||||||
|
# Example: prepare_release.sh 6.5.1.202602
|
||||||
|
# Hotfix: prepare_release.sh 6.5.1.202602a
|
||||||
|
#
|
||||||
|
# This script:
|
||||||
|
# 1. Creates branch release-<version>-preparation from dev
|
||||||
|
# 2. Updates version constants in common/inc/lx_api.h
|
||||||
|
# (commit: "Updated version number constants")
|
||||||
|
# (No port-specific version strings in this repository)
|
||||||
|
#
|
||||||
|
# Copyright (C) 2026 Eclipse ThreadX contributors
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||||
|
|
||||||
|
API_HEADER="${REPO_ROOT}/common/inc/lx_api.h"
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
# Argument validation
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
if [ "$#" -ne 1 ]; then
|
||||||
|
printf "Usage: %s <version>\n" "$(basename "$0")" >&2
|
||||||
|
printf "Example: %s 6.5.1.202602\n" "$(basename "$0")" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
VERSION="$1"
|
||||||
|
|
||||||
|
if ! printf "%s" "${VERSION}" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+[a-z]?$'; then
|
||||||
|
printf "Error: Invalid version format '%s'.\n" "${VERSION}" >&2
|
||||||
|
printf "Expected: MAJOR.MINOR.PATCH.BUILD[hotfix_letter]\n" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
# Parse version components
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
MAJOR=$(printf "%s" "${VERSION}" | cut -d. -f1)
|
||||||
|
MINOR=$(printf "%s" "${VERSION}" | cut -d. -f2)
|
||||||
|
PATCH=$(printf "%s" "${VERSION}" | cut -d. -f3)
|
||||||
|
BUILD_AND_HOTFIX=$(printf "%s" "${VERSION}" | cut -d. -f4)
|
||||||
|
BUILD=$(printf "%s" "${BUILD_AND_HOTFIX}" | sed -E 's/[a-z]+$//')
|
||||||
|
HOTFIX=$(printf "%s" "${BUILD_AND_HOTFIX}" | sed -E 's/^[0-9]+//')
|
||||||
|
|
||||||
|
if [ -z "${HOTFIX}" ]; then
|
||||||
|
HOTFIX_DEFINE="' '"
|
||||||
|
else
|
||||||
|
HOTFIX_DEFINE="'${HOTFIX}'"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
# Read and display current version
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
CURR_MAJOR=$(grep -E "^#define LEVELX_MAJOR_VERSION" "${API_HEADER}" | awk '{print $NF}')
|
||||||
|
CURR_MINOR=$(grep -E "^#define LEVELX_MINOR_VERSION" "${API_HEADER}" | awk '{print $NF}')
|
||||||
|
CURR_PATCH=$(grep -E "^#define LEVELX_PATCH_VERSION" "${API_HEADER}" | awk '{print $NF}')
|
||||||
|
CURR_BUILD=$(grep -E "^#define LEVELX_BUILD_VERSION" "${API_HEADER}" | awk '{print $NF}')
|
||||||
|
CURR_HOTFIX=$(grep -E "^#define LEVELX_HOTFIX_VERSION" "${API_HEADER}" | \
|
||||||
|
sed -E "s/.*'([^']*)'.*/\1/" | tr -d ' ')
|
||||||
|
|
||||||
|
if [ -z "${CURR_HOTFIX}" ]; then
|
||||||
|
CURR_VER="${CURR_MAJOR}.${CURR_MINOR}.${CURR_PATCH}.${CURR_BUILD}"
|
||||||
|
else
|
||||||
|
CURR_VER="${CURR_MAJOR}.${CURR_MINOR}.${CURR_PATCH}.${CURR_BUILD}${CURR_HOTFIX}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "\nLevelX release preparation\n"
|
||||||
|
printf " Repository : %s\n" "${REPO_ROOT}"
|
||||||
|
printf " Current version : %s\n" "${CURR_VER}"
|
||||||
|
printf " Target version : %s\n\n" "${VERSION}"
|
||||||
|
printf "Proceed with update? [y/N] "
|
||||||
|
read -r CONFIRM
|
||||||
|
case "${CONFIRM}" in
|
||||||
|
y|Y) ;;
|
||||||
|
*)
|
||||||
|
printf "Aborted.\n"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
# Pre-flight checks
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
if ! git -C "${REPO_ROOT}" diff --quiet HEAD 2>/dev/null; then
|
||||||
|
printf "Error: Working tree has uncommitted changes. Commit or stash first.\n" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
# Create feature branch from dev
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
BRANCH_NAME="release-${VERSION}-preparation"
|
||||||
|
printf "\nChecking out dev and pulling latest changes...\n"
|
||||||
|
git -C "${REPO_ROOT}" checkout dev
|
||||||
|
git -C "${REPO_ROOT}" pull origin dev
|
||||||
|
printf "Creating branch '%s'...\n" "${BRANCH_NAME}"
|
||||||
|
git -C "${REPO_ROOT}" checkout -b "${BRANCH_NAME}"
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
# Update version constants
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
printf "\nUpdating version constants in %s...\n" "${API_HEADER}"
|
||||||
|
|
||||||
|
sed -i -E "s|(#define LEVELX_MAJOR_VERSION[[:space:]]+)[0-9]+|\1${MAJOR}|" "${API_HEADER}"
|
||||||
|
sed -i -E "s|(#define LEVELX_MINOR_VERSION[[:space:]]+)[0-9]+|\1${MINOR}|" "${API_HEADER}"
|
||||||
|
sed -i -E "s|(#define LEVELX_PATCH_VERSION[[:space:]]+)[0-9]+|\1${PATCH}|" "${API_HEADER}"
|
||||||
|
sed -i -E "s|(#define LEVELX_BUILD_VERSION[[:space:]]+)[0-9]+|\1${BUILD}|" "${API_HEADER}"
|
||||||
|
sed -i -E "s|(#define LEVELX_HOTFIX_VERSION[[:space:]]+)'[^']*'|\1${HOTFIX_DEFINE}|" "${API_HEADER}"
|
||||||
|
|
||||||
|
git -C "${REPO_ROOT}" add "${API_HEADER}"
|
||||||
|
git -C "${REPO_ROOT}" commit -F - <<'COMMIT_EOF'
|
||||||
|
Updated version number constants
|
||||||
|
|
||||||
|
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
||||||
|
COMMIT_EOF
|
||||||
|
|
||||||
|
printf "Committed version constant updates.\n"
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
# Port version strings
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
printf "\nNo port-specific version strings in this repository. Skipping port commit.\n"
|
||||||
|
|
||||||
|
printf "\nRelease preparation complete.\n"
|
||||||
|
printf "Branch '%s' is ready for review.\n" "${BRANCH_NAME}"
|
||||||
@@ -1,2 +1,13 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
##############################################################################
|
||||||
|
# Copyright (c) 2024 Microsoft Corporation
|
||||||
|
# Copyright (c) 2026 Eclipse ThreadX contributors
|
||||||
|
#
|
||||||
|
# This program and the accompanying materials are made available under the
|
||||||
|
# terms of the MIT License which is available at
|
||||||
|
# https://opensource.org/licenses/MIT.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
$(dirname `realpath $0`)/../test/cmake/run.sh test all
|
$(dirname `realpath $0`)/../test/cmake/run.sh test all
|
||||||
@@ -1,4 +1,15 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
##############################################################################
|
||||||
|
# Copyright (c) 2024 Microsoft Corporation
|
||||||
|
# Copyright (c) 2026 Eclipse ThreadX contributors
|
||||||
|
#
|
||||||
|
# This program and the accompanying materials are made available under the
|
||||||
|
# terms of the MIT License which is available at
|
||||||
|
# https://opensource.org/licenses/MIT.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,15 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
##############################################################################
|
||||||
|
# Copyright (c) 2024 Microsoft Corporation
|
||||||
|
# Copyright (c) 2026 Eclipse ThreadX contributors
|
||||||
|
#
|
||||||
|
# This program and the accompanying materials are made available under the
|
||||||
|
# terms of the MIT License which is available at
|
||||||
|
# https://opensource.org/licenses/MIT.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
|
||||||
cd $(dirname $0)
|
cd $(dirname $0)
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
|
/***************************************************************************/
|
||||||
|
/* Copyright (c) 2024 Microsoft Corporation */
|
||||||
|
/* Copyright (c) 2026 Eclipse ThreadX contributors */
|
||||||
|
/* */
|
||||||
|
/* This program and the accompanying materials are made available under */
|
||||||
|
/* the terms of the MIT License which is available at */
|
||||||
|
/* https://opensource.org/licenses/MIT. */
|
||||||
|
/* */
|
||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
/***************************************************************************/
|
||||||
|
|
||||||
/* Basic NOR flash tests... */
|
/* Basic NOR flash tests... */
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
|
/***************************************************************************/
|
||||||
|
/* Copyright (c) 2024 Microsoft Corporation */
|
||||||
|
/* Copyright (c) 2026 Eclipse ThreadX contributors */
|
||||||
|
/* */
|
||||||
|
/* This program and the accompanying materials are made available under */
|
||||||
|
/* the terms of the MIT License which is available at */
|
||||||
|
/* https://opensource.org/licenses/MIT. */
|
||||||
|
/* */
|
||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
/***************************************************************************/
|
||||||
|
|
||||||
/* Basic NOR flash tests... */
|
/* Basic NOR flash tests... */
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|||||||
@@ -1,3 +1,16 @@
|
|||||||
|
/***************************************************************************/
|
||||||
|
/* Copyright (c) 2024 Microsoft Corporation */
|
||||||
|
/* Copyright (c) 2026 Eclipse ThreadX contributors */
|
||||||
|
/* */
|
||||||
|
/* This program and the accompanying materials are made available under */
|
||||||
|
/* the terms of the MIT License which is available at */
|
||||||
|
/* https://opensource.org/licenses/MIT. */
|
||||||
|
/* */
|
||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
/***************************************************************************/
|
||||||
|
|
||||||
|
// Some portions generated by Codex (GPT-5).
|
||||||
|
|
||||||
/* Basic NOR flash tests... */
|
/* Basic NOR flash tests... */
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -20,11 +33,31 @@ ULONG readbuffer[128];
|
|||||||
|
|
||||||
UCHAR nor_cache_memory[2048+16+8];
|
UCHAR nor_cache_memory[2048+16+8];
|
||||||
UCHAR nor_cache_memory2[8192];
|
UCHAR nor_cache_memory2[8192];
|
||||||
|
UCHAR nor_cache_memory_invalid[256];
|
||||||
|
#ifndef LX_NOR_DISABLE_EXTENDED_CACHE
|
||||||
|
UCHAR nor_zero_base_cache_memory[512];
|
||||||
|
ULONG nor_zero_base_memory[LX_NOR_SECTOR_SIZE * 2];
|
||||||
|
ULONG nor_zero_base_driver_read_count;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Define LevelX NOR flash simulator prototoypes. */
|
/* Define LevelX NOR flash simulator prototoypes. */
|
||||||
|
|
||||||
UINT _lx_nor_flash_simulator_initialize(LX_NOR_FLASH *nor_flash);
|
UINT _lx_nor_flash_simulator_initialize(LX_NOR_FLASH *nor_flash);
|
||||||
|
#ifndef LX_NOR_DISABLE_EXTENDED_CACHE
|
||||||
|
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
||||||
|
static UINT zero_base_nor_read(LX_NOR_FLASH *nor_flash, ULONG *flash_address, ULONG *destination, ULONG words);
|
||||||
|
static UINT zero_base_nor_write(LX_NOR_FLASH *nor_flash, ULONG *flash_address, ULONG *source, ULONG words);
|
||||||
|
static UINT zero_base_nor_block_erase(LX_NOR_FLASH *nor_flash, ULONG block, ULONG erase_count);
|
||||||
|
static UINT zero_base_nor_block_erased_verify(LX_NOR_FLASH *nor_flash, ULONG block);
|
||||||
|
#else
|
||||||
|
static UINT zero_base_nor_read(ULONG *flash_address, ULONG *destination, ULONG words);
|
||||||
|
static UINT zero_base_nor_write(ULONG *flash_address, ULONG *source, ULONG words);
|
||||||
|
static UINT zero_base_nor_block_erase(ULONG block, ULONG erase_count);
|
||||||
|
static UINT zero_base_nor_block_erased_verify(ULONG block);
|
||||||
|
#endif
|
||||||
|
static UINT zero_base_nor_initialize(LX_NOR_FLASH *nor_flash);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -62,12 +95,177 @@ void tx_application_define(void *first_unused_memory)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef LX_NOR_DISABLE_EXTENDED_CACHE
|
||||||
|
static UINT zero_base_nor_initialize(LX_NOR_FLASH *nor_flash)
|
||||||
|
{
|
||||||
|
|
||||||
|
UINT status;
|
||||||
|
|
||||||
|
|
||||||
|
/* Setup the base address as a logical zero offset. */
|
||||||
|
nor_flash -> lx_nor_flash_base_address = LX_NULL;
|
||||||
|
|
||||||
|
/* Setup geometry of the test flash. */
|
||||||
|
nor_flash -> lx_nor_flash_total_blocks = 1;
|
||||||
|
nor_flash -> lx_nor_flash_words_per_block = LX_NOR_SECTOR_SIZE * 2;
|
||||||
|
|
||||||
|
/* Setup function pointers for the NOR flash services. */
|
||||||
|
nor_flash -> lx_nor_flash_driver_read = zero_base_nor_read;
|
||||||
|
nor_flash -> lx_nor_flash_driver_write = zero_base_nor_write;
|
||||||
|
nor_flash -> lx_nor_flash_driver_block_erase = zero_base_nor_block_erase;
|
||||||
|
nor_flash -> lx_nor_flash_driver_block_erased_verify = zero_base_nor_block_erased_verify;
|
||||||
|
|
||||||
|
/* Setup local buffer for NOR flash operation. */
|
||||||
|
nor_flash -> lx_nor_flash_sector_buffer = buffer;
|
||||||
|
|
||||||
|
/* Erase the test flash. */
|
||||||
|
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
||||||
|
status = zero_base_nor_block_erase(nor_flash, 0, 0);
|
||||||
|
#else
|
||||||
|
status = zero_base_nor_block_erase(0, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Return completion status. */
|
||||||
|
return(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
||||||
|
static UINT zero_base_nor_read(LX_NOR_FLASH *nor_flash, ULONG *flash_address, ULONG *destination, ULONG words)
|
||||||
|
#else
|
||||||
|
static UINT zero_base_nor_read(ULONG *flash_address, ULONG *destination, ULONG words)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
|
||||||
|
ULONG offset;
|
||||||
|
|
||||||
|
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
||||||
|
LX_PARAMETER_NOT_USED(nor_flash);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* MISRA C:2012 Rule 11.4 deviation: this test driver intentionally treats
|
||||||
|
NOR flash addresses as logical offsets, including zero. */
|
||||||
|
offset = ((ULONG)flash_address) / sizeof(ULONG);
|
||||||
|
|
||||||
|
if ((offset + words) > (LX_NOR_SECTOR_SIZE * 2))
|
||||||
|
{
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
nor_zero_base_driver_read_count++;
|
||||||
|
|
||||||
|
while (words--)
|
||||||
|
{
|
||||||
|
*destination++ = nor_zero_base_memory[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
return(LX_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
||||||
|
static UINT zero_base_nor_write(LX_NOR_FLASH *nor_flash, ULONG *flash_address, ULONG *source, ULONG words)
|
||||||
|
#else
|
||||||
|
static UINT zero_base_nor_write(ULONG *flash_address, ULONG *source, ULONG words)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
|
||||||
|
ULONG offset;
|
||||||
|
|
||||||
|
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
||||||
|
LX_PARAMETER_NOT_USED(nor_flash);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* MISRA C:2012 Rule 11.4 deviation: this test driver intentionally treats
|
||||||
|
NOR flash addresses as logical offsets, including zero. */
|
||||||
|
offset = ((ULONG)flash_address) / sizeof(ULONG);
|
||||||
|
|
||||||
|
if ((offset + words) > (LX_NOR_SECTOR_SIZE * 2))
|
||||||
|
{
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (words--)
|
||||||
|
{
|
||||||
|
nor_zero_base_memory[offset++] = *source++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(LX_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
||||||
|
static UINT zero_base_nor_block_erase(LX_NOR_FLASH *nor_flash, ULONG block, ULONG erase_count)
|
||||||
|
#else
|
||||||
|
static UINT zero_base_nor_block_erase(ULONG block, ULONG erase_count)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
|
||||||
|
ULONG offset;
|
||||||
|
ULONG words;
|
||||||
|
|
||||||
|
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
||||||
|
LX_PARAMETER_NOT_USED(nor_flash);
|
||||||
|
#endif
|
||||||
|
LX_PARAMETER_NOT_USED(erase_count);
|
||||||
|
|
||||||
|
if (block != 0)
|
||||||
|
{
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = 0;
|
||||||
|
words = LX_NOR_SECTOR_SIZE * 2;
|
||||||
|
|
||||||
|
while (words--)
|
||||||
|
{
|
||||||
|
nor_zero_base_memory[offset++] = LX_ALL_ONES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(LX_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
||||||
|
static UINT zero_base_nor_block_erased_verify(LX_NOR_FLASH *nor_flash, ULONG block)
|
||||||
|
#else
|
||||||
|
static UINT zero_base_nor_block_erased_verify(ULONG block)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
|
||||||
|
ULONG offset;
|
||||||
|
ULONG words;
|
||||||
|
|
||||||
|
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
|
||||||
|
LX_PARAMETER_NOT_USED(nor_flash);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (block != 0)
|
||||||
|
{
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = 0;
|
||||||
|
words = LX_NOR_SECTOR_SIZE * 2;
|
||||||
|
|
||||||
|
while (words--)
|
||||||
|
{
|
||||||
|
if (nor_zero_base_memory[offset++] != LX_ALL_ONES)
|
||||||
|
{
|
||||||
|
return(LX_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(LX_SUCCESS);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Define the test threads. */
|
/* Define the test threads. */
|
||||||
|
|
||||||
void thread_0_entry(ULONG thread_input)
|
void thread_0_entry(ULONG thread_input)
|
||||||
{
|
{
|
||||||
|
|
||||||
ULONG i, j, sector;
|
ULONG i, j, sector;
|
||||||
|
#ifndef LX_NOR_DISABLE_EXTENDED_CACHE
|
||||||
|
ULONG read_count;
|
||||||
|
ULONG *last_sector_address;
|
||||||
|
#endif
|
||||||
UINT status;
|
UINT status;
|
||||||
|
|
||||||
ULONG *word_ptr;
|
ULONG *word_ptr;
|
||||||
@@ -76,6 +274,148 @@ ULONG *word_ptr;
|
|||||||
/* Initialize LevelX. */
|
/* Initialize LevelX. */
|
||||||
_lx_nor_flash_initialize();
|
_lx_nor_flash_initialize();
|
||||||
|
|
||||||
|
#ifndef LX_NOR_DISABLE_EXTENDED_CACHE
|
||||||
|
/* Test 0: Extended cache with a zero NOR flash base address. */
|
||||||
|
printf("Test 0: Extended cache with zero base address....");
|
||||||
|
|
||||||
|
LX_MEMSET(&nor_sim_flash, 0, sizeof(nor_sim_flash));
|
||||||
|
status = zero_base_nor_initialize(&nor_sim_flash);
|
||||||
|
nor_zero_base_memory[0] = 0x12345678;
|
||||||
|
/* MISRA C:2012 Rule 11.6 deviation: this test driver intentionally
|
||||||
|
treats NOR flash addresses as logical offset tokens. */
|
||||||
|
last_sector_address = (ULONG *)(LX_NOR_SECTOR_SIZE * sizeof(ULONG));
|
||||||
|
nor_zero_base_driver_read_count = 0;
|
||||||
|
|
||||||
|
if (status == LX_SUCCESS)
|
||||||
|
{
|
||||||
|
status = lx_nor_flash_extended_cache_enable(&nor_sim_flash, nor_zero_base_cache_memory, sizeof(nor_zero_base_cache_memory));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == LX_SUCCESS)
|
||||||
|
{
|
||||||
|
status = _lx_nor_flash_driver_read(&nor_sim_flash, LX_NULL, readbuffer, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((status != LX_SUCCESS) || (readbuffer[0] != 0x12345678) || (nor_zero_base_driver_read_count != 1))
|
||||||
|
{
|
||||||
|
printf("FAILED!\n");
|
||||||
|
#ifdef BATCH_TEST
|
||||||
|
exit(1);
|
||||||
|
#endif
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status = _lx_nor_flash_driver_read(&nor_sim_flash, LX_NULL, readbuffer, 1);
|
||||||
|
|
||||||
|
if ((status != LX_SUCCESS) || (readbuffer[0] != 0x12345678) || (nor_zero_base_driver_read_count != 1))
|
||||||
|
{
|
||||||
|
printf("FAILED!\n");
|
||||||
|
#ifdef BATCH_TEST
|
||||||
|
exit(1);
|
||||||
|
#endif
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[0] = 0x87654321;
|
||||||
|
status = _lx_nor_flash_driver_write(&nor_sim_flash, LX_NULL, buffer, 1);
|
||||||
|
|
||||||
|
if ((status != LX_SUCCESS) || (nor_zero_base_memory[0] != 0x87654321))
|
||||||
|
{
|
||||||
|
printf("FAILED!\n");
|
||||||
|
#ifdef BATCH_TEST
|
||||||
|
exit(1);
|
||||||
|
#endif
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status = _lx_nor_flash_driver_read(&nor_sim_flash, LX_NULL, readbuffer, 1);
|
||||||
|
|
||||||
|
if ((status != LX_SUCCESS) || (readbuffer[0] != 0x87654321) || (nor_zero_base_driver_read_count != 1))
|
||||||
|
{
|
||||||
|
printf("FAILED!\n");
|
||||||
|
#ifdef BATCH_TEST
|
||||||
|
exit(1);
|
||||||
|
#endif
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
read_count = nor_zero_base_driver_read_count;
|
||||||
|
status = _lx_nor_flash_driver_block_erase(&nor_sim_flash, 0, 0);
|
||||||
|
|
||||||
|
if (status == LX_SUCCESS)
|
||||||
|
{
|
||||||
|
status = _lx_nor_flash_driver_read(&nor_sim_flash, LX_NULL, readbuffer, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((status != LX_SUCCESS) || (readbuffer[0] != LX_ALL_ONES) || (nor_zero_base_driver_read_count != (read_count + 1)))
|
||||||
|
{
|
||||||
|
printf("FAILED!\n");
|
||||||
|
#ifdef BATCH_TEST
|
||||||
|
exit(1);
|
||||||
|
#endif
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nor_zero_base_memory[LX_NOR_SECTOR_SIZE] = 0xABCDEF01;
|
||||||
|
|
||||||
|
status = _lx_nor_flash_driver_read(&nor_sim_flash, last_sector_address, readbuffer, 1);
|
||||||
|
|
||||||
|
if ((status != LX_SUCCESS) || (readbuffer[0] != 0xABCDEF01) || (nor_zero_base_driver_read_count != (read_count + 2)))
|
||||||
|
{
|
||||||
|
printf("FAILED!\n");
|
||||||
|
#ifdef BATCH_TEST
|
||||||
|
exit(1);
|
||||||
|
#endif
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status = _lx_nor_flash_driver_read(&nor_sim_flash, last_sector_address, readbuffer, 1);
|
||||||
|
|
||||||
|
if ((status != LX_SUCCESS) || (readbuffer[0] != 0xABCDEF01) || (nor_zero_base_driver_read_count != (read_count + 2)))
|
||||||
|
{
|
||||||
|
printf("FAILED!\n");
|
||||||
|
#ifdef BATCH_TEST
|
||||||
|
exit(1);
|
||||||
|
#endif
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
read_count = nor_zero_base_driver_read_count;
|
||||||
|
status = _lx_nor_flash_driver_block_erase(&nor_sim_flash, 0, 0);
|
||||||
|
|
||||||
|
if (status == LX_SUCCESS)
|
||||||
|
{
|
||||||
|
status = _lx_nor_flash_driver_read(&nor_sim_flash, last_sector_address, readbuffer, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((status != LX_SUCCESS) || (readbuffer[0] != LX_ALL_ONES) || (nor_zero_base_driver_read_count != (read_count + 1)))
|
||||||
|
{
|
||||||
|
printf("FAILED!\n");
|
||||||
|
#ifdef BATCH_TEST
|
||||||
|
exit(1);
|
||||||
|
#endif
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("SUCCESS!\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Test 1: Simple write 100 sectors and read 100 sectors. */
|
/* Test 1: Simple write 100 sectors and read 100 sectors. */
|
||||||
printf("Test 1: Simple write-read 100 sectors...........");
|
printf("Test 1: Simple write-read 100 sectors...........");
|
||||||
|
|
||||||
@@ -1581,7 +1921,25 @@ status += lx_nor_flash_extended_cache_enable(&nor_sim_flash, nor_cache_memory, s
|
|||||||
/* Open the flash. */
|
/* Open the flash. */
|
||||||
status = lx_nor_flash_open(&nor_sim_flash, "sim nor flash", _lx_nor_flash_simulator_initialize);
|
status = lx_nor_flash_open(&nor_sim_flash, "sim nor flash", _lx_nor_flash_simulator_initialize);
|
||||||
#ifndef LX_NOR_DISABLE_EXTENDED_CACHE
|
#ifndef LX_NOR_DISABLE_EXTENDED_CACHE
|
||||||
status += lx_nor_flash_extended_cache_enable(&nor_sim_flash, nor_cache_memory2, sizeof(nor_cache_memory2));
|
if (status == LX_SUCCESS)
|
||||||
|
{
|
||||||
|
|
||||||
|
status = lx_nor_flash_extended_cache_enable(&nor_sim_flash, nor_cache_memory_invalid, sizeof(nor_cache_memory_invalid));
|
||||||
|
|
||||||
|
if (status != LX_ERROR)
|
||||||
|
{
|
||||||
|
|
||||||
|
printf("FAILED!\n");
|
||||||
|
#ifdef BATCH_TEST
|
||||||
|
exit(1);
|
||||||
|
#endif
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status = lx_nor_flash_extended_cache_enable(&nor_sim_flash, nor_cache_memory2, sizeof(nor_cache_memory2));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (status != LX_SUCCESS)
|
if (status != LX_SUCCESS)
|
||||||
@@ -1657,5 +2015,3 @@ status += lx_nor_flash_extended_cache_enable(&nor_sim_flash, nor_cache_memory2,
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user