ckb_vm/memory/
wxorx.rs

1use super::super::{Error, Register, RISCV_MAX_MEMORY, RISCV_PAGESIZE};
2use super::{
3    check_permission, get_page_indices, round_page_down, round_page_up, Memory, FLAG_EXECUTABLE,
4    FLAG_FREEZED, FLAG_WRITABLE,
5};
6
7use bytes::Bytes;
8
9pub struct WXorXMemory<M: Memory> {
10    inner: M,
11}
12
13impl<M: Memory> WXorXMemory<M> {
14    pub fn inner_mut(&mut self) -> &mut M {
15        &mut self.inner
16    }
17}
18
19impl<M: Memory> Memory for WXorXMemory<M> {
20    type REG = M::REG;
21
22    fn new() -> Self {
23        Self::new_with_memory(RISCV_MAX_MEMORY)
24    }
25
26    fn new_with_memory(memory_size: usize) -> Self {
27        Self {
28            inner: M::new_with_memory(memory_size),
29        }
30    }
31
32    fn init_pages(
33        &mut self,
34        addr: u64,
35        size: u64,
36        flags: u8,
37        source: Option<Bytes>,
38        offset_from_addr: u64,
39    ) -> Result<(), Error> {
40        if round_page_down(addr) != addr || round_page_up(size) != size {
41            return Err(Error::MemPageUnalignedAccess);
42        }
43
44        if addr > self.memory_size() as u64
45            || size > self.memory_size() as u64
46            || addr + size > self.memory_size() as u64
47            || offset_from_addr > size
48        {
49            return Err(Error::MemOutOfBound);
50        }
51        for page_addr in (addr..addr + size).step_by(RISCV_PAGESIZE) {
52            let page = page_addr / RISCV_PAGESIZE as u64;
53            if self.fetch_flag(page)? & FLAG_FREEZED != 0 {
54                return Err(Error::MemWriteOnFreezedPage);
55            }
56            self.set_flag(page, flags)?;
57        }
58        self.inner
59            .init_pages(addr, size, flags, source, offset_from_addr)
60    }
61
62    fn fetch_flag(&mut self, page: u64) -> Result<u8, Error> {
63        self.inner.fetch_flag(page)
64    }
65
66    fn set_flag(&mut self, page: u64, flag: u8) -> Result<(), Error> {
67        self.inner.set_flag(page, flag)
68    }
69
70    fn clear_flag(&mut self, page: u64, flag: u8) -> Result<(), Error> {
71        self.inner.clear_flag(page, flag)
72    }
73
74    fn memory_size(&self) -> usize {
75        self.inner.memory_size()
76    }
77
78    fn execute_load16(&mut self, addr: u64) -> Result<u16, Error> {
79        let page_indices = get_page_indices(addr, 2)?;
80        check_permission(self, &page_indices, FLAG_EXECUTABLE)?;
81        self.inner.execute_load16(addr)
82    }
83
84    fn execute_load32(&mut self, addr: u64) -> Result<u32, Error> {
85        let page_indices = get_page_indices(addr, 4)?;
86        check_permission(self, &page_indices, FLAG_EXECUTABLE)?;
87        self.inner.execute_load32(addr)
88    }
89
90    fn load8(&mut self, addr: &Self::REG) -> Result<Self::REG, Error> {
91        self.inner.load8(addr)
92    }
93
94    fn load16(&mut self, addr: &Self::REG) -> Result<Self::REG, Error> {
95        self.inner.load16(addr)
96    }
97
98    fn load32(&mut self, addr: &Self::REG) -> Result<Self::REG, Error> {
99        self.inner.load32(addr)
100    }
101
102    fn load64(&mut self, addr: &Self::REG) -> Result<Self::REG, Error> {
103        self.inner.load64(addr)
104    }
105
106    fn store8(&mut self, addr: &Self::REG, value: &Self::REG) -> Result<(), Error> {
107        let page_indices = get_page_indices(addr.to_u64(), 1)?;
108        check_permission(self, &page_indices, FLAG_WRITABLE)?;
109        self.inner.store8(addr, value)
110    }
111
112    fn store16(&mut self, addr: &Self::REG, value: &Self::REG) -> Result<(), Error> {
113        let page_indices = get_page_indices(addr.to_u64(), 2)?;
114        check_permission(self, &page_indices, FLAG_WRITABLE)?;
115        self.inner.store16(addr, value)
116    }
117
118    fn store32(&mut self, addr: &Self::REG, value: &Self::REG) -> Result<(), Error> {
119        let page_indices = get_page_indices(addr.to_u64(), 4)?;
120        check_permission(self, &page_indices, FLAG_WRITABLE)?;
121        self.inner.store32(addr, value)
122    }
123
124    fn store64(&mut self, addr: &Self::REG, value: &Self::REG) -> Result<(), Error> {
125        let page_indices = get_page_indices(addr.to_u64(), 8)?;
126        check_permission(self, &page_indices, FLAG_WRITABLE)?;
127        self.inner.store64(addr, value)
128    }
129
130    fn store_bytes(&mut self, addr: u64, value: &[u8]) -> Result<(), Error> {
131        if value.is_empty() {
132            return Ok(());
133        }
134        let page_indices = get_page_indices(addr, value.len() as u64)?;
135        check_permission(self, &page_indices, FLAG_WRITABLE)?;
136        self.inner.store_bytes(addr, value)
137    }
138
139    fn store_byte(&mut self, addr: u64, size: u64, value: u8) -> Result<(), Error> {
140        if size == 0 {
141            return Ok(());
142        }
143        let page_indices = get_page_indices(addr, size)?;
144        check_permission(self, &page_indices, FLAG_WRITABLE)?;
145        self.inner.store_byte(addr, size, value)
146    }
147
148    fn load_bytes(&mut self, addr: u64, size: u64) -> Result<Bytes, Error> {
149        // inner.load_bytes will check
150        self.inner.load_bytes(addr, size)
151    }
152
153    fn lr(&self) -> &Self::REG {
154        self.inner.lr()
155    }
156
157    fn set_lr(&mut self, value: &Self::REG) {
158        self.inner.set_lr(value);
159    }
160}