use x86_64::structures::paging::page_table::PageTableFlags; crate::kernel_test!( fn boot_pml4_is_nonzero() { let phys = crate::proc::address_space::boot_pml4_phys(); assert!(phys.as_u64() != 0, "boot PML4 physical address is zero"); } ); crate::kernel_test!( fn user_pml4_kernel_entries_cloned() { let mut allocator = crate::mem::phys::BitmapFrameAllocator; let user_phys = crate::proc::address_space::create_user_pml4(&mut allocator) .expect("failed to allocate user PML4"); let boot_phys = crate::proc::address_space::boot_pml4_phys(); let hhdm = crate::mem::addr::hhdm_offset(); let boot_table = unsafe { &*x86_64::VirtAddr::new(boot_phys.as_u64() + hhdm) .as_ptr::() }; let user_table = unsafe { &*x86_64::VirtAddr::new(user_phys.as_u64() + hhdm) .as_ptr::() }; let mismatch = (256..512) .filter(|&i| { let boot_entry = &boot_table[i]; let user_entry = &user_table[i]; let expected_flags = boot_entry.flags() & !PageTableFlags::USER_ACCESSIBLE; boot_entry.addr() != user_entry.addr() || user_entry.flags() != expected_flags }) .count(); assert!( mismatch == 0, "{} kernel PML4 entries (256..512) differ between boot and user tables", mismatch ); let user_accessible_count = (256..512) .filter(|&i| { user_table[i] .flags() .contains(PageTableFlags::USER_ACCESSIBLE) }) .count(); assert!( user_accessible_count == 0, "{} kernel PML4 entries in user table have USER_ACCESSIBLE set", user_accessible_count ); crate::mem::phys::BitmapFrameAllocator.deallocate_frame( x86_64::structures::paging::PhysFrame::containing_address(user_phys), ); } ); crate::kernel_test!( fn user_pml4_user_half_empty() { let mut allocator = crate::mem::phys::BitmapFrameAllocator; let user_phys = crate::proc::address_space::create_user_pml4(&mut allocator) .expect("failed to allocate user PML4"); let hhdm = crate::mem::addr::hhdm_offset(); let user_table = unsafe { &*x86_64::VirtAddr::new(user_phys.as_u64() + hhdm) .as_ptr::() }; let present_count = (0..256) .filter(|&i| user_table[i].flags().contains(PageTableFlags::PRESENT)) .count(); assert!( present_count == 0, "{} user-half PML4 entries (0..256) are present in a fresh address space", present_count ); crate::mem::phys::BitmapFrameAllocator.deallocate_frame( x86_64::structures::paging::PhysFrame::containing_address(user_phys), ); } ); crate::kernel_test!( fn pml4_phys_round_trip() { let mut allocator = crate::mem::phys::BitmapFrameAllocator; let raw_phys = crate::proc::address_space::create_user_pml4(&mut allocator) .expect("failed to allocate user PML4"); let typed = crate::mem::typed_addr::Pml4Phys::from_create(raw_phys); let extracted = typed.raw(); assert!( extracted == raw_phys, "Pml4Phys round-trip failed: raw={:#x}, extracted={:#x}", raw_phys.as_u64(), extracted.as_u64() ); assert!( raw_phys.as_u64() != 0, "PML4 physical address must be non-zero" ); assert!( raw_phys.as_u64() & 0xFFF == 0, "PML4 physical address must be page-aligned, got {:#x}", raw_phys.as_u64() ); crate::mem::phys::BitmapFrameAllocator.deallocate_frame( x86_64::structures::paging::PhysFrame::containing_address(raw_phys), ); } ); crate::kernel_test!( fn unmap_unmapped_via_pml4_phys_returns_error() { let mut allocator = crate::mem::phys::BitmapFrameAllocator; let mut ptable = crate::proc::PROCESSES.lock(); let created = ptable.allocate(&mut allocator).expect("alloc process"); let pid = created.pid(); let pml4 = ptable.exec(pid).unwrap().pml4_phys; drop(ptable); let virt = x86_64::VirtAddr::new(0x0000_6000_0000_0000); let result = crate::proc::address_space::unmap_user_page(pml4, virt); assert!( result == Err(crate::error::KernelError::InvalidAddress), "unmapping a never-mapped page via Pml4Phys must return InvalidAddress, got {:?}", result ); let mut ptable = crate::proc::PROCESSES.lock(); ptable.destroy(pid, &mut crate::mem::phys::BitmapFrameAllocator); } ); crate::kernel_test!( fn process_zero_exists_and_runnable() { let ptable = crate::proc::PROCESSES.lock(); let pid0 = crate::types::Pid::new(0); let proc0 = ptable.get(pid0).expect("process 0 does not exist"); assert!( proc0.is_runnable(), "process 0 is not runnable (state: {:?})", proc0.state() ); } );