moa_memops 0.5.0

底层内存操作(clear_page 等)
Documentation
use core::arch::naked_asm;

#[cfg(riscv64_moana)]
#[unsafe(naked)]
#[unsafe(no_mangle)]
extern "C" fn clear_page(addr: usize) {
    // 对标 Linux riscv `clear_page` 的非 Zicboz fallback:8 路展开,每轮清 64 字节,
    // 摊薄分支开销(4K 页迭代 512 → 64 次)。PAGE_SIZE 是 64 的整数倍且页首对齐,安全。
    naked_asm!(
        "li   t0, {PAGE_SIZE}",
        "add  t0, t0, a0",
        "1:",
        "sd   zero, 0(a0)",
        "sd   zero, 8(a0)",
        "sd   zero, 16(a0)",
        "sd   zero, 24(a0)",
        "sd   zero, 32(a0)",
        "sd   zero, 40(a0)",
        "sd   zero, 48(a0)",
        "sd   zero, 56(a0)",
        "addi a0, a0, 64",
        "bltu a0, t0, 1b",
        "ret",
        PAGE_SIZE = const moa_vmem::PAGE_SIZE,
    );
}

// 以下 mem*:`ld/sd` 一次 8 字节 + 字节收尾(riscv 无 load-pair / 无后变址,手动增量)。
// QEMU virt 硬件支持非对齐访问;a0 保留为返回值。

#[unsafe(naked)]
#[unsafe(no_mangle)]
extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
    naked_asm!(
        "mv   t0, a0", // t0 = 移动 dest,a0 保留为返回值
        "li   t1, 8",
        "1:",
        "bltu a2, t1, 2f",
        "ld   t2, 0(a1)",
        "sd   t2, 0(t0)",
        "addi a1, a1, 8",
        "addi t0, t0, 8",
        "addi a2, a2, -8",
        "j    1b",
        "2:",
        "beqz a2, 3f",
        "4:",
        "lbu  t2, 0(a1)",
        "sb   t2, 0(t0)",
        "addi a1, a1, 1",
        "addi t0, t0, 1",
        "addi a2, a2, -1",
        "bnez a2, 4b",
        "3:",
        "ret",
    );
}

#[unsafe(naked)]
#[unsafe(no_mangle)]
extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
    naked_asm!(
        "mv   t0, a0",
        "bgeu a1, a0, 5f", // src >= dest:前向
        // 后向:从高地址往低拷
        "add  t0, t0, a2",
        "add  a1, a1, a2",
        "li   t1, 8",
        "1:",
        "bltu a2, t1, 2f",
        "addi a1, a1, -8",
        "addi t0, t0, -8",
        "ld   t2, 0(a1)",
        "sd   t2, 0(t0)",
        "addi a2, a2, -8",
        "j    1b",
        "2:",
        "beqz a2, 9f",
        "3:",
        "addi a1, a1, -1",
        "addi t0, t0, -1",
        "lbu  t2, 0(a1)",
        "sb   t2, 0(t0)",
        "addi a2, a2, -1",
        "bnez a2, 3b",
        "9:",
        "ret",
        "5:", // 前向
        "li   t1, 8",
        "6:",
        "bltu a2, t1, 7f",
        "ld   t2, 0(a1)",
        "sd   t2, 0(t0)",
        "addi a1, a1, 8",
        "addi t0, t0, 8",
        "addi a2, a2, -8",
        "j    6b",
        "7:",
        "beqz a2, 8f",
        "4:",
        "lbu  t2, 0(a1)",
        "sb   t2, 0(t0)",
        "addi a1, a1, 1",
        "addi t0, t0, 1",
        "addi a2, a2, -1",
        "bnez a2, 4b",
        "8:",
        "ret",
    );
}

#[unsafe(naked)]
#[unsafe(no_mangle)]
extern "C" fn memset(dest: *mut u8, c: i32, n: usize) -> *mut u8 {
    naked_asm!(
        "mv   t0, a0",
        "andi a1, a1, 0xff", // 把待填字节复制到 a1 的全部 8 字节
        "slli t1, a1, 8",
        "or   a1, a1, t1",
        "slli t1, a1, 16",
        "or   a1, a1, t1",
        "slli t1, a1, 32",
        "or   a1, a1, t1",
        "li   t2, 8",
        "1:",
        "bltu a2, t2, 2f",
        "sd   a1, 0(t0)",
        "addi t0, t0, 8",
        "addi a2, a2, -8",
        "j    1b",
        "2:",
        "beqz a2, 3f",
        "4:",
        "sb   a1, 0(t0)",
        "addi t0, t0, 1",
        "addi a2, a2, -1",
        "bnez a2, 4b",
        "3:",
        "ret",
    );
}

#[unsafe(naked)]
#[unsafe(no_mangle)]
extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 {
    naked_asm!(
        "li   t2, 8",
        "1:", // 按字跳过相等前缀
        "bltu a2, t2, 2f",
        "ld   t0, 0(a0)",
        "ld   t1, 0(a1)",
        "bne  t0, t1, 2f", // 该字不同:落到逐字节定位首个差异
        "addi a0, a0, 8",
        "addi a1, a1, 8",
        "addi a2, a2, -8",
        "j    1b",
        "2:", // 逐字节比较
        "beqz a2, 3f",
        "5:",
        "lbu  t0, 0(a0)",
        "lbu  t1, 0(a1)",
        "addi a0, a0, 1",
        "addi a1, a1, 1",
        "addi a2, a2, -1",
        "bne  t0, t1, 4f",
        "bnez a2, 5b",
        "3:",
        "li   a0, 0",
        "ret",
        "4:",
        "sub  a0, t0, t1", // 返回首个差异字节的 (a - b)
        "ret",
    );
}