Skip to content

value set/get on non-aligned address #55

Open

Description

@jie-ss

it's not 100% bug but got me stucked two days...

there are such macro definitions in lx_api.h:
...
#define LX_UTILITY_SHORT_SET(address, value) ((USHORT)(address)) = (USHORT)(value)
#define LX_UTILITY_LONG_SET(address, value) ((ULONG)(address)) = (ULONG)(value)
#define LX_UTILITY_SHORT_GET(address) (((USHORT)(address)))
#define LX_UTILITY_LONG_GET(address) (((ULONG)(address)))

in case address is not 4 bytes aligned on LONG_GET/SET, neither 2 bytes aligned on SHORT_GET/SET, you will get wrong value on many platforms such as the ARM platform.

for the universality, we should use SET/GET just as what fx_utility***_read/write did to replace these macros.

btw:

  1. although there are '16' in _fx_utility_16_unsigned_write/read, it's confused that UINT type but not USHORT parameters are used.

  2. the default nand defition is 128MB in lx_nand_flash_simulator.c, however, it's a simulated nand based on RAM, and I guess most systems running LX has less than 128MB RAM, so it's not a friendly settings to the newbies.

Activity

  1. fdesbiens commented on Apr 15, 2025

    @fdesbiens
    Contributor

    Hi @jie-ss. Thank you for raising this issue. We will discuss it during our weekly meeting later today.

    @eclipse-threadx/iot-threadx-committers and @eclipse-threadx/iot-threadx-contributors: Please provide feedback.

  2. added
    discussionFlagged for discussion during the weekly team meeting
    on Apr 15, 2025
  3. moved this to Discussion in ThreadX Roadmapon Nov 25, 2025
  4. cpdpls commented on Apr 16, 2026

    @cpdpls

    Hey @fdesbiens, I was about to open a an issue similar to this but for the RISC-V64 architecture. While OP gets wrong values, on the RISCV, you end up in the trap handler until the board is rebooted, so no recovery in that case. As this issue is still ongoing, I would like to clarify our case.

    Looking at the _lx_nand_flash_memory_initialize function, we can see that the variable memory_offset is correctly aligned from the very start as long as lx_nand_flash_bytes_per_page is a common page size as described in the rtos-docs

    UINT _lx_nand_flash_memory_initialize(LX_NAND_FLASH *nand_flash, ULONG* memory_ptr, UINT memory_size)
    {
    UINT memory_offset;
    UINT buffer_size;
    /* Clear the memory buffer. */
    LX_MEMSET(memory_ptr, 0, memory_size);
    /* Reset the memory offset. */
    memory_offset = 0;
    /* Set memory size for block mapping table. */
    buffer_size = nand_flash -> lx_nand_flash_total_blocks * sizeof(*nand_flash -> lx_nand_flash_block_mapping_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 mapping table. */
    nand_flash -> lx_nand_flash_block_mapping_table = (USHORT*)(((UCHAR*)memory_ptr) + memory_offset);
    /* Update block mapping table size. */
    nand_flash -> lx_nand_flash_block_mapping_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);
    }

    The real issue happens right after were memory_offset becomes unaligned.

    memory_offset += nand_flash -> lx_nand_flash_total_blocks * sizeof(*nand_flash -> lx_nand_flash_block_list);

    The sizeof always returns 2 and nand_flash -> lx_nand_flash_total_blocks can have any value based on the size of the partition we give to levelx. In our case it was 127. Then later, the actual lx_nand_flash_page_buffer pointer will have an unaligned address
    nand_flash -> lx_nand_flash_page_buffer = ((UCHAR*)memory_ptr) + memory_offset;

    This causes issue because this pointer is used later as an ULONG which causes a trap as I talked about. More specifically here
    page_buffer_ptr = nand_flash -> lx_nand_flash_page_buffer;
    spare_buffer_ptr = page_buffer_ptr + nand_flash -> lx_nand_flash_bytes_per_page;

    page_type = LX_UTILITY_LONG_GET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset]);

    The current workaround for use as of now is to make sure the lx_nand_flash_bytes_per_page variable is a multiple of 4 in order to get a correctly aligned lx_nand_flash_page_buffer

  5. added a commit that references this issue on Sep 28, 2026
    a2b59d7
  6. fdesbiens commented on Sep 28, 2026

    @fdesbiens
    Contributor

    Hi @jie-ss and @cpdpls. I’m sorry this took so long. I confirmed both alignment faults: the metadata macros access byte buffers through potentially misaligned word pointers, and a 127-block layout can misalign the NAND page buffer. I opened PR #96 to make metadata access safe for unaligned addresses and align the page buffer. The focused regression passed on 32-bit and 64-bit GCC 14 builds; I have not run it on RISC-V64 hardware. I’ll keep this issue open until the PR merges.

    On the side questions, FileX’s _fx_utility_16_unsigned_read/write use UINT for the value but access exactly two bytes. The NAND simulator’s default geometry reserves 128 MiB for page data plus spare and bookkeeping storage; lowering TOTAL_BLOCKS reduces that test allocation. A configurable simulator size could be considered separately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdiscussionFlagged for discussion during the weekly team meeting

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions