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        } else if addr >= APIC_MEM_ADDRESS && addr < APIC_MEM_ADDRESS + APIC_MEM_SIZE {
90            apic::read32((addr - APIC_MEM_ADDRESS) & !3) as i32 >> 8 * (addr & 3) & 0xFF
91        } else if addr >= IOAPIC_MEM_ADDRESS && addr < IOAPIC_MEM_ADDRESS + IOAPIC_MEM_SIZE {
92            ioapic::read32((addr - IOAPIC_MEM_ADDRESS) & !3) as i32 >> 8 * (addr & 3) & 0xFF
93        } else {
94            unsafe { ext::mmap_read8(addr) }
95        }
96    } else {
97        read8_no_mmap_check(addr)
98    }
99}
100pub fn read8_no_mmap_check(addr: u32) -> i32 {
101    unsafe { *mem8.offset(addr as isize) as i32 }
102}
103
104#[no_mangle]
105pub fn read16(addr: u32) -> i32 {
106    if in_mapped_range(addr) {
107        if in_svga_lfb(addr) {
108            unsafe {
109                ptr::read_unaligned(vga_mem8.offset((addr - VGA_LFB_ADDRESS) as isize) as *const u16)
110                    as i32
111            }
112        } else {
113            read8(addr) | read8(addr + 1) << 8
114        }
115    } else {
116        read16_no_mmap_check(addr)
117    }
118}
119pub fn read16_no_mmap_check(addr: u32) -> i32 {
120    unsafe { ptr::read_unaligned(mem8.offset(addr as isize) as *const u16) as i32 }
121}
122
123#[no_mangle]
124pub fn read32s(addr: u32) -> i32 {
125    if in_mapped_range(addr) {
126        if in_svga_lfb(addr) {
127            unsafe {
128                ptr::read_unaligned(vga_mem8.offset((addr - VGA_LFB_ADDRESS) as isize) as *const i32)
129            } // XXX
130        } else if addr >= APIC_MEM_ADDRESS && addr < APIC_MEM_ADDRESS + APIC_MEM_SIZE {
131            apic::read32(addr - APIC_MEM_ADDRESS) as i32
132        } else if addr >= IOAPIC_MEM_ADDRESS && addr < IOAPIC_MEM_ADDRESS + IOAPIC_MEM_SIZE {
133            ioapic::read32(addr - IOAPIC_MEM_ADDRESS) as i32
134        } else {
135            unsafe { ext::mmap_read32(addr) }
136        }
137    } else {
138        read32_no_mmap_check(addr)
139    }
140}
141pub fn read32_no_mmap_check(addr: u32) -> i32 {
142    unsafe { ptr::read_unaligned(mem8.offset(addr as isize) as *const i32) }
143}
144
145pub unsafe fn read64s(addr: u32) -> i64 {
146    if in_mapped_range(addr) {
147        if in_svga_lfb(addr) {
148            ptr::read_unaligned(vga_mem8.offset((addr - VGA_LFB_ADDRESS) as isize) as *const i64)
149        } else {
150            read32s(addr) as i64 | (read32s(addr + 4) as i64) << 32
151        }
152    } else {
153        ptr::read_unaligned(mem8.offset(addr as isize) as *const i64)
154    }
155}
156
157pub unsafe fn read128(addr: u32) -> reg128 {
158    if in_mapped_range(addr) {
159        if in_svga_lfb(addr) {
160            ptr::read_unaligned(vga_mem8.offset((addr - VGA_LFB_ADDRESS) as isize) as *const reg128)
161        } else {
162            reg128 {
163                i32: [
164                    read32s(addr + 0),
165                    read32s(addr + 4),
166                    read32s(addr + 8),
167                    read32s(addr + 12),
168                ],
169            }
170        }
171    } else {
172        ptr::read_unaligned(mem8.offset(addr as isize) as *const reg128)
173    }
174}
175
176#[no_mangle]
177pub unsafe fn write8(addr: u32, value: i32) {
178    if in_mapped_range(addr) {
179        mmap_write8(addr, value & 0xFF);
180    } else {
181        jit::jit_dirty_page(Page::page_of(addr));
182        write8_no_mmap_or_dirty_check(addr, value);
183    };
184}
185
186pub unsafe fn write8_no_mmap_or_dirty_check(addr: u32, value: i32) {
187    *mem8.offset(addr as isize) = value as u8
188}
189
190#[no_mangle]
191pub unsafe fn write16(addr: u32, value: i32) {
192    if in_mapped_range(addr) {
193        mmap_write16(addr, value & 0xFFFF);
194    } else {
195        jit::jit_dirty_cache_small(addr, addr + 2);
196        write16_no_mmap_or_dirty_check(addr, value);
197    };
198}
199pub unsafe fn write16_no_mmap_or_dirty_check(addr: u32, value: i32) {
200    ptr::write_unaligned(mem8.offset(addr as isize) as *mut u16, value as u16)
201}
202
203#[no_mangle]
204pub unsafe fn write32(addr: u32, value: i32) {
205    if in_mapped_range(addr) {
206        mmap_write32(addr, value);
207    } else {
208        jit::jit_dirty_cache_small(addr, addr + 4);
209        write32_no_mmap_or_dirty_check(addr, value);
210    }
211}
212
213pub unsafe fn write32_no_mmap_or_dirty_check(addr: u32, value: i32) {
214    ptr::write_unaligned(mem8.offset(addr as isize) as *mut i32, value)
215}
216
217pub unsafe fn write64_no_mmap_or_dirty_check(addr: u32, value: u64) {
218    ptr::write_unaligned(mem8.offset(addr as isize) as *mut u64, value)
219}
220
221pub unsafe fn write128_no_mmap_or_dirty_check(addr: u32, value: reg128) {
222    ptr::write_unaligned(mem8.offset(addr as isize) as *mut reg128, value)
223}
224
225pub unsafe fn memset_no_mmap_or_dirty_check(addr: u32, value: u8, count: u32) {
226    ptr::write_bytes(mem8.offset(addr as isize), value, count as usize);
227}
228
229pub unsafe fn memcpy_no_mmap_or_dirty_check(src_addr: u32, dst_addr: u32, count: u32) {
230    dbg_assert!(src_addr < *memory_size);
231    dbg_assert!(dst_addr < *memory_size);
232    ptr::copy(
233        mem8.offset(src_addr as isize),
234        mem8.offset(dst_addr as isize),
235        count as usize,
236    )
237}
238
239pub unsafe fn memcpy_into_svga_lfb(src_addr: u32, dst_addr: u32, count: u32) {
240    dbg_assert!(src_addr < *memory_size);
241    dbg_assert!(in_svga_lfb(dst_addr));
242    dbg_assert!(Page::page_of(dst_addr) == Page::page_of(dst_addr + count - 1));
243    vga::mark_dirty(dst_addr);
244    ptr::copy_nonoverlapping(
245        mem8.offset(src_addr as isize),
246        vga_mem8.offset((dst_addr - VGA_LFB_ADDRESS) as isize),
247        count as usize,
248    )
249}
250
251pub unsafe fn mmap_write8(addr: u32, value: i32) {
252    if in_svga_lfb(addr) {
253        vga::mark_dirty(addr);
254        *vga_mem8.offset((addr - VGA_LFB_ADDRESS) as isize) = value as u8
255    } else {
256        ext::mmap_write8(addr, value)
257    }
258}
259pub unsafe fn mmap_write16(addr: u32, value: i32) {
260    if in_svga_lfb(addr) {
261        vga::mark_dirty(addr);
262        ptr::write_unaligned(
263            vga_mem8.offset((addr - VGA_LFB_ADDRESS) as isize) as *mut u16,
264            value as u16,
265        )
266    } else {
267        ext::mmap_write16(addr, value)
268    }
269}
270pub unsafe fn mmap_write32(addr: u32, value: i32) {
271    if in_svga_lfb(addr) {
272        vga::mark_dirty(addr);
273        ptr::write_unaligned(
274            vga_mem8.offset((addr - VGA_LFB_ADDRESS) as isize) as *mut i32,
275            value,
276        )
277    } else if addr >= APIC_MEM_ADDRESS && addr < APIC_MEM_ADDRESS + APIC_MEM_SIZE {
278        apic::write32(addr - APIC_MEM_ADDRESS, value as u32);
279        handle_irqs();
280    } else if addr >= IOAPIC_MEM_ADDRESS && addr < IOAPIC_MEM_ADDRESS + IOAPIC_MEM_SIZE {
281        ioapic::write32(addr - IOAPIC_MEM_ADDRESS, value as u32);
282        handle_irqs();
283    } else {
284        ext::mmap_write32(addr, value)
285    }
286}
287pub unsafe fn mmap_write64(addr: u32, value: u64) {
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 u64,
292            value,
293        )
294    } else {
295        ext::mmap_write64(addr, value as i32, (value >> 32) as i32)
296    }
297}
298pub unsafe fn mmap_write128(addr: u32, v0: u64, v1: u64) {
299    if in_svga_lfb(addr) {
300        vga::mark_dirty(addr);
301        ptr::write_unaligned(
302            vga_mem8.offset((addr - VGA_LFB_ADDRESS) as isize) as *mut u64,
303            v0,
304        );
305        ptr::write_unaligned(
306            vga_mem8.offset((addr - VGA_LFB_ADDRESS + 8) as isize) as *mut u64,
307            v1,
308        )
309    } else {
310        ext::mmap_write128(
311            addr,
312            v0 as i32,
313            (v0 >> 32) as i32,
314            v1 as i32,
315            (v1 >> 32) as i32,
316        )
317    }
318}
319
320#[no_mangle]
321pub unsafe fn is_memory_zeroed(addr: u32, length: u32) -> bool {
322    dbg_assert!(addr % 8 == 0);
323    dbg_assert!(length % 8 == 0);
324    for i in (addr..addr + length).step_by(8) {
325        if *(mem8.offset(i as isize) as *const i64) != 0 {
326            return false;
327        }
328    }
329    return true;
330}