Using the RTEMS DOS File System

From RTEMSWiki
Jump to: navigation, search

Contents

RTEMS provides an MS-DOS compatible file system. Currently the implementation provides support FAT12, FAT16 and FAT32 disks and short file-names. Long file-name support is being added. Contact for ChrisJohns for details.

Configuration is based around the confdefs.h configuration file.

For details of the RTEMS File System see File Systems.

General Configuration

Your application needs a clock driver. The swap out task manages the block hold timers. You also need to use the IMFS as the base file system, configure the number of libio descriptors and indicate the application needs libblock:

/**
 * Configure drivers.
 */
#define CONFIGURE_MAXIMUM_DRIVERS                  10
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
/**
 * Configure file system and libblock.
 */
#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM
#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS   20
#define CONFIGURE_APPLICATION_NEEDS_LIBBLOCK

The block cache requires configuration. You can configure:

  • CONFIGURE_BDBUF_MAX_READ_AHEAD_BLOCKS
Number of blocks to read ahead of the block read. Default is 32.
  • CONFIGURE_BDBUF_MAX_WRITE_BLOCKS
Number of blocks to pass to the driver when writing to a device. Default is 16.
  • CONFIGURE_SWAPOUT_TASK_PRIORITY
Priority of the swap out task. Default is 15.
  • CONFIGURE_SWAPOUT_SWAP_PERIOD
The period of time in milli-seconds the swap out sleeps for. This is the period of time the block hold timers are updated. Default is 250 msecs.
  • CONFIGURE_SWAPOUT_BLOCK_HOLD
The period of time in milli-seconds a block is held after being modified for the first time before being written to disk. Further updates to the block do not reset the timer. Default time is 1000 msecs.

An example that can be used with a 4.5G IDE disk on a PC with 1G of memory to get great performance coping 250M of files:

#define CONFIGURE_SWAPOUT_TASK_PRIORITY            10
#define CONFIGURE_BDBUF_BUFFER_COUNT               1024
#define CONFIGURE_BDBUF_MAX_READ_AHEAD_BLOCKS      64
#define CONFIGURE_BDBUF_MAX_WRITE_BLOCKS           32

ATA Disk

The ATA driver is in libchip and requires a BSP driver. It is best to take an existing driver and modify it. You can locate the various drivers by searching the source tree for IDE_Controller_Table. There are drivers in :

c/src/lib/libbsp/arm/nds/block/block.c
c/src/lib/libbsp/i386/pc386/ide/idecfg.c
c/src/lib/libbsp/powerpc/gen5200/ide/idecfg.c
c/src/lib/libbsp/powerpc/mbx8xx/ide/idecfg.c
c/src/lib/libbsp/powerpc/mbx8xx/ide/pcmcia_ide.c

The confdefs.h configuration entry configures the IDE driver and the ATA driver:

#define CONFIGURE_APPLICATION_NEEDS_IDE_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_ATA_DRIVER
#define CONFIGURE_ATA_DRIVER_TASK_PRIORITY         9

Note, the examples given the ATA driver is a higher priority than the cache swap out task. This will make the ATA more responsive to the low levels. It does not have to be configured this way.

Some where in the initialization phase of your application you need to read the IDE disk partition table. You need to provide the path to the IDE block driver. The code is:

extern rtems_status_code rtems_ide_part_table_initialize (const char* );
 
rtems_status_code sc;

/*
 * Register the IDE Disk driver.
 */
printf ("Read IDE Disk Partition Table: ");
sc = rtems_ide_part_table_initialize ("/dev/ide0");
if (sc != RTEMS_SUCCESSFUL)
{
  printf ("error: ide partition table not found: %s\n",
          rtems_status_text (sc));
  return 1;
}

printf ("successful\n");

Once the partition table has been read you can mount partitions. The ATA code will create devices in the device tree for each MSDOS partition found. The first primary partition on a primary IDE disk is called /dev/hda1.

You can use the shell to mount the partition or you can code the mount call directly. Note, the shell can run scripts so you could embedded a simple initialization script that mounts the partition. The shell code to mount is in the function rtems_shell_libc_mounter and the shell command is:

mkdir c
mount -t msdos /dev/hda1 /c

The code to mount the same partition to an existing /c directory is:

#include <rtems/dosfs.h>
#include <rtems/fsmount.h>

rtems_filesystem_mount_table_entry_t* mt_entry;
 
if (mount (&mt_entry, &msdos_ops, options, "/dev/hda1", "/c") < 0)
{
  fprintf (stderr, "mount: mount failed: %s\n", strerror (errno));
  return 1;
}

RAM Disk

The RAM disk driver supports a single continuous memory region as a disk. There is no partitions. You can specify the location of the memory to use or the driver can allocate the memory from the heap. The memory is not initialised so you need to format the disk once you have created it.

The RAM disk has a 1:1 block mapping. Block 0 is the first block in the memory region. There is not checking on blocks so a block of memory that survives reset and even power loss such as static RAM cannot be checked for a valid disk image. You should considering using the NV Disk driver in this case.

To configure a RAM disk add this following to a source file in your application. The configuration items are:

  1. Block size. This is normally 512 for the MSDOS file-system
  2. Number of blocks in the disk drive. The memory size is the block size multiplied by the number of blocks
  3. The location. If NULL the heap is used.

An example is:

/**
 * The RAM Disk configuration.
 */
rtems_ramdisk_config rtems_ramdisk_configuration[] =
{
  {
    .block_size = 512,
    .block_num  = 4000,
    .location   = NULL
  }
};

/**
 * The number of RAM Disk configurations.
 */
size_t rtems_ramdisk_configuration_size = 1;

To use the RAM disk you need to register the driver. For example:

 rtems_driver_address_table rtems_flashdisk_io_ops = 
    RAMDISK_DRIVER_TABLE_ENTRY;
 
 rtems_device_major_number major;
 rtems_status_code         sc;
 
 /*
  * Register the RAM Disk driver.
  */
 printf ("Register RAM Disk Driver: ");
 sc = rtems_io_register_driver (RTEMS_DRIVER_AUTO_MAJOR,
                                &rtems_ramdisk_io_ops,
                                &major);
 if (sc != RTEMS_SUCCESSFUL)
 {
   printf ("error: ramdisk driver not initialised: %s\n",
           rtems_status_text (sc));
   return 1;
 }
 
 printf ("successful\n");

Once the driver has been register you can mount the disk using the shell command of:

mkdir rd
mount -t msdos /dev/ramdisk0 /rd

The code to mount the same device to an existing /rd directory is:

#include <rtems/dosfs.h>
#include <rtems/fsmount.h>

rtems_filesystem_mount_table_entry_t* mt_entry;
 
if (mount (&mt_entry, &msdos_ops, options, "/dev/ramdisk0", "/rd") < 0)
{
  fprintf (stderr, "mount: mount failed: %s\n", strerror (errno));
  return 1;
}

NV Disk

The Non-Volatile Disk driver supports more than one device per disk. A table of device descriptions describes the devices in a disk and you can have more than one NV disk active at once.

The NV Disk is suitable for devices that byte or word reprogrammable and retain data over a power loss or target reset. For example battery backed up static RAM or EEPROM type devices. The driver performs no wear levelling as the disk blocks are mapped 1:1 with the devices in the device description table. There is no remapping of blocks.

A device is describing using the rtems_nvdisk_device_desc structure. It is located in the <file>nvdisk.h</file> header file. The structure is:

/**
 * NV Device Descriptor holds the description of a device that is
 * part of the NV disk.
 *
 * Typically this structure is part of a table of the device which
 * is referenced in the nvdisk configuration table.
 * The reference is kept in the driver and used all the time to
 * manage the nv device, therefore it must always exist.
 */
typedef struct rtems_nvdisk_device_desc
{
  uint32_t                            flags;  /**< Private user flags. */
  uint32_t                            base;   /**< Base address of the device. */
  uint32_t                            size;   /**< Size of the device. */
  const rtems_nvdisk_driver_handlers* nv_ops; /**< Device handlers. */
} rtems_nvdisk_device_desc;

The fields are:

  1. The flags field provides a private set of flags a specific low level device handlers for a device may need.
  2. The base is the base address of the device. Its definition depends on the low level device handlers for a specific device.
  3. The size field defines the number of bytes of storage the device provides in bytes. This is the raw number of bytes available to the driver.
  4. The nv_ops is a set of handlers for the specific device.

The NV Disk device requires a set of handlers for each type of device. The handles can manage more than one device in a disk or disks. The handlers are:

int (*read) (uint32_t device, uint32_t flags, uint32_t base, uint32_t offset,
void* buffer, uint32_t size);
Read a block of data from the offset in the device with the base address to the provided buffer.
int (*write) (uint32_t device, uint32_t flags, uint32_t base, uint32_t offset,
const void* buffer, uint32_t size);
Write a block of data to the offset in the device with the base address from the provided buffer.
int (*verify) (uint32_t device, uint32_t flags, uint32_t base, uint32_t offset,
const void* buffer, uint32_t size);
Verify a block of data provided in buffer against to the data at the offset in the device with this base address.

The nvdisk-sram.h provides a set of handlers suitable for static RAM.

To configure a NV disk add this following to a source file in your application. The configuration items are:

  1. Block size. This is normally 512 for the MSDOS file-system.
  2. Number of device descriptions.
  3. Pointer to the device descriptions.
  4. Flags to control the driver.
  5. Debug information level if compiled into the driver.

The flags to control the driver are:

  1. RTEMS_NVDISK_CHECK_PAGES checks the pages during initialisation. This can slow down the initialisation of the disk. Pages not written too may have incorrect checksums.

An example set up with static RAM allocated from the heap is:

#include <rtems/nvdisk.h>
#include <rtems/nvdisk-sram.h>
/**
 * The NV Device descriptor. For this test it is just DRAM.
 */
rtems_nvdisk_device_desc rtems_nv_heap_device_descriptor[] =
{
  {
    .flags  =  0,
    .base   =  0,
    .size   =  2 * 1024 * 1024,
    .nv_ops = &rtems_nvdisk_sram_handlers
  }
};

/**
 * The NV Disk configuration.
 */
const rtems_nvdisk_config rtems_nvdisk_configuration[] =
{
  {
    .block_size    =    512,
    .device_count  =    1,
    .devices       =    &rtems_nv_heap_device_descriptor[0],
    .flags         =    0,
    .info_level    =    0
  }
};

To use the NV disk you need to register the driver. For example:

 /*
  * For our test we do not have any static RAM or EEPROM devices so
  * we allocate the memory from the heap.
  */
 rtems_nv_heap_device_descriptor[0].base =
   (uint32_t) malloc (rtems_nv_heap_device_descriptor[0].size);
 if (!rtems_nv_heap_device_descriptor[0].base)
 {
   printf ("error: no memory for NV disk\n");
   return 1;
 }
 
 /*
  * Register the NV Disk driver.
  */
 printf ("Register NV Disk Driver: ");
 sc = rtems_io_register_driver (RTEMS_DRIVER_AUTO_MAJOR,
                                &rtems_nvdisk_io_ops,
                                &major);
 if (sc != RTEMS_SUCCESSFUL)
 {
   printf ("error: nvdisk driver not initialised: %s\n",
           rtems_status_text (sc));
   return 1;
 }
 
 printf ("successful\n");

Once the driver has been register you can mount the disk using the shell command of:

mkdir nv
mount -t msdos /dev/nvdisk0 /nv

The code to mount the same device to an existing /nv directory is:

#include <rtems/dosfs.h>
#include <rtems/fsmount.h>
rtems_filesystem_mount_table_entry_t* mt_entry;

if (mount (&mt_entry, &msdos_ops, options, "/dev/nvdisk0", "/nv") < 0)
{
  fprintf (stderr, "mount: mount failed: %s\n", strerror (errno));
  return 1;
}

Flash Disk

Personal tools
Namespaces

Variants
Actions
Navigation
Gedare's Special Help
Toolbox