FileX causes memory corruption on read with SF_EL_FX_BlockDriver triggered by USB-mass-storage-device

The SF_EL_FX_BlockDriver function doesn't respect the defined size of the media memory on read.
At first, the SSC has an issue showing a senseless warning when setting the memory size greater than 512 bytes (the sector size). But the definition of the buffer size of g_media_memory_g_fx_media0 will be made correct. May be that there are other settings affected by this issue.

But independent from the settings of the media-size the SF_EL_FX_BlockDriver-function reads the number of sectors requested by the USB-read-function.
Here is the end of the g_media_memory_g_fx_media0 to see. Direct subsequent lies the memory for the packet-pool of the network interface.

the end of the media-memory before the 8-sector-read-request

 

As long as the USB-driver wants to read only 1 or 2 sectors at a time the system works normally. But often the USB wants to read more sectors (8 in this case). Now the border of the media-memory is busted and 4096 Bytes (8 sectors) of disk-content were read flooding the packet-pool of the network-interface and brings it out of function because no new packet can be allocated and processed. From this point on USB continues working normally and network is dead.

the end of the media-memory after the 8-sector-read-request

 

the end of the 4096 bytes read by the driver (start of the media-memory + 0x1000)

 

Attached is an example to test this issue on an DK-S7G2 eval board.Connect network an both USB (J2 and J7) with your PC.
After flashing and starting the programm the IP got by DHCP is to see within a breakpoint in the variable "gtext". Type in browser "http://<the_IP>/usbon". Now you will hear the typical USB-sound on your PC and there will be a new drive. Format this drive and copy some files on it.
Restart the board (because network was dead already) and enter in browser "http://<the_IP>". Now you will see directory of the drive just formatted and be able to download the listed files. The USB-drive will not be visible on the PC till now.
If you now call "http://<the_IP>/usbon" again, the USB-drive will appear on the PC but you will not longer be able to access the network.

6330.FileX_issue.zip

  • At the moment I use a workaround by modifying the media-functions. But the size of the media-memory (1024 in this case) can't be retrieved by a function and must be entered by hand:

    UINT ux_device_msc_media_read0(VOID* storage,
                                   ULONG lun,
                                   UCHAR* data_pointer,
                                   ULONG number_blocks,
                                   ULONG lba,
                                   ULONG* media_status)
    {
       ULONG blocks_mem, blocks_left, blocks_offs, blocks_work;

        blocks_offs = 0;
        blocks_mem = 1024 / g_fx_media0.fx_media_bytes_per_sector; // number must be copied from declaration of g_media_memory_g_fx_media0 in common_data.c
        blocks_left = number_blocks;

        g_fx_media0.fx_media_driver_request = FX_DRIVER_READ;
        while(blocks_left)
        {
            blocks_work = (blocks_left <= blocks_mem)?blocks_left:blocks_mem;
            g_fx_media0.fx_media_driver_logical_sector = lba + blocks_offs;
            g_fx_media0.fx_media_driver_sectors = blocks_work;
            SF_EL_FX_BlockDriver(&g_fx_media0);
            memcpy(data_pointer + (blocks_offs * g_fx_media0.fx_media_bytes_per_sector), g_fx_media0.fx_media_driver_buffer, g_fx_media0.fx_media_bytes_per_sector * blocks_work);
            blocks_left -= blocks_work;
            blocks_offs += blocks_work;
        }
        return (UX_SUCCESS);
    }

    UINT ux_device_msc_media_write0(VOID* storage,
                                    ULONG lun,
                                    UCHAR* data_pointer,
                                    ULONG number_blocks,
                                    ULONG lba,
                                    ULONG* media_status)
    {
       ULONG blocks_mem, blocks_left, blocks_offs, blocks_work;

        blocks_offs = 0;
        blocks_mem = 1024 / g_fx_media0.fx_media_bytes_per_sector; // number must be copied from declaration of g_media_memory_g_fx_media0 in common_data.c
        blocks_left = number_blocks;

        g_fx_media0.fx_media_driver_request = FX_DRIVER_WRITE;
        while(blocks_left)
        {
            blocks_work = (blocks_left <= blocks_mem)?blocks_left:blocks_mem;
            g_fx_media0.fx_media_driver_logical_sector = lba + blocks_offs;
            g_fx_media0.fx_media_driver_sectors = blocks_work;
            memcpy(g_fx_media0.fx_media_driver_buffer, data_pointer + (blocks_offs * g_fx_media0.fx_media_bytes_per_sector), g_fx_media0.fx_media_bytes_per_sector * blocks_work);
            SF_EL_FX_BlockDriver(&g_fx_media0);
            blocks_left -= blocks_work;
            blocks_offs += blocks_work;
        }
        return (UX_SUCCESS);
    }

  • In reply to 4711:

    Hi 4711,

    The warning from configurator is obviously wrong. But I don't think this is a right usage of FileX. You cannot access the same FileX instance by both HTTP server and USB Device mass storage at the same time.

    Regards,
    adboc
  • In reply to adboc:

    Hi adboc,
    it is possible to use the FileX by HTTP-server and USB at the same time. I had to add a mutex for FileX in the HTTP-server and the USB-callbacks.
    But independent from the usage by the HTTP-server the USB-driver requests the SF_EL_FX_BlockDriver to read 8 sectors (4096 byte) from g_fx_media0 which has a media-buffer of only 1024 bytes for example. This floods the memory following the media-buffer. I don't know what the maximum of sectors is the USB-driver will request but the remarked 8 was enough to crash the system without this workaround.

    UINT ux_device_msc_media_read0(VOID* storage,
                                   ULONG lun,
                                   UCHAR* data_pointer,
                                   ULONG number_blocks,
                                   ULONG lba,
                                   ULONG* media_status)
    {
        ULONG blocks_mem, blocks_left, blocks_offs, blocks_work;

        blocks_offs = 0;
        blocks_mem = 1024 / g_fx_media0.fx_media_bytes_per_sector; // number must be copied from declaration of g_media_memory_g_fx_media0 in common_data.c
        blocks_left = number_blocks;

        tx_mutex_get (&g_fx_media0_mutex, TX_WAIT_FOREVER);
        g_fx_media0.fx_media_driver_request = FX_DRIVER_READ;
        while(blocks_left)
        {
            blocks_work = (blocks_left <= blocks_mem)?blocks_left:blocks_mem;
            g_fx_media0.fx_media_driver_logical_sector = lba + blocks_offs;
            g_fx_media0.fx_media_driver_sectors = blocks_work;
            SF_EL_FX_BlockDriver(&g_fx_media0);
            memcpy(data_pointer + (blocks_offs * g_fx_media0.fx_media_bytes_per_sector), g_fx_media0.fx_media_driver_buffer, g_fx_media0.fx_media_bytes_per_sector * blocks_work);
            blocks_left -= blocks_work;
            blocks_offs += blocks_work;
        }
        tx_mutex_put (&g_fx_media0_mutex);
        return (UX_SUCCESS);
    }

    UINT ux_device_msc_media_write0(VOID* storage,
                                    ULONG lun,
                                    UCHAR* data_pointer,
                                    ULONG number_blocks,
                                    ULONG lba,
                                    ULONG* media_status)
    {
        ULONG blocks_mem, blocks_left, blocks_offs, blocks_work;

        blocks_offs = 0;
        blocks_mem = 1024 / g_fx_media0.fx_media_bytes_per_sector; // number must be copied from declaration of g_media_memory_g_fx_media0 in common_data.c
        blocks_left = number_blocks;

        tx_mutex_get (&g_fx_media0_mutex, TX_WAIT_FOREVER);
        g_fx_media0.fx_media_driver_request = FX_DRIVER_WRITE;
        while(blocks_left)
        {
            blocks_work = (blocks_left <= blocks_mem)?blocks_left:blocks_mem;
            g_fx_media0.fx_media_driver_logical_sector = lba + blocks_offs;
            g_fx_media0.fx_media_driver_sectors = blocks_work;
            memcpy(g_fx_media0.fx_media_driver_buffer, data_pointer + (blocks_offs * g_fx_media0.fx_media_bytes_per_sector), g_fx_media0.fx_media_bytes_per_sector * blocks_work);
            SF_EL_FX_BlockDriver(&g_fx_media0);
            blocks_left -= blocks_work;
            blocks_offs += blocks_work;
        }
        tx_mutex_put (&g_fx_media0_mutex);
        return (UX_SUCCESS);
    }
  • In reply to 4711:

    I found a possibility to retrieve the media-buffer-size. So this workaround can be used without manually entering this value.

    UINT ux_device_msc_media_read0(VOID* storage,
                                   ULONG lun,
                                   UCHAR* data_pointer,
                                   ULONG number_blocks,
                                   ULONG lba,
                                   ULONG* media_status)
    {
        ULONG blocks_mem, blocks_left, blocks_offs, blocks_work;

        blocks_offs = 0;
        blocks_mem = g_fx_media0.fx_media_memory_size / g_fx_media0.fx_media_bytes_per_sector;
        blocks_left = number_blocks;

        tx_mutex_get (&g_fx_media0_mutex, TX_WAIT_FOREVER);
        g_fx_media0.fx_media_driver_request = FX_DRIVER_READ;
        while(blocks_left)
        {
            blocks_work = (blocks_left <= blocks_mem)?blocks_left:blocks_mem;
            g_fx_media0.fx_media_driver_logical_sector = lba + blocks_offs;
            g_fx_media0.fx_media_driver_sectors = blocks_work;
            SF_EL_FX_BlockDriver(&g_fx_media0);
            memcpy(data_pointer + (blocks_offs * g_fx_media0.fx_media_bytes_per_sector), g_fx_media0.fx_media_driver_buffer, g_fx_media0.fx_media_bytes_per_sector * blocks_work);
            blocks_left -= blocks_work;
            blocks_offs += blocks_work;
        }
        tx_mutex_put (&g_fx_media0_mutex);
        return (UX_SUCCESS);
    }

    UINT ux_device_msc_media_write0(VOID* storage,
                                    ULONG lun,
                                    UCHAR* data_pointer,
                                    ULONG number_blocks,
                                    ULONG lba,
                                    ULONG* media_status)
    {
        ULONG blocks_mem, blocks_left, blocks_offs, blocks_work;

        blocks_offs = 0;
        blocks_mem = g_fx_media0.fx_media_memory_size / g_fx_media0.fx_media_bytes_per_sector;
        blocks_left = number_blocks;

        tx_mutex_get (&g_fx_media0_mutex, TX_WAIT_FOREVER);
        g_fx_media0.fx_media_driver_request = FX_DRIVER_WRITE;
        while(blocks_left)
        {
            blocks_work = (blocks_left <= blocks_mem)?blocks_left:blocks_mem;
            g_fx_media0.fx_media_driver_logical_sector = lba + blocks_offs;
            g_fx_media0.fx_media_driver_sectors = blocks_work;
            memcpy(g_fx_media0.fx_media_driver_buffer, data_pointer + (blocks_offs * g_fx_media0.fx_media_bytes_per_sector), g_fx_media0.fx_media_bytes_per_sector * blocks_work);
            SF_EL_FX_BlockDriver(&g_fx_media0);
            blocks_left -= blocks_work;
            blocks_offs += blocks_work;
        }
        tx_mutex_put (&g_fx_media0_mutex);
        return (UX_SUCCESS);
    }
  • In reply to 4711:

    Hi 4711,

    I decided to re-create your scenario from scratch (HTTP Server on eMMC, USB MSD on eMMC) however I did not manage to reproduce issues you're seeing. I'm attaching project for DK-S7 and SSP 1.4.0 if you'd like to investigate: s7_dk_nx_ux_http_emmc_1_4_0.zip.

    Few comments:
    * It's essential that the FileX media instance is closed when your media (here: eMMC) is accessed by another host (in this case Windows PC). FX_MEDIA control block retains media state and also keeps track of cache entries. Same is likely to be done on PC end also, so you'll end up with two hosts with different cache blocks for the same sectors on the physical media.
    * Typical eMMC sector size is 512 bytes. Most hosts will only tolerate 512-byte blocks on mass storage device. FileX on Block Media specifies 512 bytes as default size for Working media memory so all of the defaults are perfectly fine for "eMMC on USB" scenario.
    * Small patch in ux_msc_callbacks.h was required as there's an issue in the configurator for USB mass storage device (prototypes for activate/deactivate callbacks are not generated).
    * FileX/sf_block_media_sdmmc can only be opened/closed from thread. As such, activate/deactivate callbacks post a semaphore and appropriate action is taken in the user thread.

    Regards

  • In reply to Renesas Karol:

    Hi Karol,

    thanks for your hints. I tried to test your example but got it not to work.

    • made a new Synergy-Project for S7G2-DK and SSP 1.4.0 in IAR
    • created the sources from SSC
    • closed IAR and SSC and copied your src, configuration.xml and S7G2-DK.pincfg to the project folder
    • reopened IAR and SSC
    • created the sources from SSC and made the #include-statement for ux_msc_callbacks.h in common_data.c
    • made "status" in ux_msc_read static to see the value in debugger
    • built the project and started the debugging

    -> g_sf_sdmmc.p_api->read says: SSP_ERR_TRANSFER_BUSY

    I've no idea what I made wrong.

  • In reply to 4711:

    Hello 4711,

    Please make sure that the only 3 switches enabled on the board are JTAG, ENET1 and MMC. Do you know how your eMMC is formatted? Formatting with Windows (any allocation unit) should be fine, although I'd recommend for "Working media memory" size to be increased when you want to work with bigger allocation units. You can find out current parameters by pausing your project after initialization and inspecting g_fx_media structure.

    Regards
  • In reply to Renesas Karol:

    Hi Karol,

    I switched all other DIP-switches off. The drive is formatted from previous tests with 512 bytes/sector, 65536 sectors and the media-buffer is 512 bytes too.

  • In reply to 4711:

    Hi Karol,

    I implemented your direct calls of the mmc-driver in my callback functions and they work faster and simpler than with my workaround.

    At the moment here are no further problems communicating via HTTP-server or USB. Thanks for your solution.

     

    UINT ux_device_msc_media_read0(VOID* storage,
                                   ULONG lun,
                                   UCHAR* data_pointer,
                                   ULONG number_blocks,
                                   ULONG lba,
                                   ULONG* media_status)
    {
        UINT status;

        tx_mutex_get (&g_mmc_media_mutex, TX_WAIT_FOREVER);
        status = g_sf_block_media_sdmmc0.p_api->read(g_sf_block_media_sdmmc0.p_ctrl, data_pointer, lba, number_blocks);
        tx_mutex_put (&g_mmc_media_mutex);

        return (status);
    }