Given the base-and-bound system, it might be appropriate
to use ranges rather than aligned regions for the
"standard" MPU. (It might be conceptually nicer to use
base-and-size. Such might map more naturally to a flexible
interface definition.) While ranges could use subregion
disable bits even when the range size is not evenly
divisible by the number of subregions supported, subregions
fit more naturally with aligned regions.
Some considerations for MPU specification include
supporting low-overhead permission updating, exploiting
the base hardware memory map, conflict resolution/priority
for entries, and flexibility in implementation cost and
granularity of protection.
For lower overhead in permission changing, supporting
setting/clearing of multiple valid bits could be useful.
(16 regions plus the system memory map might be enough
to support three tasks. Defining the bit mapping to
allow LUI to be used for this purpose seems somewhat
desirable.) I suspect in many cases, permission changes
involve complete revocation (and re-enabling) rather
than disabling (and re-enabling) one permission.
A base hardware memory map would not only provide
definitions of regions which could have natural
permission aspects and support dynamic specification
of attributes/permissions. It might also be natural
to define some MPU entries as subsets of regions in
the system map, reducing the tag bits required.
(While I can think of a few ways to reduce storage
overhead, they tend to introduce complexity, especially
in software. For example, having MPU entries with
different alignment support can reduce CAM sizes, but
makes allocation choices more complex. Similarly,
supporting split CAMs where the check bits are variably
shifted and two sets of attribute bits are provided would
extend the number of entries with less storage
(using high bits only or low/sign-extended bits only).)
With the separation of memory attributes and address
translation, it might be worth considering defining
MPUs in a way that fits with defining attributes
in a paged virtual memory environment.
My copy of the specification (1.9) specifies both base+bounds and
page-based memory management unit behaviors. The paging MMU provides
for security via R, W, and X bits on a page-by-page basis. A discrete
memory protection unit seems redundant.
> With the separation of memory attributes and address
> translation, it might be worth considering defining
> MPUs in a way that fits with defining attributes
> in a paged virtual memory environment.
Can you provide a concrete example of some benefits this would offer?
What would this look like at the assembly / CSR level?
As I see it, a process with a page table entry mapping to some
physical resource would suffice to offer that process access to said
resource. No other process (at least those lacking the same PTE
mapping) would have privilege to access the resource. The only
requirement is that resources be page-aligned.
I see a few benefits of separating MPU and MMU functionality, but
wonder if it will be worth the implementation costs:
- It'd make support for sub-page privilege management easier. You can
effectively restrict access down to the smallest possible segment
size. E.g., for x86 machines, that'd be a single byte. We could
probably get by with 8 or 16 bytes. This would be particularly useful
in microkernel environments where user-space drivers are expected to
manage only their own I/O registers. It's also useful for message
passing, particularly in a single-address-space OS. Speaking of
which...
- It'd make support for single-address-space operating systems
significantly easier and safer; maybe even preferable to
multi-address-space OSes. So, e.g., something like AmigaOS could
conceptually be ported to RISC-V to use this facility and attain the
reliability of Unix. (Fun fact: Commodore Business Machines was
working on a 68020-compatible MMU designed just for the Amiga's
single-address-space runtime before they went belly-up.)
- It'd eliminate the need for OSes to loop through a page table
hierarchy to update RWX bits, so some calls to mmap() would be faster.
It *could* (in some circumstances at least) eliminate the need to
emulate segmentation mapping inside the kernel (e.g., Plan 9's
"segattach" system call and supporting data structures).
- It'd make object-capability OSes easier to implement, since segments
and object capabilities share a lot of features.
- Just a speculation on my part, but it seems that if actual
segmentation is used (e.g., not just protection, but relocation as
well), it could make supporting 64-bit virtual address spaces (as
distinct from 39- or 48-bit) significantly simpler to deal with.
MULTICS-style paging seems to be the way to go here. But, this is pie
in the sky stuff.
There are real disadvantages too:
- your application would need to have user-level read/write access to
the protection registers if you need access to more than 16 (or
whatever your hardware supports) segments, or you risk segment
thrashing. This could easily happen in an I/O bound server, where
zero-copy network drivers need access to a plurality of client process
buffers to best schedule network link utilization. Yet, this
contradicts the requirements you'd need to support object
capabilities.
- it adds an extra layer of circuitry to the critical path to memory.
--
Samuel A. Falvo II