Introduction
============

8x50 chipset requires the ability to disable HW domain manager function.

The ARM MMU architecture has a feature known as domain manager mode.
Briefly each page table, section, or supersection is assigned a domain.
Each domain can be globally configured to NoAccess, Client, or Manager
mode.  These global configurations allow the access permissions of the
entire domain to be changed simultaneously.

The domain manger emulation is required to fix a HW problem on the 8x50
chipset.  The problem is simple to repair except when domain manager mode
is enabled.  The emulation allows the problem to be completely resolved.


Hardware description
====================

When domain manager mode is enabled on a specific domain, the MMU
hardware ignores the access permission bits and the execute never bit.  All
accesses, to memory in the domain, are granted full read, write,
execute permissions.

The mode of each domain is controlled by a field in the cp15 dacr register.
Each domain can be globally configured to NoAccess, Client, or Manager mode.

See: ARMv7 Architecture Reference Manual


Software description
====================

In order to disable domain manager mode the equivalent HW functionality must
be emulated in SW.  Any attempts to enable domain manager mode, must be
intercepted.

Because domain manager mode is not enabled, permissions for the
associated domain will remain restricted.  Permission faults will be generated.
The permission faults will be intercepted.  The faulted pages/sections will
be modified to grant full access and execute permissions.

The modified page tables must be restored when exiting domain manager mode.


Design
======

Design Goals:

Disable Domain Manager Mode
Exact SW emulation of Domain Manager Mode
Minimal Kernel changes
Minimal Security Risk

Design Decisions:

Detect kernel page table modifications on restore
Direct ARMv7 HW MMU table manipulation
Restore emulation modified MMU entries on context switch
No need to restore MMU entries for MMU entry copy operations
Invalidate TLB entries on modification
Store Domain Manager bits in memory
8 entry MMU entry cache
Use spin_lock_irqsave to protect domain manipulation
Assume no split MMU table

Design Discussion:

Detect kernel page table modifications on restore -
When restoring original page/section permission faults, the submitted design
verifies the MMU entry has not been modified.  The kernel modifies MMU
entries for the following purposes : create a memory mapping, release a
memory mapping, add permissions during a permission fault, and map a page
during a translation fault.  The submitted design works with the listed
scenarios.  The translation fault and permission faults simply do not happen on
relevant entries (valid entries with full access permissions).  The alternative
would be to hook every MMU table modification.  The alternative greatly
increases complexity and code maintenance issues.

Direct ARMv7 HW MMU table manipulation -
The natural choice would be to use the kernel provided mechanism to manipulate
MMU page table entries.  The ARM MMU interface is described in pgtable.h.
This interface is complicated by the Linux implementation.  The level 1 pgd
entries are treated and manipulated as entry pairs.  The level 2 entries are
shadowed and cloned.  The compromise was chosen to actually use the ARMv7 HW
registers to walk and modify the MMU table entries.  The choice limits the
usage of this implementation to ARMv7 and similar ARM MMU architectures.  Since
this implementation is targeted at fixing an issue in 8x50 ARMv7, the choice is
logical.  The HW manipulation is in distinct low level functions.  These could
easily be replaced or generalized to support other architectures as necessary.

Restore emulation modified MMU entries on context switch -
This additional hook was added to minimize performance impact.  By guaranteeing
the ASID will not change during the emulation, the emulation may invalidate each
entry by MVA & ASID.  Only the affected page table entries will be removed from
the TLB cache.  The performance cost of the invalidate on context switch is near
zero.  Typically on context switch the domain mode would also change, forcing a
complete restore of all modified MMU entries.  The alternative would be to
invalidate the entire TLB every time a table entry is restored.

No need to restore MMU entries for copy operations -
Operations which copy MMU entries are relatively rare in the kernel.  Because
we modify the level 2 pte entries directly in hardware, the Linux shadow copies
are left untouched.  The kernel treats the shadow copies as the primary pte
entry.  Any pte copy operations would be unaffected by the HW modification.
On translation section fault, pgd entries are copied from the kernel master
page table to the current thread page table.  Since we restore MMU entries on
context switch, we guarantee the master table will not contain modifications,
while faulting on a process local entry.  Other read, modify write operations
occur during permission fault handling.  Since we open permission on modified
entries, these do not need to be restored, because we guarantee these
permission fault operations will not happen.

Invalidate TLB entries on modification -
No real choice here.  This is more of a design requirement.  On permission
fault, the MMU entry with restricted permissions will be in the TLB.  To open
access permissions, the TLB entry must be invalidated.  Otherwise the access
will permission fault again.  Upon restoring original MMU entries, the TLB
must be invalidated to restrict memory access.

Store Domain Manager bits in memory -
There was only one alternative here.  2.6.29 kernel only uses 3 of 16
possible domains.  Additional bits in dacr could be used to store the
manager bits.  This would allow faster access to the manager bits.
Overall this would reduce any performance impact.  The performance
needs did not seem to justify the added weirdness.

8 entry MMU entry cache-
The size of the modified MMU entry cache is somewhat arbitrary.  The thought
process is that typically, a thread is using two pointers to perform a copy
operation.  In this case only 2 entries would be required.  One could imagine
a more complicated operation, a masked copy for instance, which would require
more pointers.  8 pointer seemed to be large enough to minimize risk of
permission fault thrashing.  The disadvantage of a larger cache would simply
be a longer list of entries to restore.

Use spin_lock_irqsave to protect domain manipulation -
The obvious choice.

Assume no split MMU table -
This same assumption is documented in cpu_v7_switch_mm.


Power Management
================

Not affected.


SMP/multi-core
==============

SMP/multicore not supported.  This is intended as a 8x50 workaround.


Security
========

MMU page/section permissions must be manipulated correctly to emulate domain
manager mode.  If page permission are left in full access mode, any process
can read associated memory.


Performance
===========

Performance should be impacted only minimally.  When emulating domain manager
mode, there is overhead added to MMU table/context switches, set_domain()
calls, data aborts, and prefetch aborts.

Normally the kernel operates with domain != DOMAIN_MANAGER.  In this case the
overhead is minimal.  An additional check is required to see if domain manager
mode is on.  This minimal code is added to each of emulation entry points :
set, data abort, prefetch abort, and MMU table/context switch.

Initial accesses to a MMU protected page/section will generate a permission
fault. The page will be manipulated to grant full access permissions and
the access will be retried.  This will typically require 2-3 page table
walks.

On a context switch, all modified MMU entries will be restored.  On thread
resume, additional accesses will be treated as initial accesses.


Interface
=========

The emulation does not have clients.  It is hooked to the kernel through a
small list of functions.

void emulate_domain_manager_set(u32 domain);
int emulate_domain_manager_data_abort(u32 dfsr, u32 dfar);
int emulate_domain_manager_prefetch_abort(u32 ifsr, u32 ifar);
void emulate_domain_manager_switch_mm(
	unsigned long pgd_phys,
	struct mm_struct *mm,
	void (*switch_mm)(unsigned long pgd_phys, struct mm_struct *));

emulate_domain_manager_set() is the set_domain handler.  This replaces the
direct manipulation of CP15 dacr with a function call.  This allows emulation
to prevent setting dacr manager bits.  It also allows emulation to restore
page/section permissions when domain manger is disabled.

emulate_domain_manager_data_abort() handles data aborts caused by domain
not being set in HW, and handles section/page manipulation.

emulate_domain_manager_prefetch_abort() is the similar prefetch abort handler.

emulate_domain_manager_switch_mm() handles MMU table and context switches.
This notifies the emulation that the MMU context is changing.  Allowing the
emulation to restore page table entry permission before switching contexts.


Config options
==============

This option is enable/disable by the EMULATE_DOMAIN_MANAGER_V7 option.


Dependencies
============

Implementation is for ARMv7, MMU, and !SMP.  Targets solving issue for 8x50
chipset.


User space utilities
====================

None


Other
=====

Code is implemented in kernel/arch/arm/mm.


arch/arm/mm/emulate_domain_manager.c contains comments.  No additional public
documentation available or planned.


Known issues
============

No intent to support SMP or non ARMv7 architectures


To do
=====

None

