How does memory protection work?
Usually, there is one entity that manages the whole memory. This entity assigns memory to processes and sets the basic access levels: read, write, execute. For performance reasons, the actual enforcement of these access rights is done in a dedicated hardware unit:
- Either a Memory Protection Unit (MPU)
- Or a more complex Memory Management Unit (MMU).
While read can be use alone for read-only data, common combinations are read/write for data memory and read/execute for program code. Having memory that can only be written but not be read is allowed but is not common (rare practical use cases).
Having memory with both write and execute rights at the same time is usually avoided as self-modifying program code is a very rare usage scenario and can easily be exploited by attackers.
Having executable code that is not readable is usually not supported. However, this can be an additional security feature, as it allows hiding the actual implementation details of an algorithm from the program using it.
Memory Protection Unit (MPU)
In low-end embedded systems such as Codasip L31, the MPU allows splitting up the physical memory up into regions, where processes are given individual access rights. Regions may even overlap to allow the setting up of hierarchical access models. This model is sufficient for static usage scenarios with a few well-known processes. Also, the complexity of the hardware implementation of an MPU is low, its size mainly depends on the number of regions supported. The additional time for the access right check on each memory access can be practically neglected.
Memory Management Unit (MMU)
In general-purpose systems, processes are not static and their behavior is not known in advance. Arbitrary processes get started, change their memory needs over the lifetime, and use different shared memory communication channels with other processes. The MPU region model is not flexible enough to cope with this. Also, the fact that there is just one address space shared by every process requires some form of general usage alignment.
Thus, in more complex systems, the concept of separate virtual address spaces for each process is used. To be able to use a part of a virtual address space, physical memory must be mapped into it and access rights get assigned to each mapping. Physical memory can be mapped into multiple virtual address space with different access right.
At hardware level, an MMU handles both the translation of virtual to physical addresses and the enforcement of access rights. Because of the translation process, an MMU is much more complex than an MPU, and the translation itself requires a certain amount of time.
Memory protection for DMA
In modern systems, the CPU is not the only entity that accesses memory. Using DMA, peripherals can also do it and read or write data without the CPU having control over this. This can bypass the memory protection enforced by the MPU or MMU. Thus, another memory protection unit becomes necessary, which is called IO-MMU, System-MMU, or IO-PMP. While often called “MMU”, the MPU concept is far more common, as there is almost no overhead for the access right check.
Memory protection in RISC-V
Physical Memory Protection (PMP) is an implementation of the MPU concept. It is usually available on all embedded and application cores. Application cores capable of running a general-purpose OS also contain an MMU. While the MMU is managed by the OS, it still is on top of PMP, so the OS can be blocked from accessing certain physical regions, for example the boot loader or firmware needed by peripherals.