Nothing to see here, move along
at main 885 lines 29 kB view raw
1use crate::cap::cnode; 2use crate::cap::pool::POOL; 3use crate::cap::table::{CapRef, Rights}; 4use crate::error::KernelError; 5use crate::mem::phys::BitmapFrameAllocator; 6use crate::proc::PROCESSES; 7use lancer_core::object_layout::KernelObject; 8use lancer_core::object_tag::ObjectTag; 9 10crate::kernel_test!( 11 fn scale_10k_pids() { 12 let mut allocator = BitmapFrameAllocator; 13 let mut ptable = PROCESSES.lock(); 14 15 let mut allocated = crate::static_vec::StaticVec::<crate::types::Pid, 256>::new(); 16 17 let target = 256; 18 (0..target).for_each(|_| { 19 if let Some(created) = ptable.allocate(&mut allocator) { 20 let _ = allocated.push(created.pid()); 21 } 22 }); 23 24 let count = allocated.len(); 25 assert!(count >= 200, "expected at least 200 PIDs, got {}", count); 26 27 allocated.as_slice().iter().for_each(|&pid| { 28 assert!( 29 ptable.get(pid).is_some(), 30 "allocated PID {} should be accessible", 31 pid.raw() 32 ); 33 }); 34 35 (1..count).for_each(|i| { 36 (0..i).for_each(|j| { 37 assert!( 38 allocated.as_slice()[i] != allocated.as_slice()[j], 39 "duplicate PID at indices {} and {}", 40 i, 41 j 42 ); 43 }); 44 }); 45 46 allocated.as_slice().iter().for_each(|&pid| { 47 ptable.destroy(pid, &mut allocator); 48 }); 49 50 let mut reallocated = crate::static_vec::StaticVec::<crate::types::Pid, 256>::new(); 51 (0..target).for_each(|_| { 52 if let Some(created) = ptable.allocate(&mut allocator) { 53 let _ = reallocated.push(created.pid()); 54 } 55 }); 56 assert!( 57 reallocated.len() >= 200, 58 "after free, expected at least 200 re-allocated PIDs, got {}", 59 reallocated.len() 60 ); 61 62 reallocated.as_slice().iter().for_each(|&pid| { 63 ptable.destroy(pid, &mut allocator); 64 }); 65 } 66); 67 68crate::kernel_test!( 69 fn scale_create_destroy_loop() { 70 let ptable = PROCESSES.lock(); 71 let mut pool = POOL.lock_after(&ptable); 72 73 let baseline = pool.active_count(); 74 75 let iterations = 50; 76 (0..iterations).for_each(|round| { 77 let (ep_id, ep_gen) = crate::tests::helpers::alloc_endpoint(&mut pool) 78 .unwrap_or_else(|e| panic!("alloc endpoint round {}: {:?}", round, e)); 79 if let Some((phys, _)) = pool.dec_ref_phys(ep_id, ep_gen) { 80 crate::cap::kernel_objects::free_slot(phys); 81 } 82 }); 83 84 let after = pool.active_count(); 85 assert!( 86 after == baseline, 87 "object leak: baseline={}, after={}, delta={}", 88 baseline, 89 after, 90 after as i64 - baseline as i64 91 ); 92 } 93); 94 95crate::kernel_test!( 96 fn exhaust_retype() { 97 let mut ptable = PROCESSES.lock(); 98 let mut allocator = BitmapFrameAllocator; 99 100 let created = ptable.allocate(&mut allocator).expect("alloc proc"); 101 ptable.start(created).expect("start"); 102 let pid = created.pid(); 103 crate::tests::helpers::bootstrap_test_cnode(pid, &mut ptable); 104 105 let (ut_id, ut_gen, _) = crate::tests::helpers::allocate_small_untyped(&ptable, 12); 106 let (cnode_id, cnode_gen, depth, gv, gb) = 107 cnode::cnode_coords(pid, &ptable).expect("coords"); 108 let mut pool = POOL.lock_after(&ptable); 109 110 let ut_cap = CapRef::new(ObjectTag::Untyped, ut_id, Rights::ALL, ut_gen); 111 cnode::resolve_and_insert(&pool, cnode_id, cnode_gen, 900, depth, gv, gb, ut_cap) 112 .expect("insert ut"); 113 114 let mut dest = 100u64; 115 let mut created_count = 0u32; 116 let mut hit_exhaustion = false; 117 (0..200u32).for_each(|_| { 118 match crate::cap::retype::kernel_retype( 119 &mut pool, 120 None, 121 ut_id, 122 ut_gen, 123 ObjectTag::Endpoint, 124 0, 125 cnode_id, 126 cnode_gen, 127 dest, 128 depth, 129 gv, 130 gb, 131 1, 132 ) { 133 Ok(()) => { 134 created_count += 1; 135 dest += 1; 136 } 137 Err(KernelError::ResourceExhausted) => { 138 hit_exhaustion = true; 139 } 140 Err(_) => { 141 hit_exhaustion = true; 142 } 143 } 144 }); 145 146 assert!(hit_exhaustion, "should have hit resource exhaustion"); 147 assert!(created_count > 0, "should have created at least one object"); 148 149 drop(pool); 150 ptable.destroy(pid, &mut allocator); 151 } 152); 153 154crate::kernel_test!( 155 fn interleaved_retype_revoke() { 156 let mut ptable = PROCESSES.lock(); 157 let mut allocator = BitmapFrameAllocator; 158 159 let created = ptable.allocate(&mut allocator).expect("alloc proc"); 160 ptable.start(created).expect("start"); 161 let pid = created.pid(); 162 crate::tests::helpers::bootstrap_test_cnode(pid, &mut ptable); 163 164 let (ut_id, ut_gen, _) = crate::tests::helpers::allocate_untyped(&ptable, false); 165 let (cnode_id, cnode_gen, depth, gv, gb) = 166 cnode::cnode_coords(pid, &ptable).expect("coords"); 167 168 { 169 let pool = POOL.lock_after(&ptable); 170 let ut_cap = CapRef::new(ObjectTag::Untyped, ut_id, Rights::ALL, ut_gen); 171 cnode::resolve_and_insert(&pool, cnode_id, cnode_gen, 900, depth, gv, gb, ut_cap) 172 .expect("insert ut"); 173 } 174 175 let rounds = 10u32; 176 (0..rounds).for_each(|round| { 177 let dest_base = 100u64; 178 let obj_count = 5u32; 179 180 { 181 let mut pool = POOL.lock_after(&ptable); 182 let result = crate::cap::retype::kernel_retype( 183 &mut pool, 184 None, 185 ut_id, 186 ut_gen, 187 ObjectTag::Endpoint, 188 0, 189 cnode_id, 190 cnode_gen, 191 dest_base, 192 depth, 193 gv, 194 gb, 195 obj_count, 196 ); 197 assert!( 198 result.is_ok(), 199 "retype round {} failed: {:?}", 200 round, 201 result.err() 202 ); 203 } 204 205 { 206 let result = crate::cap::ops::revoke_via_cnode(pid, 900, &mut ptable); 207 assert!( 208 result.is_ok(), 209 "revoke round {} failed: {:?}", 210 round, 211 result.err() 212 ); 213 } 214 }); 215 216 let mut allocator = BitmapFrameAllocator; 217 ptable.destroy(pid, &mut allocator); 218 } 219); 220 221crate::kernel_test!( 222 fn scale_10k_pid_cycles() { 223 let mut allocator = BitmapFrameAllocator; 224 let mut ptable = PROCESSES.lock(); 225 226 let rounds = 40u32; 227 let batch = 256usize; 228 229 (0..rounds).for_each(|round| { 230 let mut allocated = crate::static_vec::StaticVec::<crate::types::Pid, 256>::new(); 231 (0..batch).for_each(|_| { 232 if let Some(created) = ptable.allocate(&mut allocator) { 233 let _ = allocated.push(created.pid()); 234 } 235 }); 236 237 let count = allocated.len(); 238 assert!( 239 count >= 200, 240 "round {}: expected >= 200 PIDs, got {}", 241 round, 242 count 243 ); 244 245 allocated.as_slice().iter().for_each(|&pid| { 246 assert!( 247 ptable.get(pid).is_some(), 248 "round {}: PID {} inaccessible", 249 round, 250 pid.raw() 251 ); 252 }); 253 254 allocated.as_slice().iter().for_each(|&pid| { 255 ptable.destroy(pid, &mut allocator); 256 }); 257 }); 258 259 match ptable.allocate(&mut allocator) { 260 Some(created) => { 261 ptable.destroy(created.pid(), &mut allocator); 262 } 263 None => panic!("fresh allocation after 10K+ cycles failed"), 264 } 265 } 266); 267 268crate::kernel_test!( 269 fn scale_10k_object_cycles() { 270 let ptable = PROCESSES.lock(); 271 let mut pool = POOL.lock_after(&ptable); 272 273 let baseline = pool.active_count(); 274 275 let rounds = 40u32; 276 let batch = 256u32; 277 278 (0..rounds).for_each(|round| { 279 let mut ids = crate::static_vec::StaticVec::< 280 (crate::types::ObjPhys, crate::types::Generation), 281 256, 282 >::new(); 283 (0..batch).for_each(|i| match crate::tests::helpers::alloc_endpoint(&mut pool) { 284 Ok((eid, egen)) => { 285 let _ = ids.push((eid, egen)); 286 } 287 Err(e) => panic!("round {} alloc {}: {:?}", round, i, e), 288 }); 289 290 ids.as_slice().iter().for_each(|&(eid, egen)| { 291 if let Some((phys, _)) = pool.dec_ref_phys(eid, egen) { 292 crate::cap::kernel_objects::free_slot(phys); 293 } 294 }); 295 }); 296 297 let after = pool.active_count(); 298 assert!( 299 after == baseline, 300 "object leak after 10K+ cycles: baseline={}, after={}", 301 baseline, 302 after 303 ); 304 } 305); 306 307crate::kernel_test!( 308 fn scale_10k_retype_cycles() { 309 let mut ptable = PROCESSES.lock(); 310 let mut allocator = BitmapFrameAllocator; 311 312 let created = ptable.allocate(&mut allocator).expect("alloc proc"); 313 ptable.start(created).expect("start"); 314 let pid = created.pid(); 315 crate::tests::helpers::bootstrap_test_cnode(pid, &mut ptable); 316 317 let (ut_id, ut_gen, _) = crate::tests::helpers::allocate_small_untyped(&ptable, 16); 318 let (cnode_id, cnode_gen, depth, gv, gb) = 319 cnode::cnode_coords(pid, &ptable).expect("coords"); 320 321 { 322 let pool = POOL.lock_after(&ptable); 323 let ut_cap = CapRef::new(ObjectTag::Untyped, ut_id, Rights::ALL, ut_gen); 324 cnode::resolve_and_insert(&pool, cnode_id, cnode_gen, 900, depth, gv, gb, ut_cap) 325 .expect("insert ut"); 326 } 327 328 let rounds = 640u32; 329 let batch_size = 16u32; 330 let mut total_retyped = 0u64; 331 332 (0..rounds).for_each(|round| { 333 { 334 let mut pool = POOL.lock_after(&ptable); 335 let result = crate::cap::retype::kernel_retype( 336 &mut pool, 337 None, 338 ut_id, 339 ut_gen, 340 ObjectTag::Endpoint, 341 0, 342 cnode_id, 343 cnode_gen, 344 100, 345 depth, 346 gv, 347 gb, 348 batch_size, 349 ); 350 match result { 351 Ok(()) => { 352 total_retyped += batch_size as u64; 353 } 354 Err(KernelError::ResourceExhausted) => {} 355 Err(e) => panic!("retype round {} failed: {:?}", round, e), 356 } 357 } 358 359 { 360 let result = crate::cap::ops::revoke_via_cnode(pid, 900, &mut ptable); 361 assert!( 362 result.is_ok(), 363 "revoke round {} failed: {:?}", 364 round, 365 result.err() 366 ); 367 } 368 }); 369 370 assert!( 371 total_retyped >= 10_000, 372 "expected 10K+ cumulative retypes, got {}", 373 total_retyped 374 ); 375 376 let mut allocator = BitmapFrameAllocator; 377 ptable.destroy(pid, &mut allocator); 378 } 379); 380 381crate::kernel_test!( 382 fn exhaust_kernel_object_slots() { 383 let ptable = PROCESSES.lock(); 384 let mut pool = POOL.lock_after(&ptable); 385 386 let mut allocated = crate::static_vec::StaticVec::< 387 (crate::types::ObjPhys, crate::types::Generation, u64), 388 512, 389 >::new(); 390 let mut count = 0u32; 391 392 while let Ok((eid, egen)) = crate::tests::helpers::alloc_endpoint(&mut pool) { 393 if allocated.push((eid, egen, eid.raw())).is_err() { 394 if let Some((phys, _)) = pool.dec_ref_phys(eid, egen) { 395 crate::cap::kernel_objects::free_slot(phys); 396 } 397 break; 398 } 399 count += 1; 400 } 401 402 assert!( 403 count >= 100, 404 "expected at least 100 kernel object slots, got {}", 405 count 406 ); 407 408 allocated.as_slice().iter().for_each(|&(eid, egen, _)| { 409 if let Some((phys, _)) = pool.dec_ref_phys(eid, egen) { 410 crate::cap::kernel_objects::free_slot(phys); 411 } 412 }); 413 414 let (eid, egen) = crate::tests::helpers::alloc_endpoint(&mut pool) 415 .unwrap_or_else(|e| panic!("alloc after free-all failed: {:?}", e)); 416 if let Some((phys, _)) = pool.dec_ref_phys(eid, egen) { 417 crate::cap::kernel_objects::free_slot(phys); 418 } 419 } 420); 421 422crate::kernel_test!( 423 fn large_child_list_revoke() { 424 let mut ptable = PROCESSES.lock(); 425 let mut allocator = BitmapFrameAllocator; 426 427 let created = ptable.allocate(&mut allocator).expect("alloc proc"); 428 ptable.start(created).expect("start"); 429 let pid = created.pid(); 430 crate::tests::helpers::bootstrap_test_cnode(pid, &mut ptable); 431 432 let (ut_id, ut_gen, _) = crate::tests::helpers::allocate_small_untyped(&ptable, 20); 433 let (cnode_id, cnode_gen, depth, gv, gb) = 434 cnode::cnode_coords(pid, &ptable).expect("coords"); 435 436 { 437 let pool = POOL.lock_after(&ptable); 438 let ut_cap = CapRef::new(ObjectTag::Untyped, ut_id, Rights::ALL, ut_gen); 439 cnode::resolve_and_insert(&pool, cnode_id, cnode_gen, 900, depth, gv, gb, ut_cap) 440 .expect("insert ut"); 441 } 442 443 let mut total_children = 0u32; 444 let mut dest = 100u64; 445 let batch = 64u32; 446 loop { 447 let mut pool = POOL.lock_after(&ptable); 448 match crate::cap::retype::kernel_retype( 449 &mut pool, 450 None, 451 ut_id, 452 ut_gen, 453 ObjectTag::Endpoint, 454 0, 455 cnode_id, 456 cnode_gen, 457 dest, 458 depth, 459 gv, 460 gb, 461 batch, 462 ) { 463 Ok(()) => { 464 total_children += batch; 465 dest += batch as u64; 466 } 467 Err(KernelError::ResourceExhausted) => break, 468 Err(KernelError::SlotOccupied) => break, 469 Err(e) => panic!("retype failed at dest {}: {:?}", dest, e), 470 } 471 } 472 473 assert!( 474 total_children > 100, 475 "expected > 100 children from 1MB untyped, got {}", 476 total_children 477 ); 478 479 { 480 let result = crate::cap::ops::revoke_via_cnode(pid, 900, &mut ptable); 481 assert!(result.is_ok(), "revoke failed: {:?}", result.err()); 482 } 483 484 { 485 let pool = POOL.lock_after(&ptable); 486 let ut = pool 487 .read_as::<lancer_core::object_layout::UntypedObject>(ut_id, ut_gen) 488 .expect("untyped still valid"); 489 assert!( 490 ut.watermark == 0, 491 "watermark must reset after revoke, got {}", 492 ut.watermark 493 ); 494 assert!( 495 ut.child_count == 0, 496 "child_count must be 0 after revoke, got {}", 497 ut.child_count 498 ); 499 } 500 501 let mut allocator = BitmapFrameAllocator; 502 ptable.destroy(pid, &mut allocator); 503 } 504); 505 506crate::kernel_test!( 507 fn object_id_recycling_generation_increases() { 508 let ptable = PROCESSES.lock(); 509 let mut pool = POOL.lock_after(&ptable); 510 511 let mut last_gen_by_slot = crate::static_vec::StaticVec::<(u64, u32), 256>::new(); 512 513 let cycles = 100u32; 514 (0..cycles).for_each(|round| { 515 let (eid, egen) = crate::tests::helpers::alloc_endpoint(&mut pool) 516 .unwrap_or_else(|e| panic!("alloc round {}: {:?}", round, e)); 517 518 let raw_id = eid.raw(); 519 let gen_val = egen.raw(); 520 521 let existing = last_gen_by_slot 522 .as_mut_slice() 523 .iter_mut() 524 .find(|(slot_id, _)| *slot_id == raw_id); 525 526 match existing { 527 Some(entry) => { 528 assert!( 529 gen_val > entry.1, 530 "round {}: slot {} gen {} not > prev gen {}", 531 round, 532 raw_id, 533 gen_val, 534 entry.1 535 ); 536 entry.1 = gen_val; 537 } 538 None => { 539 let _ = last_gen_by_slot.push((raw_id, gen_val)); 540 } 541 } 542 543 if let Some((phys, _)) = pool.dec_ref_phys(eid, egen) { 544 crate::cap::kernel_objects::free_slot(phys); 545 } 546 }); 547 } 548); 549 550crate::kernel_test!( 551 fn interleaved_retype_revoke_heavy() { 552 let mut ptable = PROCESSES.lock(); 553 let mut allocator = BitmapFrameAllocator; 554 555 let created = ptable.allocate(&mut allocator).expect("alloc proc"); 556 ptable.start(created).expect("start"); 557 let pid = created.pid(); 558 crate::tests::helpers::bootstrap_test_cnode(pid, &mut ptable); 559 560 let (ut_id, ut_gen, _) = crate::tests::helpers::allocate_untyped(&ptable, false); 561 let (cnode_id, cnode_gen, depth, gv, gb) = 562 cnode::cnode_coords(pid, &ptable).expect("coords"); 563 564 { 565 let pool = POOL.lock_after(&ptable); 566 let ut_cap = CapRef::new(ObjectTag::Untyped, ut_id, Rights::ALL, ut_gen); 567 cnode::resolve_and_insert(&pool, cnode_id, cnode_gen, 900, depth, gv, gb, ut_cap) 568 .expect("insert ut"); 569 } 570 571 let rounds = 100u32; 572 (0..rounds).for_each(|round| { 573 { 574 let mut pool = POOL.lock_after(&ptable); 575 let result = crate::cap::retype::kernel_retype( 576 &mut pool, 577 None, 578 ut_id, 579 ut_gen, 580 ObjectTag::Endpoint, 581 0, 582 cnode_id, 583 cnode_gen, 584 100, 585 depth, 586 gv, 587 gb, 588 5, 589 ); 590 assert!( 591 result.is_ok(), 592 "retype round {} failed: {:?}", 593 round, 594 result.err() 595 ); 596 } 597 598 { 599 let result = crate::cap::ops::revoke_via_cnode(pid, 900, &mut ptable); 600 assert!( 601 result.is_ok(), 602 "revoke round {} failed: {:?}", 603 round, 604 result.err() 605 ); 606 } 607 }); 608 609 { 610 let pool = POOL.lock_after(&ptable); 611 let ut = pool 612 .read_as::<lancer_core::object_layout::UntypedObject>(ut_id, ut_gen) 613 .expect("untyped valid"); 614 assert!(ut.watermark == 0, "watermark leak after 100 rounds"); 615 assert!(ut.child_count == 0, "child leak after 100 rounds"); 616 } 617 618 let mut allocator = BitmapFrameAllocator; 619 ptable.destroy(pid, &mut allocator); 620 } 621); 622 623crate::kernel_test!( 624 fn mixed_tag_retype_revoke() { 625 let mut ptable = PROCESSES.lock(); 626 let mut allocator = BitmapFrameAllocator; 627 628 let created = ptable.allocate(&mut allocator).expect("alloc proc"); 629 ptable.start(created).expect("start"); 630 let pid = created.pid(); 631 crate::tests::helpers::bootstrap_test_cnode(pid, &mut ptable); 632 633 let (ut_id, ut_gen, _) = crate::tests::helpers::allocate_untyped(&ptable, false); 634 let (cnode_id, cnode_gen, depth, gv, gb) = 635 cnode::cnode_coords(pid, &ptable).expect("coords"); 636 637 { 638 let pool = POOL.lock_after(&ptable); 639 let ut_cap = CapRef::new(ObjectTag::Untyped, ut_id, Rights::ALL, ut_gen); 640 cnode::resolve_and_insert(&pool, cnode_id, cnode_gen, 900, depth, gv, gb, ut_cap) 641 .expect("insert ut"); 642 } 643 644 { 645 let mut pool = POOL.lock_after(&ptable); 646 647 let ep_result = crate::cap::retype::kernel_retype( 648 &mut pool, 649 None, 650 ut_id, 651 ut_gen, 652 ObjectTag::Endpoint, 653 0, 654 cnode_id, 655 cnode_gen, 656 100, 657 depth, 658 gv, 659 gb, 660 10, 661 ); 662 assert!( 663 ep_result.is_ok(), 664 "retype endpoints failed: {:?}", 665 ep_result.err() 666 ); 667 668 let notif_result = crate::cap::retype::kernel_retype( 669 &mut pool, 670 None, 671 ut_id, 672 ut_gen, 673 ObjectTag::Notification, 674 0, 675 cnode_id, 676 cnode_gen, 677 110, 678 depth, 679 gv, 680 gb, 681 10, 682 ); 683 assert!( 684 notif_result.is_ok(), 685 "retype notifications failed: {:?}", 686 notif_result.err() 687 ); 688 689 let sched_result = crate::cap::retype::kernel_retype( 690 &mut pool, 691 None, 692 ut_id, 693 ut_gen, 694 ObjectTag::SchedContext, 695 0, 696 cnode_id, 697 cnode_gen, 698 120, 699 depth, 700 gv, 701 gb, 702 5, 703 ); 704 assert!( 705 sched_result.is_ok(), 706 "retype sched contexts failed: {:?}", 707 sched_result.err() 708 ); 709 } 710 711 { 712 let pool = POOL.lock_after(&ptable); 713 let ut = pool 714 .read_as::<lancer_core::object_layout::UntypedObject>(ut_id, ut_gen) 715 .expect("untyped valid"); 716 assert!( 717 ut.child_count == 25, 718 "expected 25 children, got {}", 719 ut.child_count 720 ); 721 } 722 723 { 724 let result = crate::cap::ops::revoke_via_cnode(pid, 900, &mut ptable); 725 assert!(result.is_ok(), "revoke failed: {:?}", result.err()); 726 } 727 728 { 729 let pool = POOL.lock_after(&ptable); 730 let ut = pool 731 .read_as::<lancer_core::object_layout::UntypedObject>(ut_id, ut_gen) 732 .expect("untyped valid after revoke"); 733 assert!(ut.watermark == 0, "watermark must reset"); 734 assert!(ut.child_count == 0, "child_count must be 0"); 735 } 736 737 let mut allocator = BitmapFrameAllocator; 738 ptable.destroy(pid, &mut allocator); 739 } 740); 741 742crate::kernel_test!( 743 fn nested_untyped_retype_then_revoke_parent() { 744 let mut ptable = PROCESSES.lock(); 745 let mut allocator = BitmapFrameAllocator; 746 747 let created = ptable.allocate(&mut allocator).expect("alloc proc"); 748 ptable.start(created).expect("start"); 749 let pid = created.pid(); 750 crate::tests::helpers::bootstrap_test_cnode(pid, &mut ptable); 751 752 let (parent_ut_id, parent_ut_gen, _) = 753 crate::tests::helpers::allocate_untyped(&ptable, false); 754 let (cnode_id, cnode_gen, depth, gv, gb) = 755 cnode::cnode_coords(pid, &ptable).expect("coords"); 756 757 let child_size_bits = 14u8; 758 let child_frames = 1usize << (child_size_bits - 12); 759 let child_phys = BitmapFrameAllocator 760 .allocate_contiguous(child_frames) 761 .expect("alloc child untyped backing"); 762 let child_virt = crate::mem::addr::phys_to_virt(child_phys); 763 unsafe { 764 core::ptr::write_bytes(child_virt.as_mut_ptr::<u8>(), 0, child_frames * 4096); 765 } 766 767 let header = lancer_core::header::KernelObjectHeader::new(ObjectTag::Untyped, 0, 64); 768 let mut child_ut = lancer_core::object_layout::UntypedObject::init_default(header); 769 child_ut.phys_base = child_phys.as_u64(); 770 child_ut.size_bits = child_size_bits; 771 child_ut.is_device = 0; 772 let child_slot_phys = 773 crate::cap::kernel_objects::alloc_slot().expect("alloc child ut slot"); 774 crate::cap::kernel_objects::write_at(child_slot_phys, child_ut); 775 776 let (child_ut_id, child_ut_gen) = { 777 let mut pool = POOL.lock_after(&ptable); 778 let (cid, cgen) = pool 779 .register_object(child_slot_phys, ObjectTag::Untyped) 780 .expect("register child ut"); 781 crate::cap::derivation::link_child(&mut pool, parent_ut_id, parent_ut_gen, cid) 782 .expect("link child untyped to parent"); 783 let cap = CapRef::new(ObjectTag::Untyped, cid, Rights::ALL, cgen); 784 cnode::resolve_and_insert(&pool, cnode_id, cnode_gen, 80, depth, gv, gb, cap) 785 .expect("insert child untyped cap"); 786 (cid, cgen) 787 }; 788 789 { 790 let mut pool = POOL.lock_after(&ptable); 791 crate::cap::retype::kernel_retype( 792 &mut pool, 793 None, 794 child_ut_id, 795 child_ut_gen, 796 ObjectTag::Endpoint, 797 0, 798 cnode_id, 799 cnode_gen, 800 81, 801 depth, 802 gv, 803 gb, 804 3, 805 ) 806 .expect("retype endpoints from child untyped"); 807 } 808 809 let ep_ids: [(crate::types::ObjPhys, crate::types::Generation); 3] = { 810 let pool = POOL.lock_after(&ptable); 811 let c0 = cnode::resolve_and_read(&pool, cnode_id, cnode_gen, 81, depth, gv, gb) 812 .expect("ep0"); 813 let c1 = cnode::resolve_and_read(&pool, cnode_id, cnode_gen, 82, depth, gv, gb) 814 .expect("ep1"); 815 let c2 = cnode::resolve_and_read(&pool, cnode_id, cnode_gen, 83, depth, gv, gb) 816 .expect("ep2"); 817 [ 818 (c0.phys(), c0.generation()), 819 (c1.phys(), c1.generation()), 820 (c2.phys(), c2.generation()), 821 ] 822 }; 823 824 { 825 let mut pool = POOL.lock_after(&ptable); 826 crate::cap::derivation::destroy_children( 827 &mut pool, 828 &mut ptable, 829 parent_ut_id, 830 parent_ut_gen, 831 ) 832 .expect("destroy_children on parent"); 833 } 834 835 { 836 let pool = POOL.lock_after(&ptable); 837 let ut = pool 838 .read_as::<lancer_core::object_layout::UntypedObject>(parent_ut_id, parent_ut_gen) 839 .expect("parent untyped valid"); 840 assert!(ut.watermark == 0, "parent watermark must reset"); 841 assert!(ut.child_count == 0, "parent child_count must be 0"); 842 843 assert!( 844 pool.get_tag(child_ut_id, child_ut_gen).is_err(), 845 "child untyped must be destroyed" 846 ); 847 848 ep_ids.iter().for_each(|&(eid, egen)| { 849 assert!( 850 pool.get_tag(eid, egen).is_err(), 851 "grandchild endpoint must be destroyed" 852 ); 853 }); 854 } 855 856 let mut allocator = BitmapFrameAllocator; 857 ptable.destroy(pid, &mut allocator); 858 } 859); 860 861crate::kernel_test!( 862 fn retype_after_revoke_with_stale_gen() { 863 let ptable = PROCESSES.lock(); 864 let mut pool = POOL.lock_after(&ptable); 865 866 let (ep_id, ep_gen) = 867 crate::tests::helpers::alloc_endpoint(&mut pool).expect("alloc endpoint"); 868 let stale_gen = ep_gen; 869 870 let (_new_gen, _old_phys_tag) = pool.revoke_phys(ep_id, ep_gen).expect("revoke endpoint"); 871 872 let result = pool.get_tag(ep_id, stale_gen); 873 assert!( 874 matches!(result, Err(KernelError::StaleGeneration)), 875 "accessing revoked object with stale gen should return StaleGeneration, got {:?}", 876 result 877 ); 878 879 let new_gen_val = pool.generation_of(ep_id); 880 assert!( 881 new_gen_val.is_none(), 882 "revoked slot should not report as active" 883 ); 884 } 885);