use page_table_generic::*;
mod mocks;
use mocks::*;
#[test]
fn test_translate_basic() {
let mut pg = PageTable::<T4kL3, Fram4k>::new(Fram4k).unwrap();
pg.map(&MapConfig {
vaddr: 0x1000usize.into(),
paddr: 0x2000usize.into(),
size: 0x1000,
pte: PteImpl::user_mode_config(),
allow_huge: false,
flush: false,
})
.unwrap();
let translated_addr = pg.translate_phys(0x1000usize.into()).unwrap();
assert_eq!(translated_addr, 0x2000usize.into(), "地址翻译失败");
let translated_addr = pg.translate_phys(0x1001usize.into()).unwrap();
assert_eq!(translated_addr, 0x2001usize.into(), "地址偏移翻译失败");
let result = pg.translate(0x2000usize.into());
assert!(result.is_err(), "未映射地址应该返回错误");
let (_, pte) = pg.translate(0x1000usize.into()).unwrap();
assert!(pte.to_config(false).valid, "翻译的页表项应该有效");
assert_eq!(
pte.to_config(false).paddr,
0x2000usize.into(),
"页表项的物理地址应该正确"
);
}
#[test]
fn test_translate_huge_page() {
let mut pg = PageTable::<T4kL3, Fram4k>::new(Fram4k).unwrap();
pg.map(&MapConfig {
vaddr: 0usize.into(),
paddr: 0usize.into(), size: 2 * MB,
pte: PteImpl::user_mode_config(),
allow_huge: true,
flush: false,
})
.unwrap();
let test_cases = vec![
(0x0, 0x0), (0x1000, 0x1000), (0x100000, 0x100000), (0x1FF000, 0x1FF000), ];
for (vaddr, expected_paddr) in test_cases {
let result = pg.translate_phys((vaddr as usize).into());
match result {
Ok(translated) => {
assert_eq!(
translated,
(expected_paddr as usize).into(),
"大页地址翻译失败: vaddr={:#x}, expected={:#x}, got={:#x}",
vaddr,
expected_paddr,
translated.raw()
);
}
Err(e) => {
panic!("地址翻译失败: vaddr={:#x}, error={:?}", vaddr, e);
}
}
let (_, pte) = pg.translate((vaddr as usize).into()).unwrap();
assert!(pte.to_config(false).valid, "大页页表项应该有效");
assert!(pte.to_config(false).huge, "大页页表项应该设置huge标志");
if vaddr == 0x1000 {
println!(
"DEBUG: vaddr=0x{:x}, PTE paddr=0x{:x}",
vaddr,
pte.to_config(false).paddr.raw()
);
}
}
let result = pg.translate((2 * MB).into());
assert!(result.is_err(), "大页范围外的地址应该返回错误");
let result = pg.translate_phys((2 * MB).into());
assert!(result.is_err(), "大页范围外的地址应该返回错误");
}
#[test]
fn test_translate_multiple_mappings() {
let mut pg = PageTable::<T4kL3, Fram4k>::new(Fram4k).unwrap();
pg.map(&MapConfig {
vaddr: 0x1000usize.into(),
paddr: 0x2000usize.into(),
size: 0x1000,
pte: PteImpl::user_mode_config(),
allow_huge: false,
flush: false,
})
.unwrap();
pg.map(&MapConfig {
vaddr: 0x2000usize.into(),
paddr: 0x4000usize.into(),
size: 0x1000,
pte: PteImpl::user_mode_config(),
allow_huge: false,
flush: false,
})
.unwrap();
pg.map(&MapConfig {
vaddr: 0x200000usize.into(), paddr: 0x200000usize.into(), size: 2 * MB,
pte: PteImpl::user_mode_config(),
allow_huge: true,
flush: false,
})
.unwrap();
assert_eq!(
pg.translate_phys(0x1000usize.into()).unwrap(),
0x2000usize.into()
);
assert_eq!(
pg.translate_phys(0x2000usize.into()).unwrap(),
0x4000usize.into()
);
let result = pg.translate_phys(0x200000usize.into()).unwrap();
let (_, pte) = pg.translate(0x200000usize.into()).unwrap();
if pte.to_config(false).huge {
let expected = pte.to_config(false).paddr.raw() + (0x200000 % (2 * MB));
assert_eq!(result.raw(), expected);
} else {
let expected = pte.to_config(false).paddr.raw() + (0x200000 % 0x1000);
assert_eq!(result.raw(), expected);
}
let result = pg.translate_phys(0x250000usize.into()).unwrap();
let (_, pte) = pg.translate(0x250000usize.into()).unwrap();
if pte.to_config(false).huge {
let expected = pte.to_config(false).paddr.raw() + (0x250000 % (2 * MB));
assert_eq!(result.raw(), expected);
} else {
let expected = pte.to_config(false).paddr.raw() + (0x250000 % 0x1000);
assert_eq!(result.raw(), expected);
}
let (_, pte1) = pg.translate(0x1000usize.into()).unwrap();
assert!(pte1.to_config(false).valid && !pte1.to_config(false).huge);
let (_, pte2) = pg.translate(0x200000usize.into()).unwrap();
assert!(pte2.to_config(false).valid);
assert!(pg.translate(0x3000usize.into()).is_err());
assert!(pg.translate(0x80000usize.into()).is_err());
assert!(pg.translate_phys(0x3000usize.into()).is_err());
assert!(pg.translate_phys(0x80000usize.into()).is_err());
}
#[test]
fn test_is_mapped() {
let mut pg = PageTable::<T4kL3, Fram4k>::new(Fram4k).unwrap();
pg.map(&MapConfig {
vaddr: 0x1000usize.into(),
paddr: 0x2000usize.into(),
size: 0x1000,
pte: PteImpl::user_mode_config(),
allow_huge: false,
flush: false,
})
.unwrap();
assert!(pg.is_mapped(0x1000usize.into()));
assert!(pg.is_mapped(0x1FFFusize.into()));
assert!(!pg.is_mapped(0x0usize.into()));
assert!(!pg.is_mapped(0x2000usize.into()));
assert!(!pg.is_mapped(0x10000usize.into()));
}
#[test]
fn test_translate_complex_layout() {
let mut pg = PageTable::<T4kL3, Fram4k>::new(Fram4k).unwrap();
pg.map(&MapConfig {
vaddr: 0usize.into(),
paddr: 0usize.into(),
size: 2 * MB + 0x1000 * 3, pte: PteImpl::user_mode_config(),
allow_huge: true,
flush: false,
})
.unwrap();
for i in 0..(2 * MB / 0x1000) {
let vaddr = i * 0x1000;
let translated = pg.translate_phys(vaddr.into()).unwrap();
assert_eq!(
translated,
vaddr.into(),
"2MB大页内地址翻译失败: vaddr={:#x}",
vaddr
);
let (_, pte) = pg.translate(vaddr.into()).unwrap();
assert!(
pte.to_config(false).valid && pte.to_config(false).huge,
"大页区域应该返回大页页表项"
);
}
for i in 0..3 {
let vaddr = 2 * MB + i * 0x1000;
let translated = pg.translate_phys(vaddr.into()).unwrap();
let (_, pte) = pg.translate(vaddr.into()).unwrap();
if pte.to_config(false).huge {
let expected = pte.to_config(false).paddr.raw() + (vaddr % (2 * MB));
assert_eq!(
translated.raw(),
expected,
"大页映射翻译失败: vaddr={:#x}, expected={:#x}, got={:#x}",
vaddr,
expected,
translated.raw()
);
} else {
let expected = pte.to_config(false).paddr.raw() + (vaddr % 0x1000);
assert_eq!(
translated.raw(),
expected,
"普通页面映射翻译失败: vaddr={:#x}, expected={:#x}, got={:#x}",
vaddr,
expected,
translated.raw()
);
}
}
let end_vaddr = 2 * MB + 3 * 0x1000;
assert!(
pg.translate(end_vaddr.into()).is_err(),
"映射范围外的地址应该返回错误"
);
assert!(
pg.translate_phys(end_vaddr.into()).is_err(),
"映射范围外的地址应该返回错误"
);
}
#[test]
fn test_translate_error_cases() {
let mut pg = PageTable::<T4kL3, Fram4k>::new(Fram4k).unwrap();
let result = pg.translate(0x1000usize.into());
assert!(result.is_err(), "空页表应该返回错误");
assert!(matches!(result.unwrap_err(), PagingError::NotMapped));
let result = pg.translate_phys(0x1000usize.into());
assert!(result.is_err(), "空页表物理翻译应该返回错误");
pg.map(&MapConfig {
vaddr: 0x1000usize.into(),
paddr: 0x2000usize.into(),
size: 0x1000,
pte: PteImpl::user_mode_config(),
allow_huge: false,
flush: false,
})
.unwrap();
assert!(pg.translate(0x1000usize.into()).is_ok());
assert!(pg.translate(0x1FFFusize.into()).is_ok());
assert!(pg.translate_phys(0x1000usize.into()).is_ok());
assert!(pg.translate_phys(0x1FFFusize.into()).is_ok());
assert!(pg.translate(0x0usize.into()).is_err());
assert!(pg.translate(0x2000usize.into()).is_err());
assert!(pg.translate(0x3000usize.into()).is_err());
assert!(pg.translate_phys(0x0usize.into()).is_err());
assert!(pg.translate_phys(0x2000usize.into()).is_err());
assert!(pg.translate_phys(0x3000usize.into()).is_err());
}
#[test]
fn test_translate_performance() {
let mut pg = PageTable::<T4kL3, Fram4k>::new(Fram4k).unwrap();
for i in 0..10 {
pg.map(&MapConfig {
vaddr: (i * 0x10000usize).into(),
paddr: (i * 0x10000usize).into(),
size: 0x10000,
pte: PteImpl::user_mode_config(),
allow_huge: false,
flush: false,
})
.unwrap();
}
for i in 0..10 {
let vaddr = i * 0x10000 + 0x1000;
let result = pg.translate_phys(vaddr.into());
assert!(result.is_ok(), "地址翻译应该成功: vaddr={:#x}", vaddr);
assert_eq!(result.unwrap(), vaddr.into(), "翻译结果应该正确");
let (_, pte) = pg.translate(vaddr.into()).unwrap();
assert!(pte.to_config(false).valid, "页表项应该有效");
}
}