arm/arm64: Perform dcache maintenance at boot
The arm and arm64 architectures require explicit cache maintenance to
keep the memory in sync with the caches when the MMU is turned on. When
the MMU is off, reads and writes are access system memory directly, but
with the MMU on, the same accesses hit the cache.
The sequence of cache maintenance operations to keep the cache contents
in sync with memory is:
1. Dcache invalidation for memory location M before the first write to
that location. This is needed to avoid a dirty cache line for address
M* being evicted after the explicit write that follows, and overwriting
the value that software writes. Dcache clean also works, but invalidation
is faster on bare metal. When running in a virtual machine, dcache
invalidation is promoted to dcache clean + invalidation, so it makes little
difference exactly which of the dcache operations is chosen, as long as
the result is that no cache line is dirty.
2. A write, or multiple writes, to memory address M are performed.
3. After the last write, and before the first read with the MMU on, the
dcache line that hold the value for memory location M needs to be
invalidated. This is needed to make sure that loads fetch data from
memory, where the most recent value written in step 2 is, instead of
reading clean, but stale values from the cache**.
For robustness and simplicty, the dcache invalidation at step 3 is
performed after the last write with the MMU off.
When running under KVM, the maintenance operations can be omitted when
first enabling the MMU because:
- KVM performs a dcache clean + invalidate on each page the first time a
guest accesses the page. This corresponds to the maintenance at step 1.
- KVM performs a dcache clean + invalidate on the entire guest memory when
the MMU is turned on. This corresponds to the maintenance at step 3. The
dcache clean is harmless for a guest, because all accessed cache lines are
already clean because of the cache maintenance above.
The situation changes when kvm-unit-tests turns the MMU off and then turns
it back on: KVM will skip the cache maintenance when the MMU is enabled
again, and potentially skip the maintenance on page access if the page is
already mapped at stage 2. In this case, explicit cache maintenance is
required even when running as a KVM guest, although this is the
responsibility of the test to perform, since the library or boot code
doesn't turn the MMU off after enabling it.
Do what is needed to ensure correctness and perform the CMOs before
enabling the MMU on the boot path. The stack is a special case, since
kvm-unit-tests runs C code with the MMU disabled and the compiler can
arbitrarily modify the stack when compiling C code. So invalidate the
entire stack in the assembly function asm_mmu_enable.
Note that for static variables, the dcache maintenance at step 1 is omitted
because either the variable is stored in the data section of the test
image, which is cleaned to the PoC as per the Linux boot protocol, or in
the BSS section, which is invalidated to the PoC in the assembly entry code.
*The cache line could have been dirtied by higher level software, for
example by firmware.
**Even though the address M is invalidated in step 1, higher level software
could have allocated a new, clean cache line, as a result of a direct or
speculated read.
Signed-off-by:
Alexandru Elisei <alexandru.elisei@arm.com>
Loading
Please register or sign in to comment