filename | src/sh4/mmu.c |
changeset | 1217:677b1d85f1b4 |
prev | 1202:01ae5cbad4c8 |
next | 1295:9067aff5522d |
author | nkeynes |
date | Fri Aug 24 08:53:50 2012 +1000 (11 years ago) |
permissions | -rw-r--r-- |
last change | Move the generated prologue/epilogue code out into a common entry stub (reduces space requirements) and pre-save all saved registers. Change FASTCALL to use 3 regs instead of 2 since we can now keep everything in regs. |
file | annotate | diff | log | raw |
1.1 --- a/src/sh4/mmu.c Fri Dec 23 08:20:17 2011 +10001.2 +++ b/src/sh4/mmu.c Fri Aug 24 08:53:50 2012 +10001.3 @@ -34,6 +34,9 @@1.4 mem_region_fn_t *sh4_address_space;1.5 mem_region_fn_t *sh4_user_address_space;1.7 +/* External address space (usually the same as the global ext_address_space) */1.8 +static mem_region_fn_t *sh4_ext_address_space;1.9 +1.10 /* Accessed from the UTLB accessor methods */1.11 uint32_t mmu_urc;1.12 uint32_t mmu_urb;1.13 @@ -92,6 +95,19 @@1.15 #define IS_STOREQUEUE_PROTECTED() (mmu_user_storequeue_regions == &mmu_default_regions[DEFAULT_STOREQUEUE_SQMD_REGIONS])1.17 +#ifndef SH4_TRANSLATOR1.18 +/* Dummy MMU vtable functions */1.19 +void mmu_utlb_init_vtable( struct utlb_entry *ent, struct utlb_page_entry *page, gboolean writable )1.20 +{1.21 +}1.22 +void mmu_utlb_init_storequeue_vtable( struct utlb_entry *ent, struct utlb_page_entry *page )1.23 +{1.24 +}1.25 +void mmu_utlb_1k_init_vtable( struct utlb_1k_entry *entry )1.26 +{1.27 +}1.28 +#endif1.29 +1.30 /*********************** Module public functions ****************************/1.32 /**1.33 @@ -101,6 +117,7 @@1.35 void MMU_init()1.36 {1.37 + sh4_ext_address_space = ext_address_space;1.38 sh4_address_space = mem_alloc_pages( sizeof(mem_region_fn_t) * 256 );1.39 sh4_user_address_space = mem_alloc_pages( sizeof(mem_region_fn_t) * 256 );1.40 mmu_user_storequeue_regions = &mmu_default_regions[DEFAULT_STOREQUEUE_REGIONS];1.41 @@ -343,6 +360,14 @@1.43 /********************** Address space maintenance *************************/1.45 +mem_region_fn_t *mmu_set_ext_address_space( mem_region_fn_t *ext )1.46 +{1.47 + mem_region_fn_t *old_ext = sh4_ext_address_space;1.48 + sh4_ext_address_space = ext;1.49 + mmu_set_tlb_enabled(IS_TLB_ENABLED());1.50 + return old_ext;1.51 +}1.52 +1.53 /**1.54 * MMU accessor functions just increment URC - fixup here if necessary1.55 */1.56 @@ -415,10 +440,10 @@1.57 mmu_utlb_register_all();1.58 } else {1.59 for( i=0, ptr = sh4_address_space; i<7; i++, ptr += LXDREAM_PAGE_TABLE_ENTRIES ) {1.60 - memcpy( ptr, ext_address_space, sizeof(mem_region_fn_t) * LXDREAM_PAGE_TABLE_ENTRIES );1.61 + memcpy( ptr, sh4_ext_address_space, sizeof(mem_region_fn_t) * LXDREAM_PAGE_TABLE_ENTRIES );1.62 }1.63 for( i=0, ptr = sh4_user_address_space; i<4; i++, ptr += LXDREAM_PAGE_TABLE_ENTRIES ) {1.64 - memcpy( ptr, ext_address_space, sizeof(mem_region_fn_t) * LXDREAM_PAGE_TABLE_ENTRIES );1.65 + memcpy( ptr, sh4_ext_address_space, sizeof(mem_region_fn_t) * LXDREAM_PAGE_TABLE_ENTRIES );1.66 }1.68 mmu_register_mem_region( 0xE0000000, 0xE4000000, &p4_region_storequeue );1.69 @@ -1190,6 +1215,219 @@1.70 }1.71 }1.73 +/**1.74 + * Translate a virtual to physical address for reading, raising exceptions as1.75 + * observed.1.76 + * @param addr Pointer to the virtual memory address. On successful return,1.77 + * will be updated to contain the physical address.1.78 + */1.79 +mem_region_fn_t FASTCALL mmu_get_region_for_vma_read( sh4vma_t *paddr )1.80 +{1.81 + sh4vma_t addr = *paddr;1.82 + uint32_t mmucr = MMIO_READ(MMU,MMUCR);1.83 + if( addr & 0x80000000 ) {1.84 + if( IS_SH4_PRIVMODE() ) {1.85 + if( addr >= 0xE0000000 ) {1.86 + return sh4_address_space[((uint32_t)addr)>>12]; /* P4 - passthrough */1.87 + } else if( addr < 0xC0000000 ) {1.88 + /* P1, P2 regions are pass-through (no translation) */1.89 + return sh4_ext_address_space[VMA_TO_EXT_ADDR(addr)>>12];1.90 + }1.91 + } else {1.92 + if( addr >= 0xE0000000 && addr < 0xE4000000 &&1.93 + ((mmucr&MMUCR_SQMD) == 0) ) {1.94 + /* Conditional user-mode access to the store-queue (no translation) */1.95 + return &p4_region_storequeue;1.96 + }1.97 + sh4_raise_exception(EXC_DATA_ADDR_READ);1.98 + return NULL;1.99 + }1.100 + }1.101 +1.102 + if( (mmucr & MMUCR_AT) == 0 ) {1.103 + return sh4_ext_address_space[VMA_TO_EXT_ADDR(addr)>>12];1.104 + }1.105 +1.106 + /* If we get this far, translation is required */1.107 + int entryNo;1.108 + if( ((mmucr & MMUCR_SV) == 0) || !IS_SH4_PRIVMODE() ) {1.109 + entryNo = mmu_utlb_lookup_vpn_asid( addr );1.110 + } else {1.111 + entryNo = mmu_utlb_lookup_vpn( addr );1.112 + }1.113 +1.114 + switch(entryNo) {1.115 + case -1:1.116 + RAISE_TLB_ERROR(EXC_TLB_MISS_READ,addr);1.117 + return NULL;1.118 + case -2:1.119 + RAISE_TLB_MULTIHIT_ERROR(addr);1.120 + return NULL;1.121 + default:1.122 + if( (mmu_utlb[entryNo].flags & TLB_USERMODE) == 0 &&1.123 + !IS_SH4_PRIVMODE() ) {1.124 + /* protection violation */1.125 + RAISE_MEM_ERROR(EXC_TLB_PROT_READ,addr);1.126 + return NULL;1.127 + }1.128 +1.129 + /* finally generate the target address */1.130 + sh4addr_t pma = (mmu_utlb[entryNo].ppn & mmu_utlb[entryNo].mask) |1.131 + (addr & (~mmu_utlb[entryNo].mask));1.132 + if( pma > 0x1C000000 ) { // Remap 1Cxx .. 1Fxx region to P41.133 + addr = pma | 0xE0000000;1.134 + *paddr = addr;1.135 + return sh4_address_space[addr>>12];1.136 + } else {1.137 + *paddr = pma;1.138 + return sh4_ext_address_space[pma>>12];1.139 + }1.140 + }1.141 +}1.142 +1.143 +/**1.144 + * Translate a virtual to physical address for prefetch, which mostly1.145 + * does not raise exceptions.1.146 + * @param addr Pointer to the virtual memory address. On successful return,1.147 + * will be updated to contain the physical address.1.148 + */1.149 +mem_region_fn_t FASTCALL mmu_get_region_for_vma_prefetch( sh4vma_t *paddr )1.150 +{1.151 + sh4vma_t addr = *paddr;1.152 + uint32_t mmucr = MMIO_READ(MMU,MMUCR);1.153 + if( addr & 0x80000000 ) {1.154 + if( IS_SH4_PRIVMODE() ) {1.155 + if( addr >= 0xE0000000 ) {1.156 + return sh4_address_space[((uint32_t)addr)>>12]; /* P4 - passthrough */1.157 + } else if( addr < 0xC0000000 ) {1.158 + /* P1, P2 regions are pass-through (no translation) */1.159 + return sh4_ext_address_space[VMA_TO_EXT_ADDR(addr)>>12];1.160 + }1.161 + } else {1.162 + if( addr >= 0xE0000000 && addr < 0xE4000000 &&1.163 + ((mmucr&MMUCR_SQMD) == 0) ) {1.164 + /* Conditional user-mode access to the store-queue (no translation) */1.165 + return &p4_region_storequeue;1.166 + }1.167 + sh4_raise_exception(EXC_DATA_ADDR_READ);1.168 + return NULL;1.169 + }1.170 + }1.171 +1.172 + if( (mmucr & MMUCR_AT) == 0 ) {1.173 + return sh4_ext_address_space[VMA_TO_EXT_ADDR(addr)>>12];1.174 + }1.175 +1.176 + /* If we get this far, translation is required */1.177 + int entryNo;1.178 + if( ((mmucr & MMUCR_SV) == 0) || !IS_SH4_PRIVMODE() ) {1.179 + entryNo = mmu_utlb_lookup_vpn_asid( addr );1.180 + } else {1.181 + entryNo = mmu_utlb_lookup_vpn( addr );1.182 + }1.183 +1.184 + switch(entryNo) {1.185 + case -1:1.186 + return &mem_region_unmapped;1.187 + case -2:1.188 + RAISE_TLB_MULTIHIT_ERROR(addr);1.189 + return NULL;1.190 + default:1.191 + if( (mmu_utlb[entryNo].flags & TLB_USERMODE) == 0 &&1.192 + !IS_SH4_PRIVMODE() ) {1.193 + /* protection violation */1.194 + return &mem_region_unmapped;1.195 + }1.196 +1.197 + /* finally generate the target address */1.198 + sh4addr_t pma = (mmu_utlb[entryNo].ppn & mmu_utlb[entryNo].mask) |1.199 + (addr & (~mmu_utlb[entryNo].mask));1.200 + if( pma > 0x1C000000 ) { // Remap 1Cxx .. 1Fxx region to P41.201 + addr = pma | 0xE0000000;1.202 + *paddr = addr;1.203 + return sh4_address_space[addr>>12];1.204 + } else {1.205 + *paddr = pma;1.206 + return sh4_ext_address_space[pma>>12];1.207 + }1.208 + }1.209 +}1.210 +1.211 +/**1.212 + * Translate a virtual to physical address for writing, raising exceptions as1.213 + * observed.1.214 + */1.215 +mem_region_fn_t FASTCALL mmu_get_region_for_vma_write( sh4vma_t *paddr )1.216 +{1.217 + sh4vma_t addr = *paddr;1.218 + uint32_t mmucr = MMIO_READ(MMU,MMUCR);1.219 + if( addr & 0x80000000 ) {1.220 + if( IS_SH4_PRIVMODE() ) {1.221 + if( addr >= 0xE0000000 ) {1.222 + return sh4_address_space[((uint32_t)addr)>>12]; /* P4 - passthrough */1.223 + } else if( addr < 0xC0000000 ) {1.224 + /* P1, P2 regions are pass-through (no translation) */1.225 + return sh4_ext_address_space[VMA_TO_EXT_ADDR(addr)>>12];1.226 + }1.227 + } else {1.228 + if( addr >= 0xE0000000 && addr < 0xE4000000 &&1.229 + ((mmucr&MMUCR_SQMD) == 0) ) {1.230 + /* Conditional user-mode access to the store-queue (no translation) */1.231 + return &p4_region_storequeue;1.232 + }1.233 + sh4_raise_exception(EXC_DATA_ADDR_WRITE);1.234 + return NULL;1.235 + }1.236 + }1.237 +1.238 + if( (mmucr & MMUCR_AT) == 0 ) {1.239 + return sh4_ext_address_space[VMA_TO_EXT_ADDR(addr)>>12];1.240 + }1.241 +1.242 + /* If we get this far, translation is required */1.243 + int entryNo;1.244 + if( ((mmucr & MMUCR_SV) == 0) || !IS_SH4_PRIVMODE() ) {1.245 + entryNo = mmu_utlb_lookup_vpn_asid( addr );1.246 + } else {1.247 + entryNo = mmu_utlb_lookup_vpn( addr );1.248 + }1.249 +1.250 + switch(entryNo) {1.251 + case -1:1.252 + RAISE_TLB_ERROR(EXC_TLB_MISS_WRITE,addr);1.253 + return NULL;1.254 + case -2:1.255 + RAISE_TLB_MULTIHIT_ERROR(addr);1.256 + return NULL;1.257 + default:1.258 + if( IS_SH4_PRIVMODE() ? ((mmu_utlb[entryNo].flags & TLB_WRITABLE) == 0)1.259 + : ((mmu_utlb[entryNo].flags & TLB_USERWRITABLE) != TLB_USERWRITABLE) ) {1.260 + /* protection violation */1.261 + RAISE_MEM_ERROR(EXC_TLB_PROT_WRITE,addr);1.262 + return NULL;1.263 + }1.264 +1.265 + if( (mmu_utlb[entryNo].flags & TLB_DIRTY) == 0 ) {1.266 + RAISE_MEM_ERROR(EXC_INIT_PAGE_WRITE, addr);1.267 + return NULL;1.268 + }1.269 +1.270 + /* finally generate the target address */1.271 + sh4addr_t pma = (mmu_utlb[entryNo].ppn & mmu_utlb[entryNo].mask) |1.272 + (addr & (~mmu_utlb[entryNo].mask));1.273 + if( pma > 0x1C000000 ) { // Remap 1Cxx .. 1Fxx region to P41.274 + addr = pma | 0xE0000000;1.275 + *paddr = addr;1.276 + return sh4_address_space[addr>>12];1.277 + } else {1.278 + *paddr = pma;1.279 + return sh4_ext_address_space[pma>>12];1.280 + }1.281 + }1.282 +}1.283 +1.284 +1.285 +1.286 /********************** TLB Direct-Access Regions ***************************/1.287 #define ITLB_ENTRY(addr) ((addr>>7)&0x03)
.