blob: ee9971077b1b206457942ce055c34d397e18b98d [file] [log] [blame]
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +00001// 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
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +010017use crate::helpers;
Pierre-Clément Tosi23aba522023-04-21 17:03:50 +010018use crate::helpers::PVMFW_PAGE_SIZE;
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +000019use aarch64_paging::idmap::IdMap;
20use aarch64_paging::paging::Attributes;
21use aarch64_paging::paging::MemoryRegion;
22use aarch64_paging::MapError;
23use core::ops::Range;
24use 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)
29const MEMORY: Attributes = Attributes::NORMAL.union(Attributes::NON_GLOBAL);
30const DEVICE: Attributes = Attributes::DEVICE_NGNRE.union(Attributes::EXECUTE_NEVER);
31const CODE: Attributes = MEMORY.union(Attributes::READ_ONLY);
32const DATA: Attributes = MEMORY.union(Attributes::EXECUTE_NEVER);
33const RODATA: Attributes = DATA.union(Attributes::READ_ONLY);
34
35/// High-level API for managing MMU mappings.
36pub struct PageTable {
37 idmap: IdMap,
38}
39
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +010040fn 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
Pierre-Clément Tosi23aba522023-04-21 17:03:50 +010048/// Region allocated for the stack.
49fn stack_range() -> Range<usize> {
50 const STACK_PAGES: usize = 40;
51
52 layout::stack_range(STACK_PAGES * PVMFW_PAGE_SIZE)
53}
54
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +000055impl PageTable {
56 const ASID: usize = 1;
57 const ROOT_LEVEL: usize = 1;
58
59 /// Creates an instance pre-populated with pvmfw's binary layout.
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())?;
Pierre-Clément Tosi8bb3d722023-04-21 16:10:56 +010064 page_table.map_data(&layout::scratch_range())?;
Pierre-Clément Tosi23aba522023-04-21 17:03:50 +010065 page_table.map_data(&stack_range())?;
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +000066 page_table.map_rodata(&layout::rodata_range())?;
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +010067 page_table.map_data(&appended_payload_range())?;
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +000068
69 Ok(page_table)
70 }
71
72 pub unsafe fn activate(&mut self) {
73 self.idmap.activate()
74 }
75
76 pub fn map_device(&mut self, range: &Range<usize>) -> Result<(), MapError> {
77 self.map_range(range, DEVICE)
78 }
79
80 pub fn map_data(&mut self, range: &Range<usize>) -> Result<(), MapError> {
81 self.map_range(range, DATA)
82 }
83
84 pub fn map_code(&mut self, range: &Range<usize>) -> Result<(), MapError> {
85 self.map_range(range, CODE)
86 }
87
88 pub fn map_rodata(&mut self, range: &Range<usize>) -> Result<(), MapError> {
89 self.map_range(range, RODATA)
90 }
91
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}