|
18 | 18 | // Some code borrowed from the x86_64 crate (MIT + Apache) and add support for 5-level paging |
19 | 19 | // and some kernel specific features that cannot be directly done in the crate itself. |
20 | 20 |
|
21 | | -use core::ops::Range; |
22 | | - |
23 | | -use crate::mem::AddressSpace; |
| 21 | +use core::ops::{Range, RangeInclusive}; |
24 | 22 |
|
25 | 23 | use super::addr::{PhysAddr, VirtAddr}; |
26 | 24 | use super::page::{AddressNotAligned, Page, PageSize, PhysFrame, Size1GiB, Size2MiB, Size4KiB}; |
@@ -1139,187 +1137,53 @@ impl<'a> OffsetPageTable<'a> { |
1139 | 1137 | Ok(()) |
1140 | 1138 | } |
1141 | 1139 |
|
1142 | | - pub fn fork(&mut self) -> Result<AddressSpace, MapToError<Size4KiB>> { |
1143 | | - let mut address_space = AddressSpace::new()?; // Allocate the new address space |
1144 | | - |
1145 | | - let offset_table = address_space.offset_page_table(); |
1146 | | - let make_next_level = |table: &mut PageTable, |
1147 | | - i: usize| |
1148 | | - -> Result<(bool, &mut PageTable), MapToError<Size4KiB>> { |
1149 | | - let entry = &mut table[i]; |
1150 | | - let created = if !entry.flags().contains(PageTableFlags::PRESENT) { |
1151 | | - let frame = FRAME_ALLOCATOR |
1152 | | - .allocate_frame() |
1153 | | - .ok_or(MapToError::FrameAllocationFailed)?; |
1154 | | - |
1155 | | - entry.set_frame( |
1156 | | - frame, |
1157 | | - PageTableFlags::PRESENT |
1158 | | - | PageTableFlags::WRITABLE |
1159 | | - | PageTableFlags::USER_ACCESSIBLE, |
1160 | | - ); |
1161 | | - |
1162 | | - true |
1163 | | - } else { |
1164 | | - entry.set_flags( |
1165 | | - PageTableFlags::PRESENT |
1166 | | - | PageTableFlags::WRITABLE |
1167 | | - | PageTableFlags::USER_ACCESSIBLE, |
1168 | | - ); |
1169 | | - |
1170 | | - false |
1171 | | - }; |
1172 | | - |
1173 | | - let page_table_ptr = { |
1174 | | - let addr = entry.frame().unwrap().start_address().as_hhdm_virt(); |
1175 | | - addr.as_mut_ptr::<PageTable>() |
1176 | | - }; |
1177 | | - |
1178 | | - let page_table: &mut PageTable = unsafe { &mut *page_table_ptr }; |
1179 | | - if created { |
1180 | | - page_table.zero(); |
| 1140 | + pub fn copy_page_range(&mut self, src: &mut OffsetPageTable, range: RangeInclusive<VirtAddr>) { |
| 1141 | + let mut map_to = |src: &mut OffsetPageTable, addr, frame, flags| match frame { |
| 1142 | + MappedFrame::Size4KiB(frame) => { |
| 1143 | + let page = Page::<Size4KiB>::containing_address(addr); |
| 1144 | + |
| 1145 | + unsafe { |
| 1146 | + self.map_to_with_table_flags( |
| 1147 | + page, |
| 1148 | + frame, |
| 1149 | + flags, |
| 1150 | + PageTableFlags::PRESENT |
| 1151 | + | PageTableFlags::USER_ACCESSIBLE |
| 1152 | + | PageTableFlags::WRITABLE, |
| 1153 | + ) |
| 1154 | + } |
| 1155 | + .unwrap() |
| 1156 | + // operating on an inactive page table |
| 1157 | + .ignore(); |
| 1158 | + |
| 1159 | + unsafe { src.update_flags(page, flags) } |
| 1160 | + .unwrap() |
| 1161 | + // caller is required to invalidate the TLB |
| 1162 | + .ignore(); |
1181 | 1163 | } |
1182 | | - |
1183 | | - Ok((created, page_table)) |
| 1164 | + _ => todo!(), |
1184 | 1165 | }; |
1185 | 1166 |
|
1186 | | - let last_level_fork = |entry: &mut PageTableEntry, n1: &mut PageTable, i: usize| { |
1187 | | - let mut flags = entry.flags(); |
| 1167 | + let mut addr = *range.start(); |
1188 | 1168 |
|
1189 | | - // Check if the mapping is shared. |
1190 | | - // if !flags.contains(PageTableFlags::BIT_10) { |
1191 | | - // Setup copy on write page. |
1192 | | - flags.remove(PageTableFlags::WRITABLE); |
1193 | | - // } |
| 1169 | + while addr != *range.end() { |
| 1170 | + match src.translate(addr) { |
| 1171 | + TranslateResult::Mapped { |
| 1172 | + frame, |
| 1173 | + offset, |
| 1174 | + flags, |
| 1175 | + } => { |
| 1176 | + assert_eq!(offset, 0, "unaligned page range"); |
| 1177 | + map_to(src, addr, frame, flags & !PageTableFlags::WRITABLE); |
| 1178 | + } |
1194 | 1179 |
|
1195 | | - entry.set_flags(flags); |
1196 | | - n1[i].set_frame(entry.frame().unwrap(), flags); |
1197 | | - }; |
| 1180 | + TranslateResult::NotMapped => {} |
| 1181 | + TranslateResult::InvalidFrameAddress(addr) => { |
| 1182 | + panic!("invalid frame address {:#x}", addr); |
| 1183 | + } |
| 1184 | + } |
1198 | 1185 |
|
1199 | | - // We loop through each of the page table entries in the page table which are user |
1200 | | - // accessible and we remove the writeable flag from the entry if present. This will |
1201 | | - // make the page table entry copy on the first write. Then we clone the page table entry |
1202 | | - // and place it in the new page table. |
1203 | | - if self.inner.level_5_paging_enabled { |
1204 | | - self.inner.page_table.for_entries_mut( |
1205 | | - PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE, |
1206 | | - |i, _, table| { |
1207 | | - let (_, n4) = make_next_level(offset_table.inner.page_table, i)?; |
1208 | | - let mut count_4 = 0; |
1209 | | - |
1210 | | - table.for_entries_mut( |
1211 | | - PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE, |
1212 | | - |j, _, table| { |
1213 | | - let (w3, n3) = make_next_level(n4, j)?; |
1214 | | - let mut count_3 = 0; |
1215 | | - |
1216 | | - if w3 { |
1217 | | - count_4 += 1; |
1218 | | - } |
1219 | | - |
1220 | | - table.for_entries_mut( |
1221 | | - PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE, |
1222 | | - |k, _, table| { |
1223 | | - let (w2, n2) = make_next_level(n3, k)?; |
1224 | | - let mut count_2 = 0; |
1225 | | - |
1226 | | - if w2 { |
1227 | | - count_3 += 1; |
1228 | | - } |
1229 | | - |
1230 | | - table.for_entries_mut( |
1231 | | - PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE, |
1232 | | - |l, _, table| { |
1233 | | - let (w1, n1) = make_next_level(n2, l)?; |
1234 | | - let mut count_1 = 0; |
1235 | | - |
1236 | | - if w1 { |
1237 | | - count_2 += 1; |
1238 | | - } |
1239 | | - |
1240 | | - table.for_entries_mut( |
1241 | | - PageTableFlags::PRESENT |
1242 | | - | PageTableFlags::USER_ACCESSIBLE, |
1243 | | - |i, entry, _| { |
1244 | | - last_level_fork(entry, n1, i); |
1245 | | - |
1246 | | - count_1 += 1; |
1247 | | - Ok(()) |
1248 | | - }, |
1249 | | - )?; |
1250 | | - |
1251 | | - n2[l].set_entry_count(count_1); |
1252 | | - Ok(()) |
1253 | | - }, |
1254 | | - )?; |
1255 | | - |
1256 | | - n3[k].set_entry_count(count_2); |
1257 | | - Ok(()) |
1258 | | - }, |
1259 | | - )?; |
1260 | | - |
1261 | | - n4[j].set_entry_count(count_3); |
1262 | | - Ok(()) |
1263 | | - }, |
1264 | | - )?; |
1265 | | - |
1266 | | - offset_table.inner.page_table[i].set_entry_count(count_4); |
1267 | | - Ok(()) |
1268 | | - }, |
1269 | | - )?; |
1270 | | - } else { |
1271 | | - self.inner.page_table.for_entries_mut( |
1272 | | - PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE, |
1273 | | - |i, _, table| { |
1274 | | - let (_, n3) = make_next_level(offset_table.inner.page_table, i)?; |
1275 | | - let mut count_3 = 0; |
1276 | | - |
1277 | | - table.for_entries_mut( |
1278 | | - PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE, |
1279 | | - |k, _, table| { |
1280 | | - let (w2, n2) = make_next_level(n3, k)?; |
1281 | | - let mut count_2 = 0; |
1282 | | - |
1283 | | - if w2 { |
1284 | | - count_3 += 1; |
1285 | | - } |
1286 | | - |
1287 | | - table.for_entries_mut( |
1288 | | - PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE, |
1289 | | - |l, _, table| { |
1290 | | - let (w1, n1) = make_next_level(n2, l)?; |
1291 | | - let mut count_1 = 0; |
1292 | | - |
1293 | | - if w1 { |
1294 | | - count_2 += 1; |
1295 | | - } |
1296 | | - |
1297 | | - table.for_entries_mut( |
1298 | | - PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE, |
1299 | | - |i, entry, _| { |
1300 | | - last_level_fork(entry, n1, i); |
1301 | | - |
1302 | | - count_1 += 1; |
1303 | | - Ok(()) |
1304 | | - }, |
1305 | | - )?; |
1306 | | - |
1307 | | - n2[l].set_entry_count(count_1); |
1308 | | - Ok(()) |
1309 | | - }, |
1310 | | - )?; |
1311 | | - |
1312 | | - n3[k].set_entry_count(count_2); |
1313 | | - Ok(()) |
1314 | | - }, |
1315 | | - )?; |
1316 | | - |
1317 | | - offset_table.inner.page_table[i].set_entry_count(count_3); |
1318 | | - Ok(()) |
1319 | | - }, |
1320 | | - )?; |
| 1186 | + addr += Size4KiB::SIZE; |
1321 | 1187 | } |
1322 | | - |
1323 | | - Ok(address_space) |
1324 | 1188 | } |
1325 | 1189 | } |
0 commit comments