Home | History | Annotate | Download | only in qemu
      1 /*
      2  *  Software MMU support
      3  *
      4  *  Copyright (c) 2003 Fabrice Bellard
      5  *
      6  * This library is free software; you can redistribute it and/or
      7  * modify it under the terms of the GNU Lesser General Public
      8  * License as published by the Free Software Foundation; either
      9  * version 2 of the License, or (at your option) any later version.
     10  *
     11  * This library is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14  * Lesser General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU Lesser General Public
     17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     18  */
     19 #if DATA_SIZE == 8
     20 #define SUFFIX q
     21 #define USUFFIX q
     22 #define DATA_TYPE uint64_t
     23 #elif DATA_SIZE == 4
     24 #define SUFFIX l
     25 #define USUFFIX l
     26 #define DATA_TYPE uint32_t
     27 #elif DATA_SIZE == 2
     28 #define SUFFIX w
     29 #define USUFFIX uw
     30 #define DATA_TYPE uint16_t
     31 #define DATA_STYPE int16_t
     32 #elif DATA_SIZE == 1
     33 #define SUFFIX b
     34 #define USUFFIX ub
     35 #define DATA_TYPE uint8_t
     36 #define DATA_STYPE int8_t
     37 #else
     38 #error unsupported data size
     39 #endif
     40 
     41 #if ACCESS_TYPE < (NB_MMU_MODES)
     42 
     43 #if defined(OUTSIDE_JIT)
     44 /* Dispatch calls to __ldx_outside_jit / __stx_outside_jit, which don't
     45  * expect CPU environment. to be cached in ebp register, but rather uses
     46  * cpu_single_env variable for that purpose.
     47  */
     48 #define MMUSUFFIX _outside_jit
     49 #else   // OUTSIDE_JIT
     50 #define MMUSUFFIX _mmu
     51 #endif  // OUTSIDE_JIT
     52 #define CPU_MMU_INDEX ACCESS_TYPE
     53 
     54 #elif ACCESS_TYPE == (NB_MMU_MODES)
     55 
     56 #define CPU_MMU_INDEX (cpu_mmu_index(env))
     57 #define MMUSUFFIX _mmu
     58 
     59 #elif ACCESS_TYPE == (NB_MMU_MODES + 1)
     60 
     61 #define CPU_MMU_INDEX (cpu_mmu_index(env))
     62 #define MMUSUFFIX _cmmu
     63 
     64 #else
     65 #error invalid ACCESS_TYPE
     66 #endif
     67 
     68 #if DATA_SIZE == 8
     69 #define RES_TYPE uint64_t
     70 #else
     71 #define RES_TYPE uint32_t
     72 #endif
     73 
     74 #if ACCESS_TYPE == (NB_MMU_MODES + 1)
     75 #define ADDR_READ addr_code
     76 #else
     77 #define ADDR_READ addr_read
     78 #endif
     79 
     80 /* generic load/store macros */
     81 
     82 static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr)
     83 {
     84     int page_index;
     85     RES_TYPE res;
     86     target_ulong addr;
     87     unsigned long physaddr;
     88     int mmu_idx;
     89 
     90     addr = ptr;
     91     page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
     92     mmu_idx = CPU_MMU_INDEX;
     93     if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ !=
     94                  (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) {
     95         res = glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, mmu_idx);
     96     } else {
     97         physaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
     98         res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr);
     99     }
    100     return res;
    101 }
    102 
    103 #if DATA_SIZE <= 2
    104 static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr)
    105 {
    106     int res, page_index;
    107     target_ulong addr;
    108     unsigned long physaddr;
    109     int mmu_idx;
    110 
    111     addr = ptr;
    112     page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
    113     mmu_idx = CPU_MMU_INDEX;
    114     if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ !=
    115                  (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) {
    116         res = (DATA_STYPE)glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, mmu_idx);
    117     } else {
    118         physaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
    119         res = glue(glue(lds, SUFFIX), _raw)((uint8_t *)physaddr);
    120     }
    121     return res;
    122 }
    123 #endif
    124 
    125 #if ACCESS_TYPE != (NB_MMU_MODES + 1)
    126 
    127 /* generic store macro */
    128 
    129 static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE v)
    130 {
    131     int page_index;
    132     target_ulong addr;
    133     unsigned long physaddr;
    134     int mmu_idx;
    135 
    136     addr = ptr;
    137     page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
    138     mmu_idx = CPU_MMU_INDEX;
    139     if (unlikely(env->tlb_table[mmu_idx][page_index].addr_write !=
    140                  (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) {
    141         glue(glue(__st, SUFFIX), MMUSUFFIX)(addr, v, mmu_idx);
    142     } else {
    143         physaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
    144         glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, v);
    145     }
    146 }
    147 
    148 #endif /* ACCESS_TYPE != (NB_MMU_MODES + 1) */
    149 
    150 #if ACCESS_TYPE != (NB_MMU_MODES + 1)
    151 
    152 #if DATA_SIZE == 8
    153 static inline float64 glue(ldfq, MEMSUFFIX)(target_ulong ptr)
    154 {
    155     union {
    156         float64 d;
    157         uint64_t i;
    158     } u;
    159     u.i = glue(ldq, MEMSUFFIX)(ptr);
    160     return u.d;
    161 }
    162 
    163 static inline void glue(stfq, MEMSUFFIX)(target_ulong ptr, float64 v)
    164 {
    165     union {
    166         float64 d;
    167         uint64_t i;
    168     } u;
    169     u.d = v;
    170     glue(stq, MEMSUFFIX)(ptr, u.i);
    171 }
    172 #endif /* DATA_SIZE == 8 */
    173 
    174 #if DATA_SIZE == 4
    175 static inline float32 glue(ldfl, MEMSUFFIX)(target_ulong ptr)
    176 {
    177     union {
    178         float32 f;
    179         uint32_t i;
    180     } u;
    181     u.i = glue(ldl, MEMSUFFIX)(ptr);
    182     return u.f;
    183 }
    184 
    185 static inline void glue(stfl, MEMSUFFIX)(target_ulong ptr, float32 v)
    186 {
    187     union {
    188         float32 f;
    189         uint32_t i;
    190     } u;
    191     u.f = v;
    192     glue(stl, MEMSUFFIX)(ptr, u.i);
    193 }
    194 #endif /* DATA_SIZE == 4 */
    195 
    196 #endif /* ACCESS_TYPE != (NB_MMU_MODES + 1) */
    197 
    198 #undef RES_TYPE
    199 #undef DATA_TYPE
    200 #undef DATA_STYPE
    201 #undef SUFFIX
    202 #undef USUFFIX
    203 #undef DATA_SIZE
    204 #undef CPU_MMU_INDEX
    205 #undef MMUSUFFIX
    206 #undef ADDR_READ
    207