1 // Copyright 2022, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Memory management.
16 
17 use crate::helpers;
18 use crate::helpers::PVMFW_PAGE_SIZE;
19 use aarch64_paging::idmap::IdMap;
20 use aarch64_paging::paging::Attributes;
21 use aarch64_paging::paging::MemoryRegion;
22 use aarch64_paging::MapError;
23 use core::ops::Range;
24 use vmbase::layout;
25 
26 // We assume that:
27 // - MAIR_EL1.Attr0 = "Device-nGnRE memory" (0b0000_0100)
28 // - MAIR_EL1.Attr1 = "Normal memory, Outer & Inner WB Non-transient, R/W-Allocate" (0b1111_1111)
29 const MEMORY: Attributes = Attributes::NORMAL.union(Attributes::NON_GLOBAL);
30 const DEVICE: Attributes = Attributes::DEVICE_NGNRE.union(Attributes::EXECUTE_NEVER);
31 const CODE: Attributes = MEMORY.union(Attributes::READ_ONLY);
32 const DATA: Attributes = MEMORY.union(Attributes::EXECUTE_NEVER);
33 const RODATA: Attributes = DATA.union(Attributes::READ_ONLY);
34 
35 /// High-level API for managing MMU mappings.
36 pub struct PageTable {
37     idmap: IdMap,
38 }
39 
appended_payload_range() -> Range<usize>40 fn appended_payload_range() -> Range<usize> {
41     let start = helpers::align_up(layout::binary_end(), helpers::SIZE_4KB).unwrap();
42     // pvmfw is contained in a 2MiB region so the payload can't be larger than the 2MiB alignment.
43     let end = helpers::align_up(start, helpers::SIZE_2MB).unwrap();
44 
45     start..end
46 }
47 
48 /// Region allocated for the stack.
stack_range() -> Range<usize>49 pub fn stack_range() -> Range<usize> {
50     const STACK_PAGES: usize = 8;
51 
52     layout::stack_range(STACK_PAGES * PVMFW_PAGE_SIZE)
53 }
54 
55 impl PageTable {
56     const ASID: usize = 1;
57     const ROOT_LEVEL: usize = 1;
58 
59     /// Creates an instance pre-populated with pvmfw's binary layout.
from_static_layout() -> Result<Self, MapError>60     pub fn from_static_layout() -> Result<Self, MapError> {
61         let mut page_table = Self { idmap: IdMap::new(Self::ASID, Self::ROOT_LEVEL) };
62 
63         page_table.map_code(&layout::text_range())?;
64         page_table.map_data(&layout::scratch_range())?;
65         page_table.map_data(&stack_range())?;
66         page_table.map_rodata(&layout::rodata_range())?;
67         page_table.map_data(&appended_payload_range())?;
68 
69         Ok(page_table)
70     }
71 
activate(&mut self)72     pub unsafe fn activate(&mut self) {
73         self.idmap.activate()
74     }
75 
map_device(&mut self, range: &Range<usize>) -> Result<(), MapError>76     pub fn map_device(&mut self, range: &Range<usize>) -> Result<(), MapError> {
77         self.map_range(range, DEVICE)
78     }
79 
map_data(&mut self, range: &Range<usize>) -> Result<(), MapError>80     pub fn map_data(&mut self, range: &Range<usize>) -> Result<(), MapError> {
81         self.map_range(range, DATA)
82     }
83 
map_code(&mut self, range: &Range<usize>) -> Result<(), MapError>84     pub fn map_code(&mut self, range: &Range<usize>) -> Result<(), MapError> {
85         self.map_range(range, CODE)
86     }
87 
map_rodata(&mut self, range: &Range<usize>) -> Result<(), MapError>88     pub fn map_rodata(&mut self, range: &Range<usize>) -> Result<(), MapError> {
89         self.map_range(range, RODATA)
90     }
91 
map_range(&mut self, range: &Range<usize>, attr: Attributes) -> Result<(), MapError>92     fn map_range(&mut self, range: &Range<usize>, attr: Attributes) -> Result<(), MapError> {
93         self.idmap.map_range(&MemoryRegion::new(range.start, range.end), attr)
94     }
95 }
96