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 = { .name = "text", .base = TEXT_BEGIN, .bounds = TEXT_SIZE };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.
Regions must be encapsulated within MPEs and added to a MPD to have permissions enforced. The requisite functions are
/** * 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 );So to enforce the text_region from above:
rtems_memory_protection_domain *protection_domain; 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);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).
Update: continued here
No comments:
Post a Comment