Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 36 additions & 5 deletions common/inc/lx_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,13 @@ extern "C" {
#include "tx_api.h"
#endif

#include <stdint.h>


#ifdef LX_STANDALONE_ENABLE

/* Define compiler library include files. */

#include <stdint.h>
#include <stdlib.h>
#include <string.h>

Expand Down Expand Up @@ -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
Expand Down
6 changes: 4 additions & 2 deletions common/src/lx_nand_flash_format_extended.c
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -10,6 +10,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/

// Portions of this file were generated with AI assistance.


/**************************************************************************/
/**************************************************************************/
Expand Down Expand Up @@ -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);
}
Expand Down
13 changes: 13 additions & 0 deletions common/src/lx_nand_flash_memory_initialize.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down Expand Up @@ -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;

Expand Down
2 changes: 1 addition & 1 deletion common/src/lx_nand_flash_open_extended.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down
8 changes: 8 additions & 0 deletions test/cmake/regression/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
94 changes: 94 additions & 0 deletions test/regression/levelx_nand_alignment_test.c
Original file line number Diff line number Diff line change
@@ -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;
}