Skip to main content

libarch/riscv64/
paging.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use bitrs::{bitfield_repr, layout};
6use regio::riscv64::{Csr, encoding};
7
8/// [riscv/priv]: 4.1.11  Supervisor Address Translation and Protection Register (satp)
9pub const SATP: Csr<encoding::satp, SupervisorAddressTranslationAndProtection> = Csr::new();
10
11#[bitfield_repr(u8)]
12#[derive(Clone, Copy)]
13pub enum TranslationMode {
14    Bare = 0, // No translation or protection.
15    // 1-7 are reserved for standard use.
16    Sv39 = 8,
17    Sv48 = 9,
18    Sv57 = 10,
19    Sv64 = 11,
20    // 12-13 are reserved for standard use.
21    // 14-15 are reserved for custom use.
22}
23
24layout!({
25    /// The layout of [`SATP`].
26    pub struct SupervisorAddressTranslationAndProtection(u64);
27    {
28        let mode @ 63..60: TranslationMode;
29        let asid @ 59..44;
30        let ppn @ 43..0;
31    }
32});
33
34impl SupervisorAddressTranslationAndProtection {
35    /// Returns the root page table physical address (PPN << 12).
36    pub fn root_address(&self) -> u64 {
37        self.ppn() << 12
38    }
39
40    /// Sets the root page table physical address (must be 4KiB-aligned).
41    pub fn set_root_address(&mut self, addr: u64) -> &mut Self {
42        assert!(addr & 0xfff == 0, "root address must be 4KiB-aligned");
43        self.set_ppn(addr >> 12)
44    }
45}
46
47#[cfg(test)]
48mod tests {
49    use super::*;
50
51    #[test]
52    fn satp() {
53        let mut satp = SupervisorAddressTranslationAndProtection::new();
54        satp.set_mode(TranslationMode::Sv39).set_asid(0x12).set_root_address(0x8000_0000);
55        assert_eq!(satp.mode(), TranslationMode::Sv39);
56        assert_eq!(satp.asid(), 0x12);
57        assert_eq!(satp.root_address(), 0x8000_0000);
58        assert_eq!(satp.ppn(), 0x8_0000);
59    }
60}