/src/MigTD/deps/td-shim/td-paging/src/frame.rs
Line | Count | Source |
1 | | // Copyright (c) 2021 Intel Corporation |
2 | | // Copyright (c) 2022 Alibaba Cloud |
3 | | // |
4 | | // SPDX-License-Identifier: BSD-2-Clause-Patent |
5 | | |
6 | | use alloc::vec; |
7 | | use alloc::vec::Vec; |
8 | | use core::ops::Range; |
9 | | use log::{info, trace}; |
10 | | use spin::Mutex; |
11 | | use x86_64::{ |
12 | | structures::paging::{FrameAllocator, PhysFrame, Size4KiB}, |
13 | | PhysAddr, |
14 | | }; |
15 | | |
16 | | use super::consts::PAGE_SIZE; |
17 | | |
18 | | /// Global page table page allocator. |
19 | | pub static FRAME_ALLOCATOR: Mutex<BMFrameAllocator> = Mutex::new(BMFrameAllocator::empty()); |
20 | | |
21 | | struct FrameAlloc { |
22 | | // A bit of `1` means available. |
23 | | bitmap: Vec<u128>, |
24 | | } |
25 | | |
26 | | impl FrameAlloc { |
27 | 0 | fn new(num_frames: usize) -> Self { |
28 | 0 | Self { |
29 | 0 | bitmap: vec![0u128; (num_frames + 127) / 128], |
30 | 0 | } |
31 | 0 | } |
32 | | |
33 | 0 | fn alloc(&mut self) -> Option<usize> { |
34 | 0 | for (idx, map) in self.bitmap.iter_mut().enumerate() { |
35 | 0 | let pos = map.trailing_zeros(); |
36 | 0 | if pos < 128 { |
37 | 0 | *map &= !(1 << pos); |
38 | 0 | return Some(idx * 128 + pos as usize); |
39 | 0 | } |
40 | | } |
41 | | |
42 | 0 | None |
43 | 0 | } |
44 | | |
45 | 0 | fn free(&mut self, range: Range<usize>) { |
46 | 0 | for idx in range { |
47 | 0 | if idx >= self.bitmap.len() * 128 { |
48 | 0 | panic!("invalid page frame index {} for FrameAlloc::free()!", idx); |
49 | 0 | } |
50 | 0 | if self.bitmap[idx / 128] & (1 << (idx % 128)) != 0 { |
51 | 0 | panic!( |
52 | 0 | "try to free unallocated page frame index {} for FrameAlloc::free()!", |
53 | | idx |
54 | | ); |
55 | 0 | } |
56 | 0 | self.bitmap[idx / 128] |= 1 << (idx % 128); |
57 | | } |
58 | 0 | } |
59 | | |
60 | 0 | fn reserve(&mut self, idx: usize) { |
61 | 0 | if idx >= self.bitmap.len() * 128 { |
62 | 0 | panic!("invalid page frame index {} for FrameAlloc::free()!", idx); |
63 | 0 | } |
64 | 0 | if self.bitmap[idx / 128] & (1 << (idx % 128)) == 0 { |
65 | 0 | panic!( |
66 | 0 | "try to reserve unavailable page frame index {} for FrameAlloc::free()!", |
67 | | idx |
68 | | ); |
69 | 0 | } |
70 | 0 | self.bitmap[idx / 128] &= !(1 << (idx % 128)); |
71 | 0 | } |
72 | | } |
73 | | |
74 | | pub struct BMFrameAllocator { |
75 | | base: usize, |
76 | | size: usize, |
77 | | inner: FrameAlloc, |
78 | | } |
79 | | |
80 | | #[allow(dead_code)] |
81 | | impl BMFrameAllocator { |
82 | | const fn empty() -> Self { |
83 | | Self { |
84 | | base: 0, |
85 | | size: 0, |
86 | | inner: FrameAlloc { bitmap: Vec::new() }, |
87 | | } |
88 | | } |
89 | | |
90 | | // Caller needs to ensure: |
91 | | // - base is page aligned |
92 | | // - size is page aligned |
93 | | // - base + size doesn't wrap around |
94 | 0 | fn new(base: usize, size: usize) -> Self { |
95 | 0 | let page_count = size / PAGE_SIZE; |
96 | 0 | let mut inner = FrameAlloc::new(page_count); |
97 | | |
98 | 0 | inner.free(0..page_count); |
99 | | |
100 | 0 | Self { base, size, inner } |
101 | 0 | } |
102 | | |
103 | 0 | fn alloc(&mut self) -> Option<usize> { |
104 | 0 | let ret = self.inner.alloc().map(|idx| idx * PAGE_SIZE + self.base); |
105 | 0 | trace!("Allocate frame: {:x?}\n", ret); |
106 | 0 | ret |
107 | 0 | } |
108 | | |
109 | 0 | pub(crate) fn reserve(&mut self, addr: u64) { |
110 | 0 | if addr > usize::MAX as u64 |
111 | 0 | || (addr as usize) < self.base |
112 | 0 | || (addr as usize) >= self.base + self.size |
113 | | { |
114 | 0 | panic!( |
115 | 0 | "Invalid address 0x{:x} to BMFrameAllocator::reserve()", |
116 | | addr |
117 | | ); |
118 | 0 | } |
119 | 0 | self.inner.reserve((addr as usize - self.base) / PAGE_SIZE); |
120 | 0 | } |
121 | | } |
122 | | |
123 | | unsafe impl FrameAllocator<Size4KiB> for BMFrameAllocator { |
124 | 0 | fn allocate_frame(&mut self) -> Option<PhysFrame<Size4KiB>> { |
125 | 0 | let addr = self.alloc()?; |
126 | 0 | Some(PhysFrame::containing_address( |
127 | 0 | PhysAddr::try_new(addr as u64).ok()?, |
128 | | )) |
129 | 0 | } |
130 | | } |
131 | | |
132 | | /// Initialize the physical frame allocator. |
133 | 0 | pub(super) fn init(base: u64, size: usize) { |
134 | 0 | let mut allocator = FRAME_ALLOCATOR.lock(); |
135 | 0 | if allocator.base == 0 && allocator.size == 0 { |
136 | 0 | *allocator = BMFrameAllocator::new(base as usize, size); |
137 | | // The first frame should've already been allocated to level 4 PT |
138 | | // Safe since the PAGE_TABLE_SIZE can be ensured |
139 | 0 | allocator.alloc().unwrap(); |
140 | 0 | info!( |
141 | 0 | "Frame allocator init done: {:#x?}\n", |
142 | 0 | base..base + size as u64 |
143 | | ); |
144 | 0 | } |
145 | 0 | } |
146 | | |
147 | | #[cfg(test)] |
148 | | mod tests { |
149 | | use super::*; |
150 | | |
151 | | const PAGE_TABLE_BASE: u64 = 0x800000; |
152 | | const PAGE_TABLE_SIZE: usize = 0x800000; |
153 | | const NUM_PAGE_TABLE_FRAME: usize = PAGE_TABLE_SIZE / PAGE_SIZE; |
154 | | |
155 | | #[test] |
156 | | fn test_frame_alloc() { |
157 | | let mut allocator = FrameAlloc::new(NUM_PAGE_TABLE_FRAME); |
158 | | |
159 | | assert_eq!(allocator.bitmap[0] & 0x1, 0); |
160 | | assert_eq!(allocator.bitmap[0] & 0x2, 0); |
161 | | assert_eq!(allocator.bitmap[0] & 0x4, 0); |
162 | | |
163 | | allocator.free(0..3); |
164 | | assert_eq!(allocator.bitmap[0] & 0x1, 0x1); |
165 | | assert_eq!(allocator.bitmap[0] & 0x2, 0x2); |
166 | | assert_eq!(allocator.bitmap[0] & 0x4, 0x4); |
167 | | |
168 | | allocator.reserve(0); |
169 | | assert_eq!(allocator.bitmap[0] & 0x1, 0x0); |
170 | | assert_eq!(allocator.bitmap[0] & 0x2, 0x2); |
171 | | assert_eq!(allocator.bitmap[0] & 0x4, 0x4); |
172 | | |
173 | | assert_eq!(allocator.alloc().unwrap(), 1); |
174 | | assert_eq!(allocator.bitmap[0] & 0x1, 0x0); |
175 | | assert_eq!(allocator.bitmap[0] & 0x2, 0x0); |
176 | | assert_eq!(allocator.bitmap[0] & 0x4, 0x4); |
177 | | |
178 | | allocator.free(1..2); |
179 | | assert_eq!(allocator.bitmap[0] & 0x1, 0x0); |
180 | | assert_eq!(allocator.bitmap[0] & 0x2, 0x2); |
181 | | assert_eq!(allocator.bitmap[0] & 0x4, 0x4); |
182 | | |
183 | | assert_eq!(allocator.alloc().unwrap(), 1); |
184 | | assert_eq!(allocator.alloc().unwrap(), 2); |
185 | | assert!(allocator.alloc().is_none()); |
186 | | assert!(allocator.alloc().is_none()); |
187 | | } |
188 | | |
189 | | #[test] |
190 | | #[should_panic] |
191 | | fn test_frame_free_invalid_index() { |
192 | | let mut allocator = FrameAlloc::new(NUM_PAGE_TABLE_FRAME); |
193 | | |
194 | | allocator.free(0..NUM_PAGE_TABLE_FRAME + 1); |
195 | | } |
196 | | |
197 | | #[test] |
198 | | #[should_panic] |
199 | | fn test_frame_free_invalid_state() { |
200 | | let mut allocator = FrameAlloc::new(NUM_PAGE_TABLE_FRAME); |
201 | | |
202 | | allocator.free(0..3); |
203 | | allocator.free(0..3); |
204 | | } |
205 | | |
206 | | #[test] |
207 | | #[should_panic] |
208 | | fn test_frame_reserve_invalid_index() { |
209 | | let mut allocator = FrameAlloc::new(NUM_PAGE_TABLE_FRAME); |
210 | | |
211 | | allocator.reserve(NUM_PAGE_TABLE_FRAME); |
212 | | } |
213 | | |
214 | | #[test] |
215 | | #[should_panic] |
216 | | fn test_frame_reserve_invalid_state() { |
217 | | let mut allocator = FrameAlloc::new(NUM_PAGE_TABLE_FRAME); |
218 | | |
219 | | allocator.free(0..3); |
220 | | allocator.reserve(1); |
221 | | allocator.reserve(1); |
222 | | } |
223 | | |
224 | | #[test] |
225 | | fn test_empty_bm_allocator() { |
226 | | let mut allocator = BMFrameAllocator::empty(); |
227 | | assert!(allocator.alloc().is_none()); |
228 | | assert!(allocator.alloc().is_none()); |
229 | | } |
230 | | |
231 | | #[test] |
232 | | fn test_bm_allocator() { |
233 | | init(PAGE_TABLE_BASE, PAGE_TABLE_SIZE); |
234 | | let mut allocator = FRAME_ALLOCATOR.lock(); |
235 | | |
236 | | // First page has been allocated by init(), try second page |
237 | | allocator.reserve(PAGE_TABLE_BASE + PAGE_SIZE as u64); |
238 | | allocator.reserve(PAGE_TABLE_BASE + PAGE_TABLE_SIZE as u64 - 1); |
239 | | assert_eq!( |
240 | | allocator.allocate_frame().unwrap().start_address().as_u64(), |
241 | | PAGE_TABLE_BASE + 2 * PAGE_SIZE as u64 |
242 | | ); |
243 | | } |
244 | | } |