MMU HIDD
przypis
This document is currently only a draft and as such will most likely change
before it is accepted as an official specification. It might also be
deprecated if a better approach has been found in the mean time, and
doesn't necessarily correspond precisely with the current implementations.
The mmu.hidd will be the hardware interface for the Memory Management devices,
and should have the following characteristics:
- Memory is divided in memory pages, and access restrictions are handled on
a page-by-page basis. Page size should be adaptable to hardware used.
- Access to a page could be set for any specific task to be unreadable,
readable, or read/writeable.
- Tasks should be able to change these access restrictions on regions of
memory, both for themselves and for other tasks.
- It should be possible, e.g. for reasons of speed or because of hardware
limitation, to disable some (or all) parts of the memory management, or to
decide to only partially implement the mm specification. The mmu.hidd should
implement an interface that allows the OS to determine a level of supported
memory management, to allow the OS(es) to adapt.
- The mmu.hidd should be a low-level abstraction. It should not include the
higher level of specific mm-based services, but it should be abstraction of
the interfaces used for actual MMU implementations.
Optional features:
- Virtual Address Scheme: Virtual addresses can be different from real
addresses and the same real address can be mapped to different virtual
addresses for different tasks, and vice versa.
(Mapping addresses 1:n is a requirement for a real fork() or other OS
emulation layers but will probably not be used by AROS itself.)
- Virtual memory support: Gathering metrics to decide which page should be
swapped. The virtual memory scheme itself, swapping pages in and out,
are beyond the scope of the mmu.hidd because of the need for disk IO.
Therefore it should be implemented elsewhere in the OS.
- Security features: Through the use of the mmu.hidd the OS should be able
to limit the rights of tasks to change the access restrictions of pages
Thus the OS could stop malicious code from changing an unwriteable page
to a writeable one in order to hack the page's contents.
- Feature support: Providing support for the OS for special features of
specific MM implementations. E.g.: Supervisor context on the Amiga 68k
which provides fast switching between contexts without the need for
mmu cache flushes. Similar special features may exist in other
MM implementations (PowerPC, Alpha, Intel, HP, ...).
- Support for cache control on pages and DMA support and similar, if this
can be generalized. This will mostly be useful for other drivers.
To allow room for optimization, different levels of mmu implementation can be
implemented by the mmu.hidd programmer. The OS on top of the mmu.hidd
(normally AROS) should be flexible enough to adapt itself to the level
implemented by the mmu devices. Also, different implementations can be created
for the same hardware, to allow the system administrator to decide at boot
time on the type of system to run: A fast single-user system or a, slightly
slower, secure multi-user system.
This is like it was in the classic OS: A single address space without any
memory protection.
A basic hook can be installed, which may be called when a memory access error
occurs. This is an optional feature which, on hardware that can't support it,
need not be implemented, nor if the implementation would require memory pages,
as those aren't supported for level 0. Since it's optional, the OS should not
be based on the assumption that a memory access error results in a call to
such a hook.
At all times, the mmu.hidd has to know the amount of physical memory in the
system. Two mechanisms are provided to assure this:
- During (system) initialization a list of available memory is provided.
- HIDD methods should be implemented to allow the addition and removal of
certain memory. (Such methods would be useful for PCMCIA cards, or wouldn't
they?)
Also, every mmu implementation should implement and document an API to set
caching policies. Drivers which need those should then be able to use this.
(Ideally this API would be the domain of the abstract mmu.hidd, rather than
of each specific implementation, but caching protocols appear to vary so
widely that any abstraction would limit the actual implementations. This
machine-dependent API will, however, be used only by machine-dependent
drivers.)
Although the description mentioned tasks, in the implementation of the
mmu.hidd they are replaced by Memory Contexts. Memory contexts originate from
a proposal from Dave Haynie, and were used in the mmu.library by Thomas
Richter, for the classic AmigaOS. Tasks are defined at a higher level in the
OS and could also include metrics related to task switching and the like. The
relation between contexts and tasks is up to the OS. Different contexts could
be associated with a single task, or a single context could be shared between
several tasks.
The address space is divided into memory pages. At this level there is only
one address space and all addresses are physical addresses. All contexts thus
have the same address space. However, a page can have different access
restrictions in different contexts. A page can be either non-existent,
unmapped (it exists but is not currently in use), unreadable, readable,
or read-writeable. The mapped/unmapped flag is there to allow mmu.hidd page
allocations to coexist with the OS memory allocation. When the OS wants to
allocate a page it should select an unmapped page and mark it as mapped. A
convenience method 'ReservePages' could be provided, which maps the amount of
pages required and returns a list of those pages. Since these are physical
addresses, the pages returned in such a list should be adjacent, as that's
what the application requires.
By implementing this internally, it should be possible to minimize the
required number of page tables. When creating a new context the mmu.hidd could
itself Reserve Pages, for the context's page tables.
Hooks can be registered, to be called when a page's access restriction is
violated. When a hook is called it should first check whether it's applicable
to the reported violation. If it is, it should handle the exception and return
TRUE, otherwise, it should immediately return FALSE. This allows mmu.hidd to
keep a list of hooks and call each in turn until one of them handles the
exception.
When no (other) hook handles a certain exception the mmu.hidd will try to make
the program continue by skipping the offending instruction. Of course, OS
developers are urged to handle every exception generated (and AROS probably
will).
When the OS wants to change something on a context it should lock the context
first. Afterwards it should unlock the context again. This allows the mmu.hidd
to optimize determining the page tables, by only recomputing them when a
context is unlocked. (Though LockContext will keep processes from changing the
settings of the same context at the same time, it does not block usage of the
context in any way. You should be as quick as possible inside the lock, and
check that the order of your changes will not have unintended side-effects.)
Because no two LockContext()s can be executed simultaneously on the same
context, functions have to be provided so the OS can keep track of which
process has locked a context and a hook is called when a second lock is tried
on a context. This way a deadlock can be prevented by the OS by switching back
to the task which first locked the context.
Like the mmu.library on the classic AmigaOS, mmu.hidd could offer a way to
lock multiple contexts at once.
At this level an address need no longer be a physical address. Methods have to
be provided for the mmu.hidd to get the amount of real memory on the system,
and the segments it is divided in, and to map/unmap a real page in a certain
context or contexts. For hardware drivers and DMA the real address will be
needed, so methods to translate between virtual address and physical address
will also have to be provided.
This is basically the same as the previous level, but some additional flags
allow virtual memory support. One flag should indicate whether a page is
swapped to disk. Other flags should help the OS to decide which pages to swap
out, by indicating whether a page has been read or been written to. The former
can be used by the OS to decide which pages are accessed the least frequent
and are a candidate to be used when a new page needs to be swapped in; the
latter warns the OS that that page needs to be swapped out first before
swapping in the requested page. The interpretation and clearing of these flags
are part of the OS module that implements virtual memory.
An additional hook can be installed at this level which is called whenever
a program tries to access a swapped memory page. By this hook the OS should
perform everything needed to swap the page back in.
Maybe this level can be joined with the previous level, since an MMU that
allows for virtual addresses will probably implement virtual memory support
as well. On the other hand, maybe an AROS version on an FPGA may only want to
implement level 2 and not level 3. Comments wanted!
The features presented so far only implement protection against accessing
unprivileged pages. No measures were taken to protect against malicious code.
Code that tries on purpose to mess things up, is free to do so. To prevent
this some more hooks are needed. These are called whenever code tries to
change a context. So, if code wants to change access restrictions, create a
new context, switch contexts or something similar, the OS can intervene and
disallow the change, and maybe even kill the offending program. When the
kernel OS boots, it should create a context with the appropriate hooks, after
which everything can be secured.
This security support can be optionally implemented on those mmu.hidd levels
that implement contexts: Levels 1, 2, and 3. This means a mmu.hidd can
implement the following support:
- level 0
- level 1 without security
- level 1 with security
- level 2 without security
- level 2 with security
- level 3 without security
- level 3 with security
Of course, a certain level including security may be (somewhat) slower than
the same level without security.
|
|