eclipse-threadx / threadx

Eclipse ThreadX is an advanced real-time operating system (RTOS) designed specifically for deeply embedded applications.
https://github.com/eclipse-threadx/rtos-docs/blob/main/rtos-docs/threadx/index.md
MIT License
2.8k stars 767 forks source link

vfp_enable breaks FileX on Cortex-R5 #382

Open errikosmes opened 2 months ago

errikosmes commented 2 months ago

Description

Environment

To Reproduce

include "fx_api.h"

include "tx_api.h"

include "tx_zynqmp.h"

include "xparameters.h"

extern VOID _fx_ram_driver(FX_MEDIA *media_ptr); // Define RAM device driver entry.

define STACK_SIZE 10000

define KERNEL_BYTE_POOL_SIZE 20000

// Memory used for the thread stacks. ARM-R5 stacks need to be aligned 64-bit static uint8_t s_memoryPool[KERNEL_BYTE_POOL_SIZE] attribute((aligned(8)));

TX_BYTE_POOL g_kernelPool; static TX_THREAD s_thread;

void thread_entry(uint32_t thread_input);

void tx_application_define(void first_unused_memory) { char threadStackPointer; threadStackPointer = (char *)first_unused_memory; // Put first available memory address // into a character pointer. uint32_t txStatus;

// Create a memory pool for the thread stacks (kernel pool)
txStatus = tx_byte_pool_create(&g_kernelPool, (char *)"kernel pool", s_memoryPool,
                               KERNEL_BYTE_POOL_SIZE);
if (txStatus != TX_SUCCESS) printf("line=%d, error\r\n", __LINE__);

// Allocate a stack for the thread
txStatus =
    tx_byte_allocate(&g_kernelPool, (void **)&threadStackPointer, STACK_SIZE, TX_NO_WAIT);
if (txStatus != TX_SUCCESS) printf("line=%d, error\r\n", __LINE__);

txStatus = tx_thread_create(
    &s_thread,              // Pointer to a thread control block
    (char *)"Test thread",  // Pointer to the name of the thread
    thread_entry,           // Thread function pointer
    0,                      // 32-bit value passed to the thread
    threadStackPointer,     // Stack start
    STACK_SIZE,             // Stack size
    1,                      // Thread priority
    1,                 // Thread preemption threshold **NEEDS TO BE THE SAME AS thread priority
    TX_NO_TIME_SLICE,  // Number of ticks allowed to run before executing thread with the same
                       // priority lvl
    TX_AUTO_START);    // Start immediately or wait
if (txStatus != TX_SUCCESS) printf("line=%d, error\r\n", __LINE__);

// Initialize software modules and peripherals
fx_system_initialize();  // Init FileX filesystem

}

int main(void) { tx_zynqmp_gic_init(); // Initialize global interrupt controller tx_zynqmp_malloc_init(); // Use a mutex when calling malloc tx_kernel_enter(); // Enter the ThreadX kernel. }

define RAMDISK_SECTOR_SIZE 128

define RAMDISK_NB_SECTORS 256

FX_MEDIA g_RamDisk; ///< RAM disk handler static uint8_t s_ramDiskMem[RAMDISK_NB_SECTORS * RAMDISK_SECTOR_SIZE]; ///< RAM disk memory static uint8_t s_ramDiskCache[RAMDISK_SECTOR_SIZE]; ///< RAM disk cache

void thread_entry(uint32_t thread_input) { tx_thread_vfp_enable(); uint32_t fxStatus = FX_SUCCESS;

printf("Thread entry\r\n");

/*
 * Initialize RAM disk
 */
char *kermitRamDiskName = (char *)"RAM DISK";
fxStatus = fx_media_format(&g_RamDisk,              ///< RAM disk struct
                           _fx_ram_driver,          ///< RAM disk driver entry
                           s_ramDiskMem,            ///< RAM disk memory pointer
                           s_ramDiskCache,          ///< Media cache buffer pointer
                           sizeof(s_ramDiskCache),  ///< Media cache buffer size
                           kermitRamDiskName,       ///< Volume Name
                           1,                       ///< Number of FATs
                           32,                      ///< Directory Entries
                           0,                       ///< Hidden sectors
                           RAMDISK_NB_SECTORS,      ///< Total sectors
                           RAMDISK_SECTOR_SIZE,     ///< Sector size
                           1,                       ///< Sectors per cluster
                           1,                       ///< Heads
                           1);                      ///< Sectors per track
if (fxStatus != FX_SUCCESS) printf("line=%d, error=0x%lx\r\n", __LINE__, fxStatus);

fxStatus = fx_media_open(&g_RamDisk, kermitRamDiskName, _fx_ram_driver, s_ramDiskMem,
                         s_ramDiskCache, sizeof(s_ramDiskCache));
if (fxStatus != FX_SUCCESS) printf("line=%d, error=0x%lx\r\n", __LINE__, fxStatus);

const char *file_name = "test_file";

printf("vfp enabled\r\n");
fxStatus = fx_file_create(&g_RamDisk, (char *)file_name);
if (fxStatus == FX_SUCCESS) {
    printf("filex OK\r\n");
}
else {
    printf("filex error=0x%lx\r\n", fxStatus);
}

tx_thread_vfp_disable();
printf("vfp disabled\r\n");
fxStatus = fx_file_create(&g_RamDisk, (char *)file_name);
if (fxStatus == FX_SUCCESS) {
    printf("filex OK\r\n");
}
else {
    printf("filex error=0x%lx\r\n", fxStatus);
}

}



* Activating vfp makes FileX fail, deactivating it makes it work again... 

**Impact**
* This bug, especially when looking at the assembly code implementation with the 144 offset puts into question the vfp implementation in general.
* If it's the cause for FileX breaking what else could it break
* What if TX_THREAD + 144 happens to be 0 at one point and vfp handling gets deactivated resulting in float reg corruption. Really hard to debug if it happens 
austinawolf commented 1 month ago

This seems to verify my concern with the R5 port and the TX_THREAD struct.

On the cortex A9 port, TX_THREAD_EXTENSION_2 is defined to be ULONG tx_thread_vfp_enable; Link. This allocates a flag to store the vfp enable. See tx_api.h

On the cortex R5 port, TX_THREAD_EXTENSION_2 is defined to nothing. So TX_THREAD + 144 points to the next thing in the struct which is tx_thread_filex_ptr, see here

So it makes sense that vfp_enable is going to break FileX since it'll write over the tx_thread_filex_ptr value.

You can try to update the line here on the cortex R5 to match the A9 port like this: #define TX_THREAD_EXTENSION_2 ULONG tx_thread_vfp_enable;

This should allocate space for that flag in the TX_STRUCT but not sure if it's going to throw off any other offsets.