The high-level interface comprises a region and attributes to create a memory protection entry (MPE), a set of which constitute a memory protection domain (MPD). Three structures are visible at the API layer, although only regions should ever be directly accessed; MPEs and MPDs are only meant to be used as handles in userland.
/**
* A region of contiguous memory
*/
typedef struct
{
char *name;
void *base;
size_t bounds;
} rtems_memory_protection_region_descriptor;
typedef uint8_t rtems_memory_protection_permission;
/**
* A memory protection entry (MPE) is a region of contiguous memory
* (rtems_memory_protection_region_descriptor) with a set of permissions.
* If it is currently being enforced then the installed field is true.
*/
typedef struct
{
rtems_chain_node node;
rtems_memory_protection_region_descriptor region;
bool installed;
rtems_memory_protection_permission permissions;
} rtems_memory_protection_entry;
/**
* A memory protection domain comprises a chain of active MPEs and
* a freelist of idle MPEs. MPE storage is allocated from the Workspace
* and managed in the MPD.
*/
typedef struct
{
rtems_memory_protection_entry *mpe_array;
size_t mpe_array_size;
rtems_chain_control active_mpe_chain;
rtems_chain_control idle_mpe_chain; /* free list */
} rtems_memory_protection_domain;
Application developers can create regions, for example
rtems_memory_protection_region_descriptor text_region = {Where TEXT_BEGIN and TEXT_SIZE are specified somewhere. The advantage of using a name to identify a region is that eventually we could layer a filesystem over the MPD structure and open memory files with specified attributes, for example: int fd = open("/memory/text", O_RDWR);. I have not given thought to how best to create regions, but that interface should be orthogonal to the protection API.
.name = "text",
.base = TEXT_BEGIN,
.bounds = TEXT_SIZE
};
Regions must be encapsulated within MPEs and added to a MPD to have permissions enforced. The requisite functions are
/**So to enforce the text_region from above:
* Allocates an array of max_number_of_mpes
* memory protection entries from the workspace.
*/
rtems_status_code rtems_memory_protection_initialize_domain(
rtems_memory_protection_domain *domain,
size_t max_number_of_mpes
);
/**
* Create a new memory protection entry for the region with
* permissions in perms. This function adds the newly created mpe
* to the active chain of the_domain but does not install it.
*/
rtems_status_code rtems_memory_protection_create_entry(
rtems_memory_protection_domain* the_domain,
rtems_memory_protection_region_descriptor * const region,
const rtems_memory_protection_permission perms,
rtems_memory_protection_entry** mpe_ret
);
/**
* Install all mpes on the active list of the_domain.
*/
rtems_status_code rtems_memory_protection_install_domain(
rtems_memory_protection_domain* the_domain
);
rtems_memory_protection_domain *protection_domain;One aspect I'm not happy with is the permissions field, an 8-bit field with preprocessor macros defining masks. A better solution would improve usability. The remainder of the API layer are a handful of functions to manage MPEs (find mpe by address/MPD, delete mpe from mpd, set permission) and MPDs (uninstall all MPEs and finalize to free resources).
rtems_memory_protection_entry *mp_entry;
rtems_memory_protection_permission permission;
rtems_memory_protection_initialize_domain( protection_domain, 8 );
permission = RTEMS_MEMORY_PROTECTION_READ_PERMISSION |
RTEMS_MEMORY_PROTECTION_EXECUTE_PERMISSION;
rtems_memory_protection_create_entry(
protection_domain,
&text_region,
permission,
&mp_entry
);
rtems_memory_protection_install_domain(protection_domain);
Update: continued here
0 comments:
Post a Comment