On Mon, Feb 6, 2017 at 6:15 AM, Vania Joloboff <
vania.j...@inria.fr> wrote:
> Is there an example of such things somewhere ?
> I have found nothing so far.
There are various examples, mostly on other architectures. However,
to show you just how platform dependent they are, I'll pick only a
handful of extremely divergent examples.
I start with the Commodore 128. Yes, a computer introduced in 1984
along-side the Commodore-Amiga 1000, had a very humble MMU of sorts
(the 8277 chip) that lay outside both of the computer's CPUs (Z-80 and
8502A). Both of these CPUs could access a maximum of 64KB of memory,
but the computer shipped with 128KB. With some clever hackery on the
part of the computer's owner, you could coax 256KB easily, and
sometimes up to 512KB if you're particularly desperate.
The MMU for this platform allowed the memory (as seen by the CPU
itself) to be split into several different regions, each of which
addressed different portions of physical address space, not entirely
dissimilar to paged MMUs do today. However, due to the unique
requirements of the 8502A CPU (a 6502 derivate), some special
accomodations had to be made to support zero-page, stack, and the
availability of ROM regardless of the current memory configuration.
That is to say, the MMU *guaranteed* (typically) 1KB of low memory and
1KB of high-memory referred to (so-called) "bank 0" memory, so that
software running in banks 1-3 can still invoke system calls.
(Sidebar: To the Commodore 128 software community, a "bank" is a 64KB
"page" of memory.)
Note that this counts as an example of PMP, because it's _external_ to
the CPUs themselves. You could easily pull the CPUs out and replace
them (and the system ROMs) with a RISC-V derivate and support
privilege modes and hardware-based page table walkers and the such,
and the 8277 MMU chip won't care if you're running in M-mode, S-mode,
or U-mode. If you map the top of physical memory to 16KB in your
local address space, then the top 1KB of that page will still refer to
bank 0, even if the other 3KB of the page are mapped to bank 1.
Another example comes from the Commodore-Amiga 1000 computer
(specifically). The computer shipped before system software ROMs
could be fabricated, so Commodore had to compromise to meet shipping
deadlines. A "256KB" RAM computer actually shipped with 512KB of RAM
total. Half of the RAM was mapped to where the ROMs *would* be once
they came out of the fabs. During cold-boot, the Amiga 1000 required
you to insert a "Kickstart" disk, which loaded the contents of high
RAM with an image of the Kickstart ROM. Once loaded, the Amiga
flipped a bit in GPIO which forced the WE# signal to that RAM to
remain negated (high). Even if you flipped the GPIO bit back, WE#
would remain high until the system was reset. In this way, RAM now
acted exactly like ROM.
Again, we're seeing circuitry which exists external to the CPU
intended to protect some invariant of physical memory from accidental
abuse by untrusted system software. (And since AmigaOS was a
single-address-space OS which could freely mix supervisor and
user-mode operation, effectively all software had to be treated as if
it were running in supervisor mode.) In this case, the PMP basically
consisted of a single D-flip-flop. It's a far cry simpler than the
8277 MMU in the C128, but it still counts!
> I don't really understand how the PMP, the PMA's
> and the XRW bits in the PTE's are connected.
RWX bits are used by the CPU to determine which pages your U-mode
software can access *before* the address is presented to the rest of
the memory subsystem.
(ASIDE: this may not actually be the case; some architectures
parallelize memory operations to a great extent. But, LOGICALLY, this
is the intent, and is a relevant abstraction for the topic.)
Once the CPU's MMU decides you have privileges to access a particular
page, it's translated to a "physical address". Let's call this a PA
so we make sure we're always talking about the same thing.
Post-translation, the CPU will attempt to reference memory using that
PA. Note that M-mode also works directly with PAs (no translation at
all!), so the question arises: if S-mode can map memory used by M-mode
(since they're both using PAs), how do you enforce complete isolation
between these two components?
Different PA ranges will have different aspects ascribed to them. As
an electrical engineer, I could decide PAs between $00000000 and
$003FFFFF refer to cached RAM. I could also say that memory from
$00800000-$00BFFFFF refers to the same memory but in an uncached
manner. Note that the system programmer doesn't get to make this
decision; this is an attribute of the physical hardware on which your
software is running. Typically, but not always, there are *no*
configuration registers that influences this design. Hence, "Physical
Memory Attribute" (PMA).
What determines whether or not I access a block of RAM in a cached
versus uncached way is a chunk of circuitry on the mainboard of the
computer. This circuitry is typically referred to as your "memory
controller." Since it's unlikely you'll ever want U-mode software to
reference memory in a way that bypasses caches, you can configure your
system software to use its page tables to prevent access to
$00800000-$00BFFFFF. So long as this is sufficient and you trust your
S-mode code implicitly, your memory controller can be oblivious and
get by just fine.
But, what happens when you no longer trust your software running in
S-mode? Consider most Linux and BSD installations allow developers
and users with root privileges to install kernel modules, post-boot
even. Can you continue to trust the system software under these
conditions? In a perfect world, the web of trust extends to those
with root privileges. However, in reality, root escalations seem
prominent enough that it's wise to not trust even root user to vet all
software that a system can run, particularly since she might not even
be *aware* of the software that's currently running.
Under these conditions, we need to export the most base security
requirements to the memory controller circuitry. We want to reduce
our trusted computing base to JUST the engineers responsible for the
system software (M-mode software) and the memory controller's design.
In this case, the memory controller needs to know just one piece of
additional information: is this memory access made on behalf of M-mode
or not? (Extra credit: not only check that M-mode is running, but
also check that the last fetched instruction came from a well-known
range of memory.) Given that one piece of information, the memory
controller itself is now capable of deciding whether or not to grant
uncached memory access to system software. If you're running in
M-mode, then access is granted unconditionally. Otherwise, the memory
controller might (conditionally, based on a configuration register
setting) issue a bus error, and prevent access. Like the Commodore
128's MMU above, this decision is made *external* to any and all CPUs,
and is intended to protect the memory from untrusted access. Hence,
the memory controller is now more than just a controller: it is now a
Physical Memory Protection unit.
Hope this helps clear the relationships and rationales up.
Fun fact: Commodore named the 8277 chip a "memory management unit"
because MMUs were all the rage during that time. It was a very
marketable name. Today, the 8277 would be called a PMP chip.
> I suppose the XWR bits in the PTE's are constructed by
> deducting information from the PMA's...
They're decided by supervisor software. This software is *trusted* to
have knowledge of PMAs, but is not guaranteed to do so. The PMP
exists to enforce the desired PMAs in complete isolation from the
trustworthiness of the system software.
--
Samuel A. Falvo II