Typed memory

Updated: April 19, 2023

POSIX typed memory provides an interface that lets you open named memory objects and perform mapping operations on them.

Typed memory is useful in providing an abstraction between BSP- or board-specific address layouts and device drivers or user code. You can reserve memory in advance for specific purposes, such as graphics, and remove that memory from the system RAM that programs typically allocate from.

POSIX specifies that typed memory pools (or objects) are created and defined in an implementation-specific fashion. Under QNX Neutrino, typed memory objects are defined from the memory regions specified in the asinfo section of the system page. Thus, typed memory objects map directly to the address space hierarchy (asinfo segments) defined by startup. The typed memory objects also inherit the properties defined in asinfo, namely the physical address (or bounds) of the memory segments.

In general, the naming and properties of the asinfo entries are arbitrary and completely under the user's control. There are, however, some mandatory entries:

memory
Physical addressability of the processor, which depends on the architecture.
ram
All of the RAM on the system. This may consist of multiple entries.
sysram
System RAM, which is memory that has been given to the OS to manage. This may also consist of multiple entries. The OS uses this pool for all general-purpose memory allocations on the system, including code, data, stack, heap, kernel and process manager data, shared memory objects, and memory-mapped files.

You can create additional entries, but only in startup, using the as_add() function (see the Startup Library chapter of Building Embedded Systems).

Note: Typed memory objects can be either inside or outside SYSRAM. Objects that are inside SYSRAM are used to restrict normal allocations to a subset of the normal pool, while those outside SYSRAM are used to carve regions that aren't available for general-purpose allocation.

The names of typed memory regions are derived directly from the names of the asinfo segments. The asinfo section itself describes a hierarchy, and so the naming of typed memory objects is a hierarchy. Their names may contain intermediate slash (/) characters that are considered as path-component separators.

Let's look at a sample asinfo configuration, which you can display with the pidin syspage=asinfo command:

Header size=0x00000108, Total Size=0x00000cd0, #Cpu=2, Type=256
Section:asinfo offset:0x00000710 size:0x00000340 elsize:0x00000020
  0000) 0000000000000000-000000000000ffff o:ffff a:0000 p:100 c:0 n:/io
  0020) 0000000000000000-000fffffffffffff o:ffff a:0010 p:100 c:0 n:/memory
  0040) 0000000000000000-00000000ffffffff o:0020 a:0010 p:100 c:0 n:/memory/below4G
  0060) 0000000000000000-0000000000ffffff o:0020 a:0010 p:100 c:0 n:/memory/isa
  0080) 0000000006000000-00000000ffefffff o:0020 a:0013 p:100 c:0 n:/memory/device
  00a0) 00000000fff00000-00000000ffffffff o:0020 a:0005 p:100 c:0 n:/memory/rom
  00c0) 0000000000000000-000000000009f7ff o:0060 a:0017 p:100 c:0 n:/memory/isa/ram
  00e0) 0000000000100000-0000000000ffffff o:0060 a:0037 p:100 c:0 n:/memory/isa/ram
  0100) 0000000001000000-0000000005ffffff o:0040 a:0037 p:100 c:0 n:/memory/below4G/ram
  0120) 0000000006000000-000000003fedffff o:0080 a:0017 p:100 c:0 n:/memory/device/ram
  0140) 000000003ff00000-000000003fffffff o:0080 a:0017 p:100 c:0 n:/memory/device/ram
  0160) 00000000000f6a00-00000000000f6a23 o:0020 a:0007 p:100 c:0 n:/memory/acpi_rsdp
  0180) 00000000fee00000-00000000fee003ef o:0020 a:0003 p:100 c:0 n:/memory/lapic
  01a0) 000000000142c038-0000000001c9bb7b o:0020 a:0005 p:100 c:0 n:/memory/imagefs
  01c0) 0000000001400f30-000000000142c037 o:0020 a:0007 p:100 c:0 n:/memory/startup
  01e0) 000000000142c038-0000000001c9bb7b o:0020 a:0007 p:100 c:0 n:/memory/bootram
  0200) 0000000000000000-00000000ffffffff o:ffff a:0010 p:100 c:0 n:/virtual
  0220) ffff800000001000-ffff8000000f25d0 o:0200 a:0000 p:100 c:0 n:/virtual/vboot
  0240) 0000000000001000-000000000009efff o:00c0 a:0007 p:100 c:0 n:/memory/isa/ram/sysram
  0260) 0000000000106000-0000000000108fff o:00e0 a:0007 p:100 c:0 n:/memory/isa/ram/sysram
  0280) 000000000010f000-00000000004f6fff o:00e0 a:0007 p:100 c:0 n:/memory/isa/ram/sysram
  02a0) 00000000004f8000-0000000000ffffff o:00e0 a:0027 p:100 c:0 n:/memory/isa/ram/sysram
  02c0) 0000000001000000-000000000142bfff o:0100 a:0007 p:100 c:0 n:/memory/below4G/ram/sysram
  02e0) 0000000001c9c000-0000000005ffffff o:0100 a:0027 p:100 c:0 n:/memory/below4G/ram/sysram
  0300) 0000000006000000-000000003f2d4fff o:0120 a:0007 p:100 c:0 n:/memory/device/ram/sysram
  0320) 000000003ff00000-000000003fffffff o:0140 a:0007 p:100 c:0 n:/memory/device/ram/sysram

For details about the above information, see the section on asinfo in the “System Page” chapter of Building Embedded Systems.

You use posix_typed_mem_open() to open a typed memory object, specifying the name of the object, the access mode, and flags that indicate how the object behaves when it's mapped. The name you pass to this function follows the above naming convention. If the name starts with a leading slash (/), an exact match is done. POSIX allows an implementation to define what happens when the name doesn't start with a leading slash; in QNX Neutrino, a tail match is done on the pathname components specified.

You can also use ampersands and vertical bars (& and |) between segments to specify intersections and unions, respectively. You can specify an arbitrary number of them; they're evaluated from left to right, but parentheses aren't supported.

Here are some examples of how posix_typed_mem_open() resolves names, using the above sample configuration:

This name: Resolves to:
/memory /memory
isa Fails because isa isn't a leaf in the hierarchy
/memory/rom /memory/rom
/sysram Fails because sysram isn't at the top of the hierarchy
sysram All sysram segments, including four occurrences of /memory/isa/ram/sysram, two occurrences of /memory/device/below4G/sysram, and two occurrences of /memory/device/ram/sysram
below4G&sysram The intersection of all physical address ranges for below4G with all physical address ranges for sysram.

For example, if you have two memory regions, one being /ram/below4G with addresses from 0 to 4 GB, and the other being /ram/sysram with addresses from 1 GB to 6 GB, then below4G&sysram gives pages in the range 1 GB to 4 GB.

Specifying a union or intersection can be more useful than specifying a full name.

As an extension to POSIX, the typed memory name hierarchy is exported through the process manager namespace under /dev/tymem. Applications can list this hierarchy and look at the asinfo entries in the system page to get information about the typed memory.

Note: You can't open typed memory through the namespace interface (as you can for shared memory objects), because posix_typed_mem_open() requires an additional tflag argument, which you can't provide when you call open().

If successful, posix_typed_mem_open() returns a file descriptor for the typed memory object. What you do with the file descriptor depends on which approach you want to take:

Memory that's mapped from a typed-memory file descriptor is implicitly locked.

POSIX also defines posix_typed_mem_get_info(), which you can use to get information about a typed memory object. For more information about working with typed memory, see Typed memory in the “Working with Memory” chapter of the QNX Neutrino Programmer's Guide.