diff --git a/common/inc/lx_api.h b/common/inc/lx_api.h index 6ef35ff..935020e 100644 --- a/common/inc/lx_api.h +++ b/common/inc/lx_api.h @@ -73,12 +73,13 @@ extern "C" { #include "tx_api.h" #endif +#include + #ifdef LX_STANDALONE_ENABLE /* Define compiler library include files. */ -#include #include #include @@ -288,19 +289,49 @@ typedef unsigned long long ULONG64; #endif #ifndef LX_UTILITY_SHORT_SET -#define LX_UTILITY_SHORT_SET(address, value) *((USHORT*)(address)) = (USHORT)(value) +/* Store a 16-bit metadata value at any byte address. */ +static inline VOID _lx_utility_short_set(VOID *address, USHORT value) +{ + uint16_t data = (uint16_t)value; + + LX_MEMCPY(address, &data, sizeof(data)); +} +#define LX_UTILITY_SHORT_SET(address, value) _lx_utility_short_set((address), (USHORT)(value)) #endif #ifndef LX_UTILITY_LONG_SET -#define LX_UTILITY_LONG_SET(address, value) *((ULONG*)(address)) = (ULONG)(value) +/* NAND metadata words occupy four bytes on every target. */ +static inline VOID _lx_utility_long_set(VOID *address, ULONG value) +{ + uint32_t data = (uint32_t)value; + + LX_MEMCPY(address, &data, sizeof(data)); +} +#define LX_UTILITY_LONG_SET(address, value) _lx_utility_long_set((address), (ULONG)(value)) #endif #ifndef LX_UTILITY_SHORT_GET -#define LX_UTILITY_SHORT_GET(address) (*((USHORT*)(address))) +/* Read a 16-bit metadata value from any byte address. */ +static inline USHORT _lx_utility_short_get(const VOID *address) +{ + uint16_t data; + + LX_MEMCPY(&data, address, sizeof(data)); + return (USHORT)data; +} +#define LX_UTILITY_SHORT_GET(address) _lx_utility_short_get((address)) #endif #ifndef LX_UTILITY_LONG_GET -#define LX_UTILITY_LONG_GET(address) (*((ULONG*)(address))) +/* Read a four-byte NAND metadata word from any byte address. */ +static inline ULONG _lx_utility_long_get(const VOID *address) +{ + uint32_t data; + + LX_MEMCPY(&data, address, sizeof(data)); + return (ULONG)data; +} +#define LX_UTILITY_LONG_GET(address) _lx_utility_long_get((address)) #endif /* Define the mask for the hash index into the NAND sector mapping cache table. The sector mapping cache is divided diff --git a/common/src/lx_nand_flash_format_extended.c b/common/src/lx_nand_flash_format_extended.c index c8484f6..5e38b9d 100644 --- a/common/src/lx_nand_flash_format_extended.c +++ b/common/src/lx_nand_flash_format_extended.c @@ -1,7 +1,7 @@ /*************************************************************************** * Copyright (c) 2024 Microsoft Corporation - * Copyright (c) 2026-present Eclipse ThreadX contributors * Copyright (c) 2025 STMicroelectronics + * 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 @@ -10,6 +10,8 @@ * SPDX-License-Identifier: MIT **************************************************************************/ +// Portions of this file were generated with AI assistance. + /**************************************************************************/ /**************************************************************************/ @@ -118,7 +120,7 @@ UCHAR *page_buffer_ptr; } /* Check the spare data length. */ - if (nand_flash -> lx_nand_flash_spare_data1_length < sizeof(ULONG)) + if (nand_flash -> lx_nand_flash_spare_data1_length < sizeof(uint32_t)) { return(LX_ERROR); } diff --git a/common/src/lx_nand_flash_memory_initialize.c b/common/src/lx_nand_flash_memory_initialize.c index af8f444..b60a97a 100644 --- a/common/src/lx_nand_flash_memory_initialize.c +++ b/common/src/lx_nand_flash_memory_initialize.c @@ -75,6 +75,7 @@ UINT _lx_nand_flash_memory_initialize(LX_NAND_FLASH *nand_flash, ULONG* memory UINT memory_offset; UINT buffer_size; +UINT alignment_padding; /* Clear the memory buffer. */ @@ -224,6 +225,18 @@ UINT buffer_size; } #endif + /* Align the page buffer for drivers that access it as ULONG words. */ + alignment_padding = (UINT)(memory_offset % sizeof(ULONG)); + if (alignment_padding != 0u) + { + alignment_padding = (UINT)sizeof(ULONG) - alignment_padding; + } + if (alignment_padding > memory_size - memory_offset) + { + return(LX_NO_MEMORY); + } + memory_offset += alignment_padding; + /* Assign memory for page buffer. */ nand_flash -> lx_nand_flash_page_buffer = ((UCHAR*)memory_ptr) + memory_offset; diff --git a/common/src/lx_nand_flash_open_extended.c b/common/src/lx_nand_flash_open_extended.c index 282a21d..6f373aa 100644 --- a/common/src/lx_nand_flash_open_extended.c +++ b/common/src/lx_nand_flash_open_extended.c @@ -129,7 +129,7 @@ LX_INTERRUPT_SAVE_AREA } /* Check the spare data length. */ - if (nand_flash -> lx_nand_flash_spare_data1_length < sizeof(ULONG)) + if (nand_flash -> lx_nand_flash_spare_data1_length < sizeof(uint32_t)) { /* Return an error. */ diff --git a/test/cmake/regression/CMakeLists.txt b/test/cmake/regression/CMakeLists.txt index 10bf3d8..b04201d 100644 --- a/test/cmake/regression/CMakeLists.txt +++ b/test/cmake/regression/CMakeLists.txt @@ -20,6 +20,14 @@ foreach(test_case ${regression_test_cases} ${regression_test_cases_exfat}) add_test(${CMAKE_BUILD_TYPE}::${test_name} ${test_name}) endforeach() +add_executable(levelx_nand_alignment_test + ${SOURCE_DIR}/levelx_nand_alignment_test.c + ${CMAKE_CURRENT_LIST_DIR}/../../../common/src/lx_nand_flash_memory_initialize.c) +target_include_directories(levelx_nand_alignment_test PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/../../../common/inc) +target_compile_definitions(levelx_nand_alignment_test PRIVATE LX_STANDALONE_ENABLE) +add_test(${CMAKE_BUILD_TYPE}::levelx_nand_alignment_test levelx_nand_alignment_test) + add_executable(levelx_nor_reclaim_failure_test ${SOURCE_DIR}/levelx_nor_reclaim_failure_test.c) target_link_libraries(levelx_nor_reclaim_failure_test PRIVATE azrtos::levelx) diff --git a/test/regression/levelx_nand_alignment_test.c b/test/regression/levelx_nand_alignment_test.c new file mode 100644 index 0000000..2ed046e --- /dev/null +++ b/test/regression/levelx_nand_alignment_test.c @@ -0,0 +1,94 @@ +/*************************************************************************** + * 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. + * + * AI Disclosure: This file was largely AI-generated by Codex (GPT-6-Sol). + * The AI-generated portions may be considered public domain (CC0-1.0) + * and not subject to the project's licence. The human contributor has + * reviewed and verified that the code is correct. + * + * SPDX-License-Identifier: MIT and CC0-1.0 + **************************************************************************/ + +#include "lx_api.h" + +/* Verify unaligned metadata access and NAND workspace alignment. */ +int main(void) +{ +LX_NAND_FLASH nand_flash; +ULONG workspace[1024]; +UCHAR metadata[16]; +UINT status; +UINT index; +UINT page_offset; + + LX_MEMSET(metadata, 0xA5, sizeof(metadata)); + LX_UTILITY_SHORT_SET(&metadata[1], 0x1234u); + LX_UTILITY_LONG_SET(&metadata[5], 0x89ABCDEFu); + + if ((LX_UTILITY_SHORT_GET(&metadata[1]) != 0x1234u) || + (LX_UTILITY_LONG_GET(&metadata[5]) != 0x89ABCDEFu)) + { + return 1; + } + + for (index = 0; index < sizeof(metadata); index++) + { + if ((index != 1u) && (index != 2u) && + (index != 5u) && (index != 6u) && + (index != 7u) && (index != 8u) && + (metadata[index] != 0xA5u)) + { + return 2; + } + } + + LX_MEMSET(&nand_flash, 0, sizeof(nand_flash)); + nand_flash.lx_nand_flash_total_blocks = 127u; + nand_flash.lx_nand_flash_bytes_per_page = 512u; + nand_flash.lx_nand_flash_spare_total_length = 16u; + + status = _lx_nand_flash_memory_initialize(&nand_flash, workspace, 2848u); + if (status != LX_SUCCESS) + { + return 3; + } + + page_offset = (UINT)(nand_flash.lx_nand_flash_page_buffer - (UCHAR *)workspace); + if ((page_offset != 1792u) || + ((page_offset % sizeof(ULONG)) != 0u) || + (nand_flash.lx_nand_flash_page_buffer_size != 1056u)) + { + return 4; + } + + status = _lx_nand_flash_memory_initialize(&nand_flash, workspace, 1791u); + if (status != LX_NO_MEMORY) + { + return 5; + } + + status = _lx_nand_flash_memory_initialize(&nand_flash, workspace, 2847u); + if (status != LX_NO_MEMORY) + { + return 6; + } + + nand_flash.lx_nand_flash_total_blocks = 128u; + status = _lx_nand_flash_memory_initialize(&nand_flash, workspace, 2848u); + if (status != LX_SUCCESS) + { + return 7; + } + + page_offset = (UINT)(nand_flash.lx_nand_flash_page_buffer - (UCHAR *)workspace); + if ((page_offset != 1792u) || ((page_offset % sizeof(ULONG)) != 0u)) + { + return 8; + } + + return 0; +}