moa_mm 0.1.3

内存管理基础(页表、虚拟地址布局)
Documentation
//! `AArch64` 页表编解码

use super::{PAGE_SHIFT, PGD_MASK, PGD_SHIFT, PGD_SIZE, PTRS_PER_TABLE, PageLevel, PageProt};

const PA_BITS: usize = 48;

// ---- 内存类型 ----

/// nGnRnE
#[allow(non_upper_case_globals)]
pub const MT_DEVICE_nGnRnE: usize = 0;
/// nGnRE
#[allow(non_upper_case_globals)]
pub const MT_DEVICE_nGnRE: usize = 1;
/// GRE
pub const MT_DEVICE_GRE: usize = 2;
/// NC
pub const MT_NORMAL_NC: usize = 3;
/// NORMAL
pub const MT_NORMAL: usize = 4;
/// WT
pub const MT_NORMAL_WT: usize = 5;

/// 内存域属性
///
/// Memory region attributes for LPAE:
///
/// ```text
///  n = AttrIndx[2:0]
///      n   MAIR
///  DEVICE_nGnRnE   000    00000000
///  DEVICE_nGnRE    001    00000100
///  DEVICE_GRE      010    00001100
///  NORMAL_NC       011    01000100
///  NORMAL          100    11111111
///  NORMAL_WT       101    10111011
/// ```
pub const MAIR_ATTR: usize = (0x04 << (MT_DEVICE_nGnRE * 8))
    | (0x0c << (MT_DEVICE_GRE * 8))
    | (0x44 << (MT_NORMAL_NC * 8))
    | (0xff << (MT_NORMAL * 8))
    | (0xbb << (MT_NORMAL_WT * 8));

// ---- MMU / 页表(VA39 三级:PGD 1GB → PMD 2MB → PTE 4KB) ----

/// pgd 页表 table descriptor type
pub const PGD_TYPE_TABLE: usize = 3;
/// pgd 页表特权级不可执行
pub const PGD_TABLE_PXN: usize = 1 << 59;
/// pgd 页表非特权级不可执行
pub const PGD_TABLE_UXN: usize = 1 << 60;
/// pgd 段描述符(1GB block)
pub const PGD_TYPE_SECT: usize = 1 << 0;
/// pgd Access Flag
pub const PGD_SECT_AF: usize = 1 << 10;
/// pgd Inner Shareable
pub const PGD_SECT_S: usize = 3 << 8;
/// pgd Privileged eXecute Never
pub const PGD_SECT_PXN: usize = 1 << 53;
/// pgd 1GB block 基础 flags(块描述符 + AF + Inner Shareable)
pub const SWAPPER_PGD_FLAGS: usize = PGD_TYPE_SECT | PGD_SECT_AF | PGD_SECT_S;
/// 内核代码映射 flags:Normal, 可读写可执行
pub const SWAPPER_MM_NORMALFLAGS: usize = (MT_NORMAL << 2) | SWAPPER_PGD_FLAGS;
/// 内核数据映射 flags:Normal, 可读写不可执行
pub const SWAPPER_MM_NORMAL_PXN_FLAGS: usize = (MT_NORMAL << 2) | SWAPPER_PGD_FLAGS | PGD_SECT_PXN;
/// IO 映射 flags:Device-nGnRE, 不可执行
pub const SWAPPER_MM_IOFLAGS: usize = (MT_DEVICE_nGnRE << 2) | SWAPPER_PGD_FLAGS | PGD_SECT_PXN;

// VA39 下 PUD 与 PGD 是同一级(兼容运行时页表代码)
/// PUD table descriptor type
pub const PUD_TYPE_TABLE: usize = PGD_TYPE_TABLE;
/// PUD 特权级不可执行
pub const PUD_TABLE_PXN: usize = 1 << 59;
/// PUD 非特权级不可执行
pub const PUD_TABLE_UXN: usize = 1 << 58;
/// PUD 偏移(= `PGD_SHIFT`)
pub const PUD_SHIFT: usize = PGD_SHIFT;
/// PUD 大小(= `PGD_SIZE`)
pub const PUD_SIZE: usize = PGD_SIZE;
/// PUD 掩码(= `PGD_MASK`)
pub const PUD_MASK: usize = PGD_MASK;
/// PUD entry 数量
pub const PTRS_PER_PUD: usize = PTRS_PER_PGD;

/// pmd 页表 type
pub const PMD_TYPE_TABLE: usize = 3;
/// pmd 页表特权级不可执行
pub const PMD_TABLE_PXN: usize = 1 << 59;
/// pmd 页表非特权级不可执行
pub const PMD_TABLE_UXN: usize = 1 << 58;

/// pgd entry 数量
pub const PTRS_PER_PGD: usize = PTRS_PER_TABLE;
/// pmd entry 数量
pub const PTRS_PER_PMD: usize = PTRS_PER_TABLE;
/// pte entry 数量
pub const PTRS_PER_PTE: usize = PTRS_PER_TABLE;

// ---- 描述符类型位 ----

const DESC_TABLE: usize = 0b11;
const DESC_BLOCK: usize = 0b01;
const DESC_PAGE: usize = 0b11;
const DESC_VALID: usize = 0b01;

// ---- PTE 属性位 ----

const PTE_USER: usize = 1 << 6; // AP[1]
const PTE_RDONLY: usize = 1 << 7; // AP[2]
const PTE_SHARED: usize = 3 << 8; // SH[1:0], inner shareable
const PTE_AF: usize = 1 << 10; // Access Flag
const PTE_NG: usize = 1 << 11; // nG
const PTE_DBM: usize = 1 << 51; // Dirty Bit Management
const PTE_PXN: usize = 1 << 53; // Privileged eXecute Never
const PTE_UXN: usize = 1 << 54; // User eXecute Never

const PTE_WRITE: usize = PTE_DBM;

const fn attrindx(t: usize) -> usize {
    t << 2
}

// ---- 地址掩码 ----

const ADDR_MASK: usize = ((1usize << (PA_BITS - PAGE_SHIFT)) - 1) << PAGE_SHIFT;

// ---- table pointer 编解码 ----

#[inline(always)]
pub(crate) fn paddr_to_table(paddr: usize) -> usize {
    debug_assert_eq!(paddr & !ADDR_MASK, 0);
    paddr | DESC_TABLE
}

#[inline(always)]
pub(crate) fn table_to_paddr(entry: usize) -> usize {
    entry & ADDR_MASK
}

// ---- leaf 编解码 ----

#[inline(always)]
pub(crate) fn paddr_to_leaf(paddr: usize, prot: PageProt, level: PageLevel) -> usize {
    let desc_type = match level {
        PageLevel::Page4K => DESC_PAGE,
        PageLevel::Page2M | PageLevel::Page1G => DESC_BLOCK,
    };
    let attr = prot_to_attr(prot);
    (paddr & ADDR_MASK) | attr | desc_type
}

#[inline(always)]
pub(crate) fn leaf_to_paddr(entry: usize) -> usize {
    entry & ADDR_MASK
}

// ---- valid / leaf 判定 ----

#[inline(always)]
pub(crate) fn entry_is_valid(entry: usize) -> bool {
    entry & DESC_VALID != 0
}

#[inline(always)]
pub(crate) fn entry_is_leaf(entry: usize) -> bool {
    entry & DESC_VALID != 0 && entry & 0b10 == 0
}

// ---- PageProt → 硬件属性位(const 查找表) ----

// 索引: PageProt 低 4 位 [U:X:W:R]
//   bit0 = R, bit1 = W, bit2 = X, bit3 = U

const BASE: usize = PTE_AF | PTE_SHARED;

#[allow(clippy::fn_params_excessive_bools, clippy::if_not_else)]
const fn mk_normal(bits: usize) -> usize {
    let wr = bits & 2 != 0;
    let ex = bits & 4 != 0;
    let us = bits & 8 != 0;
    let mut attr = BASE | attrindx(MT_NORMAL);
    if us {
        attr |= PTE_USER | PTE_NG;
    }
    if wr {
        attr |= PTE_WRITE;
    } else {
        attr |= PTE_RDONLY;
    }
    if !ex {
        attr |= PTE_PXN | PTE_UXN;
    } else if !us {
        attr |= PTE_UXN;
    }
    attr
}

#[allow(clippy::fn_params_excessive_bools, clippy::if_not_else)]
const fn mk_device(bits: usize) -> usize {
    let wr = bits & 2 != 0;
    let us = bits & 8 != 0;
    let mut attr = BASE | attrindx(MT_DEVICE_nGnRE) | PTE_UXN | PTE_PXN;
    if us {
        attr |= PTE_USER | PTE_NG;
    }
    if wr {
        attr |= PTE_WRITE;
    } else {
        attr |= PTE_RDONLY;
    }
    attr
}

const fn build_table(device: bool) -> [usize; 16] {
    let mut table = [0usize; 16];
    let mut idx = 0usize;
    while idx < 16 {
        table[idx] = if device { mk_device(idx) } else { mk_normal(idx) };
        idx += 1;
    }
    table
}

const NORMAL_TABLE: [usize; 16] = build_table(false);
const DEVICE_TABLE: [usize; 16] = build_table(true);

#[inline(always)]
fn prot_to_attr(prot: PageProt) -> usize {
    let idx = prot.bits() & 0xF;
    if prot.contains(PageProt::IO) { DEVICE_TABLE[idx] } else { NORMAL_TABLE[idx] }
}