occupied by the Raspberry's peripherals such as the UART.
```
It will be used by code in `mmu.rs` to request attributes for a virtual address
and the translation of the address. The function scans `KERNEL_VIRTUAL_LAYOUT`
for a descriptor that contains the queried address, and returns the respective
findings for the first entry that is a hit. If no entry is found, it returns
default attributes for normal chacheable DRAM and the input address, hence
telling the `MMU` code that the requested address should be `identity mapped`.
The page tables we install alternate between `2 MiB` blocks and `4 KiB` blocks.
Due to this default return, it is not needed to define normal cacheable DRAM
regions in `KERNEL_VIRTUAL_LAYOUT`.
The first `2 MiB` of memory are identity mapped, and therefore contain our code
### mmu.rs
and the stack. We use a single table with a `4 KiB` granule to differentiate
between code, RO-data and RW-data. The linker script was adapted to adhere to
the pagetable sizes.
Next, we map the UART into the second `2 MiB` block to show the effects of
This file contains the `AArch64` specific code. It is a driver, if you like, and
virtual memory.
the split in paging granule mentioned before is hardcoded here (`4 KiB` page
descriptors for the first `2 MiB` and `2 MiB` block descriptors for everything
else).
Everyting else is, for reasons of convenience, again identity mapped using `2
Two static page table arrays are instantiated, `LVL2_TABLE` and `LVL3_TABLE`,
MiB` blocks.
and they are populated using `get_virt_addr_properties()` and a bunch of utility
functions that convert our own descriptors to the actual `64 bit` descriptor
entries needed by the MMU hardware for the page table arrays.
Hopefully, in a later tutorial, we will write or use (e.g. from the `cortex-a`
Afterwards, the [Translation Table Base Register 0 - EL1](https://docs.rs/crate/cortex-a/2.4.0/source/src/regs/ttbr0_el1.rs) is set up with the base address of the `LVL3_TABLE` and
crate) proper modules for page table handling, that, among others, cover topics
the [Translation Control Register - EL1](https://docs.rs/crate/cortex-a/2.4.0/source/src/regs/tcr_el1.rs) is
such as using recursive mapping for maintenace.
configured.
## Adress translation with the 4 KiB LVL3 table
Finally, the MMU is turned on through the [System Control Register - EL1](https://docs.rs/crate/cortex-a/2.4.0/source/src/regs/sctlr_el1.rs). The last step also enables caching for data and instructions.
The following block diagram shows address translation by example of the UART's
## Address translation examples
Control Register (CR).
For educational purposes, in `memory.rs`, a layout is defined which allows to
access the `UART` via two different virtual addresses:
- Since we identity map the whole `Device MMIO` region, it is accessible by
asserting its physical base address (`0x3F20_1000`) after the `MMU` is turned
on.
- Additionally, it is also mapped into the last `4 KiB` entry of the `LVL3`
table, making it accessible through base address `0x001F_F000`.
The following two block diagrams visualize the underlying translations for the
two mappings, accessing the UART's Control Register (`CR`, offset `0x30`).
### Adress translation using a 2 MiB block descriptor
The MMU init code is a good example to see the great potential of Rust's
The MMU init code is also a good example to see the great potential of Rust's
zero-cost abstractions[[1]](https://blog.rust-lang.org/2015/05/11/traits.html)[[2]](https://ruudvanasseldonk.com/2016/11/30/zero-cost-abstractions) for embedded programming.
zero-cost abstractions[[1]](https://blog.rust-lang.org/2015/05/11/traits.html)[[2]](https://ruudvanasseldonk.com/2016/11/30/zero-cost-abstractions) for embedded programming.
Take this piece of code for setting up the `MAIR_EL1` register using the
Take this piece of code for setting up the `MAIR_EL1` register using the
@ -57,7 +149,7 @@ MAIR_EL1.write(
);
);
```
```
This piece of code is super expressive, and it makes us of `traits`, different
This piece of code is super expressive, and it makes use of `traits`, different
`types` and `constants` to provide type-safe register manipulation.
`types` and `constants` to provide type-safe register manipulation.
In the end, this code sets the first four bytes of the register to certain
In the end, this code sets the first four bytes of the register to certain
@ -84,6 +176,5 @@ ferris@box:~$ make raspboot
[i] MMU: Up to 40 Bit physical address range supported!
[i] MMU: Up to 40 Bit physical address range supported!
[2] MMU online.
[2] MMU online.
Writing through the virtual mapping at 0x00000000001FF000.
Writing through the virtual mapping at base address 0x00000000001FF000.