Skip to content

xxx deleted2

Pavel A edited this page Apr 19, 2016 · 1 revision

*** will be rewritten, don't use as is

Memaccess module

(TC branch only; ver. 0.95)

This is a small "devmem library" to share among utilities in our package that do memory poking.

Currently it is just a .c file that builds with every program that uses it.

Useful library functions:

#include memaccess.h

  • int mem_init() -- Initialize the library.

    On success it returns 0.

    Note that almost all configuration is passed via environment variables (see below), so init() needs no parameters.

  • mem_mapping_hnd mem_create_mapping(mem_phys_address_t target, mem_mapping_size_t size, unsigned flags) -- Create a memory mapping of given address and size. The target can be a physical address or offset from preconfigured base (recommended for new code). If this fails, the function returns 0.

    Flags is bit mask of following:

     * MF_READONLY = 0x2 - mapping is read-only, otherwise read-write
     * MF_PHYSICAL = 0x4 - Without this flag set, `target` is offset from a pre-set base (which is the preferred mode). If set, `target` is a physical address (legacy mode).
     * MF_ABSOLUTE - the address is absolute physical address. This flag should be needed only for the 'devmem' utility.
    
  • char *mem_get_ptr(mem_mapping_hnd mapping, mem_phys_address_t start_addr, mem_mapping_size_t size) -- Get a pointer (virtual address) in the mapping, by address/offset and size. This gets a C pointer that you can use. The function returns NULL in case of error.

  • int mem_mapping_close(mem_mapping_hnd mapping) -- Close the mapping. This invalidates the mapping handle and all pointers returned by mem_get_ptr(). Not really necessary to call, this will be done automatically when the program exits.

  • int mem_finalize(void) -- Finalize the library. Not really necessary, cleanup will be done when the program exits.

Other functions

  • int mem_translate_address(mem_mapping_hnd mapping, mem_phys_address_t a_from, mem_phys_address_t *a_to) - Get the real, true physical address of a_from' into a_to`. The "real" address can differ from "logical" as result of configured remapping; see below. This function is useful only for debugging. It can be also used to determine whether the library uses physical memory mapping or something else. It can fail (return not 0) if the underlying implementation is not based on physical memory. This can be, for example, based on sysfs ore debugfs files so there may be no "real" physical address at all.

  • int mem_set_debug(int flags, FILE *output) - enable debug prints in the library. Use flags = 1, output file can be stdout or stderr or your own file. Enabling debug can be also done via environment parameter (below).

  • int mem_get_version() - get the library version

Configuration

The following environment variables should be set:

  • DEVMEMBASE - Base address of the physical memory block that the utilities should use (in C format, for example, "DEVMEMBASE=0xC0000000"

  • DEVMEMREBASE - "Old" base address, used by legacy code. Physical addresses that are greater than this value al less or equal to DEVMEMREBASEEND will be rebased to DEVMEMBASE. For example, if DEVMEMREBASE=0xD0000000 and DEVMEMBASE=0xC0000000, address 0xD0001234 will be changed to 0xC0001234. If mem_create_mapping is used in non-physical (offsets) mode, the offset will be added to the DEVMEMBASE value and DEVMEMREBASE will not be used.

  • DEVMEMREBASEEND - the last address of the rebased area (that begins at DEVMEMBASE).

  • DEVMEMOPT - Options string. Evaluation of the options occurs during mem_init() call.

    • -d enables debug output to stderr, if debug mode was not set already.
    • ..... TBD

NOTE: for our devmem utility (devmemx), DEVMEMBASE and other parameters can be not present, but this is special exception, intended to debug all other things.

Example 1: For new code

Assume DEVMEMBASE is set to 0xC0000000 as above, then the following example will access the data at 0xC0001000. The code, however, does not know the physical address, and does not need to.

// poky.c
#include <stdlib.h>
#include <stdio.h>
#include "memaccess.h"

#define MY_THING_OFFS 0x1000

typedef struct {
   int32_t junk1;
   int16_t junk2;
} my_thing;

int main()
{
   void * mapping;
   volatile my_thing *p;
   if ( 0 != mem_init() )
     return 1;
   mapping = mem_create_mapping( MY_THING_OFFS, sizeof(my_thing), 0 );
   if (!mapping)
     return 2;
   p = mem_get_ptr(mapping, MY_THING_OFFS, sizeof(my_thing));
   if (!p)
     return 3;
   printf("my var= %#x\n", p->junk1);
   
   // All clean-up happens automatically
   return 0;
}

Example 2: Porting legacy code

Assume the following example was written for base address 0xD0000000, but on actual platform the memory area is 0xC0000000 to 0xC00FFFFF. Set DEVMEMBASEto 0xC0000000, DEVMEMREBASE=0xD0000000 and DEVMEMREBASEEND=0xD00FFFFF. The code below will access the data at 0xC0001000.

// poky-legacy.c
#include <stdlib.h>
#include <stdio.h>
#include "memaccess.h"

#define MY_THING_ADDR 0xD0001000

typedef struct {
   int junk1;
} my_thing;

int main()
{
   void * mapping;
   volatile my_thing *p;
   if ( 0 != mem_init() )
     return 1;
   mapping = mem_create_mapping( MY_THING_ADDR, sizeof(my_thing), MF_PHYSICAL );
   /* using MF_PHYSICAL because the author believes that  MY_THING_ADDR is a physical address */
   if (!mapping)
     return 2;
   p = mem_get_ptr(mapping, MY_THING_ADDR, sizeof(my_thing));
   if (!p)
     return 3;
   printf("data at 0x%X = %d\n", MY_THING_ADDR, p->junk1);
   
   return 0;
}
Clone this wiki locally