1 #ifndef H_MMU
2 #define H_MMU
3 
4 #include "cpu.h"
5 #include "emu.h"
6 
7 #ifdef __cplusplus
8 extern "C" {
9 #endif
10 
11 /* Translate a VA to a PA, using a page table lookup */
12 uint32_t mmu_translate(uint32_t addr, bool writing, fault_proc *fault, uint8_t *s_status);
13 
14 /* Used for t-type (usermode-like) access */
15 void mmu_check_priv(uint32_t addr, bool writing);
16 
17 /* addr_cache is used to cache the translation of VA to PA per page.
18  * It has two entries per page (1k), one for reading and one for writing.
19  * The format for 32-bit x86 with JIT is different to minimize the needed
20  * registers in the x86 memory access functions and won't work for all
21  * platforms:
22  *
23  * a) Pointer entry
24  *    The result of adding the virtual address (VA) to the entry has bit 31
25  *    clear, and that sum is a pointer to within mem_and_flags.
26  *    It would be cleaner to just use bit 0 or 1 to distinguish this case, but
27  *    this way we can simultaneously check both that this is a pointer entry,
28  *    and that the address is aligned, with a single bit test instruction.
29  * b) Physical address entry
30  *    VA + entry has bit 31 set, and the entry (not the sum) has bit 22 clear.
31  *    Bits 0-21 contain the difference between virtual and physical address.
32  * c) Invalid entry
33  *    VA + entry has bit 31 set, entry has bit 22 set. Entry is invalid and
34  *    addr_cache_miss must be called.
35  *
36  * In all other cases the format is simpler:
37  * a) Pointer entry: Bit 0 clear, rest difference to pointer to start of physical page
38  * b) Physical entry: Bit 0 set, Bit 1 clear, rest difference to physical address
39  * c) Invalid entry: Bit 0 set, Bit 1 set
40  */
41 
42 #define AC_NUM_ENTRIES (((1ull << 32) >> 10) * 2)
43 typedef uint8_t *ac_entry;
44 extern ac_entry *addr_cache __asm__("addr_cache");
45 
46 #if defined(__i386__) && !defined(NO_TRANSLATION)
47     #define AC_SET_ENTRY_PTR(entry, va, ptr) \
48             entry = (ptr) - (va);
49     #define AC_NOT_PTR 0x80000000
50     #define AC_INVALID (1 << 22)
51     #define AC_SET_ENTRY_PHYS(entry, va, pa) \
52             entry = (ac_entry)(((pa) - (va)) >> 10); \
53             entry += (~(uintptr_t)((va) + entry) & AC_NOT_PTR);
54     #define AC_SET_ENTRY_INVALID(entry, va) \
55             entry = (ac_entry)(AC_INVALID); \
56             entry += (~(uintptr_t)((va) + entry) & AC_NOT_PTR);
57 #else
58     #define AC_SET_ENTRY_PTR(entry, va, ptr) \
59             entry = (ptr) - (va);
60     #define AC_NOT_PTR 0x1
61     #define AC_INVALID 0x2
62     #define AC_FLAGS 0x3
63     #define AC_SET_ENTRY_PHYS(entry, va, pa) \
64             entry = (ac_entry)(((pa) - (va)) | AC_NOT_PTR);
65     #define AC_SET_ENTRY_INVALID(entry, va) \
66             entry = (ac_entry)(AC_INVALID | AC_NOT_PTR);
67 #endif
68 
69 bool addr_cache_pagefault(void *addr);
70 void *addr_cache_miss(uint32_t addr, bool writing, fault_proc *fault) __asm__("addr_cache_miss");
71 void addr_cache_flush(void);
72 void mmu_dump_tables(void);
73 
74 #ifdef __cplusplus
75 }
76 #endif
77 
78 #endif
79