device_identification direct_memory_flush
API Reference Manual  /  5 Model-to-Simulator Interfaces  / 

direct_memory

Description

The direct_memory interface is implemented by objects that model memory, such as RAM and ROM objects. These are called direct-memory objects. A user of the interface is called a memory user and is typically a processor that wants to do fast accesses to memory. The direct-memory object corresponding to a particular physical address can be obtained using the lookup method of the direct_memory_lookup interface. See the documentation for the direct_memory_lookup interface for more information.

A memory user using the direct_memory interface must implement the direct_memory_update interface.

The get_handle method is used by a memory user to create or retrieve a handle to the memory region starting at offset offs with size size. The handle is typically used later on to request access permissions and to retrieve a direct pointer to the region. The handle returned by get_handle is private to the memory user specified in the requester parameter.

If get_handle is invoked multiple times for the same range, and with identical requester and subsystem arguments, then the same handle will be returned each time, assuming the original handle is still valid. Note that the original handle is only returned if the range matches exactly. A single memory user can obtain multiple distinct handles for the same memory range by using different values for the subsystem parameter.

For RAM and ROM, offs and size must specify a region which does not intersect a naturally aligned 8192 byte boundary, or the request will fail with a NULL return value. Other direct-memory objects might have different requirements.

The request method is used to request a host pointer to simulated memory. This pointer can be used to carry out fast memory operations without having to involve the Simics API. The handle argument is the handle obtained using get_handle.

Both the permission argument and the inhibit argument are access_t type bit fields. The permission argument is used to specify what kind of memory operations the memory user will perform. For example, if a memory user wants to read memory, the permission argument must include the Sim_Access_Read value. The inhibit argument specifies what other memory users are not allowed to do. For example, if inhibit is set to Sim_Access_Write other memory users are not allowed to write to the memory range. This protection mechanism can be used to create caches of simulated memory, request exclusive permissions to a memory range in order to carry out atomic operations, and similar. When a memory user is requesting permission to a memory range that another memory user has protected with conflicting inhibit bits, the direct-memory object will inform the other memory user of the lost permissions and protection through the direct_memory_update interface. A user can lose both the permission and protection for a memory range in this way. When this happens, a memory user may re-request permissions and inhibit protection.

Note: if a memory user has multiple handles which overlaps, then each handle is considered to be a distinct memory user. For example, if a memory user holds two handles, and requests write inhibit on one of them, then write permission will be revoked from the second handle (if such permission had been granted).

The request method returns a direct_memory_t value with information about the retrieved permissions and inhibit bits. These bits can be a super set of the bits that actually were requested. The returned data pointer can be used to access the memory range. Accesses are valid from the data pointer and up to the end of the range, i.e., addresses up to data pointer + size - 1, where size is the size valid for the handle. A call to request always succeeds and the corresponding memory range is valid until the permissions or the handle are revoked by the direct_memory_update interface. Note that the data pointer may change each time request is called (with the same handle) since Simics may move simulated memory. If the pointer changes, then the old pointer must not be used.

With set_user_data, a memory user can associate a user-defined pointer with a specific handle. The pointer can be retrieved using the get_user_data method, which takes a handle as an argument.

A memory user can use the release function to notify the direct-memory object when it is no longer interested in the memory region corresponding to handle. The handle is invalid and must not be used for anything after being released.

The ack method is used by a memory user to inform the direct-memory object that it has given up the corresponding permission and inhibit rights for a memory range when called by a method in the direct_memory_update interface.

Permissions can be revoked from all memory users by invoking the revoke method. The permission parameter specifies the permissions which will be revoked from all memory users. Similarly, inhibit specifies the inhibit privileges which will be revoked. For instance, calling revoke with permission set to Sim_Access_Write will ensure that nobody has write permissions to the direct-memory object.

typedef granted_mem_t *direct_memory_handle_t;

typedef struct {
#ifndef PYWRAP
        uint8                 *data;
#endif
        access_t               permission;
        access_t               inhibit;
} direct_memory_t;

typedef uint64 direct_memory_ack_id_t;

SIM_INTERFACE(direct_memory) {
        direct_memory_handle_t (*get_handle)(conf_object_t *NOTNULL obj,
                                             conf_object_t *NOTNULL requester,
                                             uint64 subsystem,
                                             uint64 offs,
                                             unsigned size);
        direct_memory_t (*request)(conf_object_t *NOTNULL obj,
                                   direct_memory_handle_t handle,
                                   access_t permission,
                                   access_t inhibit);
        void (*revoke)(conf_object_t *NOTNULL obj,
                       access_t access,
                       access_t permission,
                       access_t inhibit);
#ifndef PYWRAP
        void *(*get_user_data)(conf_object_t *NOTNULL obj,
                                    direct_memory_handle_t handle);
        void (*set_user_data)(conf_object_t *NOTNULL obj,
                              direct_memory_handle_t handle,
                              void *user_data);
#endif
        void (*release)(conf_object_t *NOTNULL obj,
                        direct_memory_handle_t handle);
        void (*ack)(conf_object_t *NOTNULL obj,
                    direct_memory_ack_id_t id);
};

#define DIRECT_MEMORY_INTERFACE "direct_memory"

Execution Context
Cell Context for all methods.

device_identification direct_memory_flush