Skip to main content

native_v86_core/cpu/
memory.rs

1mod ext {
2    #[link(wasm_import_module = "env")]
3    extern "C" {
4        pub fn mmap_read8(addr: u32) -> i32;
5        pub fn mmap_read32(addr: u32) -> i32;
6
7        pub fn mmap_write8(addr: u32, value: i32);
8        pub fn mmap_write16(addr: u32, value: i32);
9        pub fn mmap_write32(addr: u32, value: i32);
10        pub fn mmap_write64(addr: u32, v0: i32, v1: i32);
11        pub fn mmap_write128(addr: u32, v0: i32, v1: i32, v2: i32, v3: i32);
12    }
13}
14
15use crate::cpu::apic;
16use crate::cpu::cpu::{
17    handle_irqs, reg128, APIC_MEM_ADDRESS, APIC_MEM_SIZE, IOAPIC_MEM_ADDRESS, IOAPIC_MEM_SIZE,
18};
19use crate::cpu::global_pointers::memory_size;
20use crate::cpu::ioapic;
21use crate::cpu::vga;
22use crate::jit;
23use crate::page::Page;
24
25use std::alloc;
26use std::ptr;
27
28#[allow(non_upper_case_globals)]
29pub static mut mem8: *mut u8 = ptr::null_mut();
30
31#[no_mangle]
32pub fn allocate_memory(size: u32) -> u32 {
33    unsafe {
34        dbg_assert!(mem8.is_null());
35    };
36    dbg_log!("Allocate memory size={}m", size >> 20);
37    let layout = alloc::Layout::from_size_align(size as usize, 0x1000).unwrap();
38    let raw = unsafe { alloc::alloc(layout) };
39    unsafe {
40        mem8 = raw;
41    };
42    raw as u32
43}
44
45#[no_mangle]
46pub unsafe fn zero_memory(addr: u32, size: u32) {
47    ptr::write_bytes(mem8.offset(addr as isize), 0, size as usize);
48}
49
50#[allow(non_upper_case_globals)]
51pub static mut vga_mem8: *mut u8 = ptr::null_mut();
52#[allow(non_upper_case_globals)]
53pub static mut vga_memory_size: u32 = 0;
54
55#[no_mangle]
56pub fn svga_allocate_memory(size: u32) -> u32 {
57    unsafe {
58        dbg_assert!(vga_mem8.is_null());
59    };
60    let layout = alloc::Layout::from_size_align(size as usize, 0x1000).unwrap();
61    let raw = unsafe { alloc::alloc(layout) };
62    dbg_assert!(
63        size & (1 << 12 << 6) == 0,
64        "size not aligned to dirty_bitmap"
65    );
66    unsafe {
67        vga_mem8 = raw;
68        vga_memory_size = size;
69        vga::set_dirty_bitmap_size(size >> 12 >> 6);
70    };
71    raw as u32
72}
73
74#[no_mangle]
75pub fn in_mapped_range(addr: u32) -> bool {
76    return addr >= 0xA0000 && addr < 0xC0000 || addr >= unsafe { *memory_size };
77}
78
79pub const VGA_LFB_ADDRESS: u32 = 0xE0000000;
80pub fn in_svga_lfb(addr: u32) -> bool {
81    addr >= VGA_LFB_ADDRESS && addr <= unsafe { VGA_LFB_ADDRESS + (vga_memory_size - 1) }
82}
83
84#[no_mangle]
85pub fn read8(addr: u32) -> i32 {
86    if in_mapped_range(addr) {
87        if in_svga_lfb(addr) {
88            unsafe { *vga_mem8.offset((addr - VGA_LFB_ADDRESS) as isize) as i32 }
89        }
90        else if addr >= APIC_MEM_ADDRESS && addr < APIC_MEM_ADDRESS + APIC_MEM_SIZE {
91            apic::read32((addr - APIC_MEM_ADDRESS) & !3) as i32 >> 8 * (addr & 3) & 0xFF
92        }
93        else if addr >= IOAPIC_MEM_ADDRESS && addr < IOAPIC_MEM_ADDRESS + IOAPIC_MEM_SIZE {
94            ioapic::read32((addr - IOAPIC_MEM_ADDRESS) & !3) as i32 >> 8 * (addr & 3) & 0xFF
95        }
96        else {
97            unsafe { ext::mmap_read8(addr) }
98        }
99    }
100    else {
101        read8_no_mmap_check(addr)
102    }
103}
104pub fn read8_no_mmap_check(addr: u32) -> i32 { unsafe { *mem8.offset(addr as isize) as i32 } }
105
106#[no_mangle]
107pub fn read16(addr: u32) -> i32 {
108    if in_mapped_range(addr) {
109        if in_svga_lfb(addr) {
110            unsafe {
111                ptr::read_unaligned(vga_mem8.offset((addr - VGA_LFB_ADDRESS) as isize) as *const u16)
112                    as i32
113            }
114        }
115        else {
116            read8(addr) | read8(addr + 1) << 8
117        }
118    }
119    else {
120        read16_no_mmap_check(addr)
121    }
122}
123pub fn read16_no_mmap_check(addr: u32) -> i32 {
124    unsafe { ptr::read_unaligned(mem8.offset(addr as isize) as *const u16) as i32 }
125}
126
127#[no_mangle]
128pub fn read32s(addr: u32) -> i32 {
129    if in_mapped_range(addr) {
130        if in_svga_lfb(addr) {
131            unsafe {
132                ptr::read_unaligned(vga_mem8.offset((addr - VGA_LFB_ADDRESS) as isize) as *const i32)
133            } // XXX
134        }
135        else if addr >= APIC_MEM_ADDRESS && addr < APIC_MEM_ADDRESS + APIC_MEM_SIZE {
136            apic::read32(addr - APIC_MEM_ADDRESS) as i32
137        }
138        else if addr >= IOAPIC_MEM_ADDRESS && addr < IOAPIC_MEM_ADDRESS + IOAPIC_MEM_SIZE {
139            ioapic::read32(addr - IOAPIC_MEM_ADDRESS) as i32
140        }
141        else {
142            unsafe { ext::mmap_read32(addr) }
143        }
144    }
145    else {
146        read32_no_mmap_check(addr)
147    }
148}
149pub fn read32_no_mmap_check(addr: u32) -> i32 {
150    unsafe { ptr::read_unaligned(mem8.offset(addr as isize) as *const i32) }
151}
152
153pub unsafe fn read64s(addr: u32) -> i64 {
154    if in_mapped_range(addr) {
155        if in_svga_lfb(addr) {
156            ptr::read_unaligned(vga_mem8.offset((addr - VGA_LFB_ADDRESS) as isize) as *const i64)
157        }
158        else {
159            read32s(addr) as i64 | (read32s(addr + 4) as i64) << 32
160        }
161    }
162    else {
163        ptr::read_unaligned(mem8.offset(addr as isize) as *const i64)
164    }
165}
166
167pub unsafe fn read128(addr: u32) -> reg128 {
168    if in_mapped_range(addr) {
169        if in_svga_lfb(addr) {
170            ptr::read_unaligned(vga_mem8.offset((addr - VGA_LFB_ADDRESS) as isize) as *const reg128)
171        }
172        else {
173            reg128 {
174                i32: [
175                    read32s(addr + 0),
176                    read32s(addr + 4),
177                    read32s(addr + 8),
178                    read32s(addr + 12),
179                ],
180            }
181        }
182    }
183    else {
184        ptr::read_unaligned(mem8.offset(addr as isize) as *const reg128)
185    }
186}
187
188#[no_mangle]
189pub unsafe fn write8(addr: u32, value: i32) {
190    if in_mapped_range(addr) {
191        mmap_write8(addr, value & 0xFF);
192    }
193    else {
194        jit::jit_dirty_page(Page::page_of(addr));
195        write8_no_mmap_or_dirty_check(addr, value);
196    };
197}
198
199pub unsafe fn write8_no_mmap_or_dirty_check(addr: u32, value: i32) {
200    *mem8.offset(addr as isize) = value as u8
201}
202
203#[no_mangle]
204pub unsafe fn write16(addr: u32, value: i32) {
205    if in_mapped_range(addr) {
206        mmap_write16(addr, value & 0xFFFF);
207    }
208    else {
209        jit::jit_dirty_cache_small(addr, addr + 2);
210        write16_no_mmap_or_dirty_check(addr, value);
211    };
212}
213pub unsafe fn write16_no_mmap_or_dirty_check(addr: u32, value: i32) {
214    ptr::write_unaligned(mem8.offset(addr as isize) as *mut u16, value as u16)
215}
216
217#[no_mangle]
218pub unsafe fn write32(addr: u32, value: i32) {
219    if in_mapped_range(addr) {
220        mmap_write32(addr, value);
221    }
222    else {
223        jit::jit_dirty_cache_small(addr, addr + 4);
224        write32_no_mmap_or_dirty_check(addr, value);
225    }
226}
227
228pub unsafe fn write32_no_mmap_or_dirty_check(addr: u32, value: i32) {
229    ptr::write_unaligned(mem8.offset(addr as isize) as *mut i32, value)
230}
231
232pub unsafe fn write64_no_mmap_or_dirty_check(addr: u32, value: u64) {
233    ptr::write_unaligned(mem8.offset(addr as isize) as *mut u64, value)
234}
235
236pub unsafe fn write128_no_mmap_or_dirty_check(addr: u32, value: reg128) {
237    ptr::write_unaligned(mem8.offset(addr as isize) as *mut reg128, value)
238}
239
240pub unsafe fn memset_no_mmap_or_dirty_check(addr: u32, value: u8, count: u32) {
241    ptr::write_bytes(mem8.offset(addr as isize), value, count as usize);
242}
243
244pub unsafe fn memcpy_no_mmap_or_dirty_check(src_addr: u32, dst_addr: u32, count: u32) {
245    dbg_assert!(src_addr < *memory_size);
246    dbg_assert!(dst_addr < *memory_size);
247    ptr::copy(
248        mem8.offset(src_addr as isize),
249        mem8.offset(dst_addr as isize),
250        count as usize,
251    )
252}
253
254pub unsafe fn memcpy_into_svga_lfb(src_addr: u32, dst_addr: u32, count: u32) {
255    dbg_assert!(src_addr < *memory_size);
256    dbg_assert!(in_svga_lfb(dst_addr));
257    dbg_assert!(Page::page_of(dst_addr) == Page::page_of(dst_addr + count - 1));
258    vga::mark_dirty(dst_addr);
259    ptr::copy_nonoverlapping(
260        mem8.offset(src_addr as isize),
261        vga_mem8.offset((dst_addr - VGA_LFB_ADDRESS) as isize),
262        count as usize,
263    )
264}
265
266pub unsafe fn mmap_write8(addr: u32, value: i32) {
267    if in_svga_lfb(addr) {
268        vga::mark_dirty(addr);
269        *vga_mem8.offset((addr - VGA_LFB_ADDRESS) as isize) = value as u8
270    }
271    else {
272        ext::mmap_write8(addr, value)
273    }
274}
275pub unsafe fn mmap_write16(addr: u32, value: i32) {
276    if in_svga_lfb(addr) {
277        vga::mark_dirty(addr);
278        ptr::write_unaligned(
279            vga_mem8.offset((addr - VGA_LFB_ADDRESS) as isize) as *mut u16,
280            value as u16,
281        )
282    }
283    else {
284        ext::mmap_write16(addr, value)
285    }
286}
287pub unsafe fn mmap_write32(addr: u32, value: i32) {
288    if in_svga_lfb(addr) {
289        vga::mark_dirty(addr);
290        ptr::write_unaligned(
291            vga_mem8.offset((addr - VGA_LFB_ADDRESS) as isize) as *mut i32,
292            value,
293        )
294    }
295    else if addr >= APIC_MEM_ADDRESS && addr < APIC_MEM_ADDRESS + APIC_MEM_SIZE {
296        apic::write32(addr - APIC_MEM_ADDRESS, value as u32);
297        handle_irqs();
298    }
299    else if addr >= IOAPIC_MEM_ADDRESS && addr < IOAPIC_MEM_ADDRESS + IOAPIC_MEM_SIZE {
300        ioapic::write32(addr - IOAPIC_MEM_ADDRESS, value as u32);
301        handle_irqs();
302    }
303    else {
304        ext::mmap_write32(addr, value)
305    }
306}
307pub unsafe fn mmap_write64(addr: u32, value: u64) {
308    if in_svga_lfb(addr) {
309        vga::mark_dirty(addr);
310        ptr::write_unaligned(
311            vga_mem8.offset((addr - VGA_LFB_ADDRESS) as isize) as *mut u64,
312            value,
313        )
314    }
315    else {
316        ext::mmap_write64(addr, value as i32, (value >> 32) as i32)
317    }
318}
319pub unsafe fn mmap_write128(addr: u32, v0: u64, v1: u64) {
320    if in_svga_lfb(addr) {
321        vga::mark_dirty(addr);
322        ptr::write_unaligned(
323            vga_mem8.offset((addr - VGA_LFB_ADDRESS) as isize) as *mut u64,
324            v0,
325        );
326        ptr::write_unaligned(
327            vga_mem8.offset((addr - VGA_LFB_ADDRESS + 8) as isize) as *mut u64,
328            v1,
329        )
330    }
331    else {
332        ext::mmap_write128(
333            addr,
334            v0 as i32,
335            (v0 >> 32) as i32,
336            v1 as i32,
337            (v1 >> 32) as i32,
338        )
339    }
340}
341
342#[no_mangle]
343pub unsafe fn is_memory_zeroed(addr: u32, length: u32) -> bool {
344    dbg_assert!(addr % 8 == 0);
345    dbg_assert!(length % 8 == 0);
346    for i in (addr..addr + length).step_by(8) {
347        if *(mem8.offset(i as isize) as *const i64) != 0 {
348            return false;
349        }
350    }
351    return true;
352}