1fdf9b3e8Sbellard /* 2fdf9b3e8Sbellard * SH4 emulation 3fdf9b3e8Sbellard * 4fdf9b3e8Sbellard * Copyright (c) 2005 Samuel Tardieu 5fdf9b3e8Sbellard * 6fdf9b3e8Sbellard * This library is free software; you can redistribute it and/or 7fdf9b3e8Sbellard * modify it under the terms of the GNU Lesser General Public 8fdf9b3e8Sbellard * License as published by the Free Software Foundation; either 9fdf9b3e8Sbellard * version 2 of the License, or (at your option) any later version. 10fdf9b3e8Sbellard * 11fdf9b3e8Sbellard * This library is distributed in the hope that it will be useful, 12fdf9b3e8Sbellard * but WITHOUT ANY WARRANTY; without even the implied warranty of 13fdf9b3e8Sbellard * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14fdf9b3e8Sbellard * Lesser General Public License for more details. 15fdf9b3e8Sbellard * 16fdf9b3e8Sbellard * You should have received a copy of the GNU Lesser General Public 17fdf9b3e8Sbellard * License along with this library; if not, write to the Free Software 18fdf9b3e8Sbellard * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19fdf9b3e8Sbellard */ 20fdf9b3e8Sbellard #include <stdarg.h> 21fdf9b3e8Sbellard #include <stdlib.h> 22fdf9b3e8Sbellard #include <stdio.h> 23fdf9b3e8Sbellard #include <string.h> 24fdf9b3e8Sbellard #include <inttypes.h> 25fdf9b3e8Sbellard #include <signal.h> 26fdf9b3e8Sbellard #include <assert.h> 27fdf9b3e8Sbellard 28fdf9b3e8Sbellard #include "cpu.h" 29fdf9b3e8Sbellard #include "exec-all.h" 30e96e2044Sths #include "hw/sh_intc.h" 31fdf9b3e8Sbellard 32355fb23dSpbrook #if defined(CONFIG_USER_ONLY) 33355fb23dSpbrook 34355fb23dSpbrook void do_interrupt (CPUState *env) 35355fb23dSpbrook { 36355fb23dSpbrook env->exception_index = -1; 37355fb23dSpbrook } 38355fb23dSpbrook 39355fb23dSpbrook int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, 406ebbf390Sj_mayer int mmu_idx, int is_softmmu) 41355fb23dSpbrook { 42355fb23dSpbrook env->tea = address; 43c3b5bc8aSths env->exception_index = 0; 44355fb23dSpbrook switch (rw) { 45355fb23dSpbrook case 0: 46c3b5bc8aSths env->tea = address; 47355fb23dSpbrook env->exception_index = 0x0a0; 48355fb23dSpbrook break; 49355fb23dSpbrook case 1: 50c3b5bc8aSths env->tea = address; 51355fb23dSpbrook env->exception_index = 0x0c0; 52355fb23dSpbrook break; 53355fb23dSpbrook } 54355fb23dSpbrook return 1; 55355fb23dSpbrook } 56355fb23dSpbrook 579b3c35e0Sj_mayer target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) 58355fb23dSpbrook { 59355fb23dSpbrook return addr; 60355fb23dSpbrook } 61355fb23dSpbrook 62355fb23dSpbrook #else /* !CONFIG_USER_ONLY */ 63355fb23dSpbrook 64fdf9b3e8Sbellard #define MMU_OK 0 65fdf9b3e8Sbellard #define MMU_ITLB_MISS (-1) 66fdf9b3e8Sbellard #define MMU_ITLB_MULTIPLE (-2) 67fdf9b3e8Sbellard #define MMU_ITLB_VIOLATION (-3) 68fdf9b3e8Sbellard #define MMU_DTLB_MISS_READ (-4) 69fdf9b3e8Sbellard #define MMU_DTLB_MISS_WRITE (-5) 70fdf9b3e8Sbellard #define MMU_DTLB_INITIAL_WRITE (-6) 71fdf9b3e8Sbellard #define MMU_DTLB_VIOLATION_READ (-7) 72fdf9b3e8Sbellard #define MMU_DTLB_VIOLATION_WRITE (-8) 73fdf9b3e8Sbellard #define MMU_DTLB_MULTIPLE (-9) 74fdf9b3e8Sbellard #define MMU_DTLB_MISS (-10) 75fdf9b3e8Sbellard 76fdf9b3e8Sbellard void do_interrupt(CPUState * env) 77fdf9b3e8Sbellard { 78e96e2044Sths int do_irq = env->interrupt_request & CPU_INTERRUPT_HARD; 79e96e2044Sths int do_exp, irq_vector = env->exception_index; 80e96e2044Sths 81e96e2044Sths /* prioritize exceptions over interrupts */ 82e96e2044Sths 83e96e2044Sths do_exp = env->exception_index != -1; 84e96e2044Sths do_irq = do_irq && (env->exception_index == -1); 85e96e2044Sths 86e96e2044Sths if (env->sr & SR_BL) { 87e96e2044Sths if (do_exp && env->exception_index != 0x1e0) { 88e96e2044Sths env->exception_index = 0x000; /* masked exception -> reset */ 89e96e2044Sths } 90833ed386Saurel32 if (do_irq && !env->intr_at_halt) { 91e96e2044Sths return; /* masked */ 92e96e2044Sths } 93833ed386Saurel32 env->intr_at_halt = 0; 94e96e2044Sths } 95e96e2044Sths 96e96e2044Sths if (do_irq) { 97e96e2044Sths irq_vector = sh_intc_get_pending_vector(env->intc_handle, 98e96e2044Sths (env->sr >> 4) & 0xf); 99e96e2044Sths if (irq_vector == -1) { 100e96e2044Sths return; /* masked */ 101e96e2044Sths } 102e96e2044Sths } 103e96e2044Sths 104fdf9b3e8Sbellard if (loglevel & CPU_LOG_INT) { 105fdf9b3e8Sbellard const char *expname; 106fdf9b3e8Sbellard switch (env->exception_index) { 107fdf9b3e8Sbellard case 0x0e0: 108fdf9b3e8Sbellard expname = "addr_error"; 109fdf9b3e8Sbellard break; 110fdf9b3e8Sbellard case 0x040: 111fdf9b3e8Sbellard expname = "tlb_miss"; 112fdf9b3e8Sbellard break; 113fdf9b3e8Sbellard case 0x0a0: 114fdf9b3e8Sbellard expname = "tlb_violation"; 115fdf9b3e8Sbellard break; 116fdf9b3e8Sbellard case 0x180: 117fdf9b3e8Sbellard expname = "illegal_instruction"; 118fdf9b3e8Sbellard break; 119fdf9b3e8Sbellard case 0x1a0: 120fdf9b3e8Sbellard expname = "slot_illegal_instruction"; 121fdf9b3e8Sbellard break; 122fdf9b3e8Sbellard case 0x800: 123fdf9b3e8Sbellard expname = "fpu_disable"; 124fdf9b3e8Sbellard break; 125fdf9b3e8Sbellard case 0x820: 126fdf9b3e8Sbellard expname = "slot_fpu"; 127fdf9b3e8Sbellard break; 128fdf9b3e8Sbellard case 0x100: 129fdf9b3e8Sbellard expname = "data_write"; 130fdf9b3e8Sbellard break; 131fdf9b3e8Sbellard case 0x060: 132fdf9b3e8Sbellard expname = "dtlb_miss_write"; 133fdf9b3e8Sbellard break; 134fdf9b3e8Sbellard case 0x0c0: 135fdf9b3e8Sbellard expname = "dtlb_violation_write"; 136fdf9b3e8Sbellard break; 137fdf9b3e8Sbellard case 0x120: 138fdf9b3e8Sbellard expname = "fpu_exception"; 139fdf9b3e8Sbellard break; 140fdf9b3e8Sbellard case 0x080: 141fdf9b3e8Sbellard expname = "initial_page_write"; 142fdf9b3e8Sbellard break; 143fdf9b3e8Sbellard case 0x160: 144fdf9b3e8Sbellard expname = "trapa"; 145fdf9b3e8Sbellard break; 146fdf9b3e8Sbellard default: 147e96e2044Sths expname = do_irq ? "interrupt" : "???"; 148fdf9b3e8Sbellard break; 149fdf9b3e8Sbellard } 150fdf9b3e8Sbellard fprintf(logfile, "exception 0x%03x [%s] raised\n", 151e96e2044Sths irq_vector, expname); 152fdf9b3e8Sbellard cpu_dump_state(env, logfile, fprintf, 0); 153fdf9b3e8Sbellard } 154fdf9b3e8Sbellard 155fdf9b3e8Sbellard env->ssr = env->sr; 156e96e2044Sths env->spc = env->pc; 157fdf9b3e8Sbellard env->sgr = env->gregs[15]; 158fdf9b3e8Sbellard env->sr |= SR_BL | SR_MD | SR_RB; 159fdf9b3e8Sbellard 160274a9e70Saurel32 if (env->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { 161274a9e70Saurel32 /* Branch instruction should be executed again before delay slot. */ 162274a9e70Saurel32 env->spc -= 2; 163274a9e70Saurel32 /* Clear flags for exception/interrupt routine. */ 164274a9e70Saurel32 env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL | DELAY_SLOT_TRUE); 165274a9e70Saurel32 } 166274a9e70Saurel32 if (env->flags & DELAY_SLOT_CLEARME) 167274a9e70Saurel32 env->flags = 0; 168274a9e70Saurel32 169e96e2044Sths if (do_exp) { 170e96e2044Sths env->expevt = env->exception_index; 171fdf9b3e8Sbellard switch (env->exception_index) { 172e96e2044Sths case 0x000: 173e96e2044Sths case 0x020: 174fdf9b3e8Sbellard case 0x140: 175e96e2044Sths env->sr &= ~SR_FD; 176e96e2044Sths env->sr |= 0xf << 4; /* IMASK */ 177fdf9b3e8Sbellard env->pc = 0xa0000000; 178fdf9b3e8Sbellard break; 179e96e2044Sths case 0x040: 180e96e2044Sths case 0x060: 181e96e2044Sths env->pc = env->vbr + 0x400; 182e96e2044Sths break; 183e96e2044Sths case 0x160: 184e96e2044Sths env->spc += 2; /* special case for TRAPA */ 185e96e2044Sths /* fall through */ 186fdf9b3e8Sbellard default: 187fdf9b3e8Sbellard env->pc = env->vbr + 0x100; 188fdf9b3e8Sbellard break; 189fdf9b3e8Sbellard } 190e96e2044Sths return; 191e96e2044Sths } 192e96e2044Sths 193e96e2044Sths if (do_irq) { 194e96e2044Sths env->intevt = irq_vector; 195e96e2044Sths env->pc = env->vbr + 0x600; 196e96e2044Sths return; 197e96e2044Sths } 198fdf9b3e8Sbellard } 199fdf9b3e8Sbellard 200fdf9b3e8Sbellard static void update_itlb_use(CPUState * env, int itlbnb) 201fdf9b3e8Sbellard { 202fdf9b3e8Sbellard uint8_t or_mask = 0, and_mask = (uint8_t) - 1; 203fdf9b3e8Sbellard 204fdf9b3e8Sbellard switch (itlbnb) { 205fdf9b3e8Sbellard case 0: 206ea2b542aSaurel32 and_mask = 0x1f; 207fdf9b3e8Sbellard break; 208fdf9b3e8Sbellard case 1: 209fdf9b3e8Sbellard and_mask = 0xe7; 210fdf9b3e8Sbellard or_mask = 0x80; 211fdf9b3e8Sbellard break; 212fdf9b3e8Sbellard case 2: 213fdf9b3e8Sbellard and_mask = 0xfb; 214fdf9b3e8Sbellard or_mask = 0x50; 215fdf9b3e8Sbellard break; 216fdf9b3e8Sbellard case 3: 217fdf9b3e8Sbellard or_mask = 0x2c; 218fdf9b3e8Sbellard break; 219fdf9b3e8Sbellard } 220fdf9b3e8Sbellard 221ea2b542aSaurel32 env->mmucr &= (and_mask << 24) | 0x00ffffff; 222fdf9b3e8Sbellard env->mmucr |= (or_mask << 24); 223fdf9b3e8Sbellard } 224fdf9b3e8Sbellard 225fdf9b3e8Sbellard static int itlb_replacement(CPUState * env) 226fdf9b3e8Sbellard { 227fdf9b3e8Sbellard if ((env->mmucr & 0xe0000000) == 0xe0000000) 228fdf9b3e8Sbellard return 0; 229ea2b542aSaurel32 if ((env->mmucr & 0x98000000) == 0x18000000) 230fdf9b3e8Sbellard return 1; 231fdf9b3e8Sbellard if ((env->mmucr & 0x54000000) == 0x04000000) 232fdf9b3e8Sbellard return 2; 233fdf9b3e8Sbellard if ((env->mmucr & 0x2c000000) == 0x00000000) 234fdf9b3e8Sbellard return 3; 235fdf9b3e8Sbellard assert(0); 236fdf9b3e8Sbellard } 237fdf9b3e8Sbellard 238fdf9b3e8Sbellard /* Find the corresponding entry in the right TLB 239fdf9b3e8Sbellard Return entry, MMU_DTLB_MISS or MMU_DTLB_MULTIPLE 240fdf9b3e8Sbellard */ 241fdf9b3e8Sbellard static int find_tlb_entry(CPUState * env, target_ulong address, 242fdf9b3e8Sbellard tlb_t * entries, uint8_t nbtlb, int use_asid) 243fdf9b3e8Sbellard { 244fdf9b3e8Sbellard int match = MMU_DTLB_MISS; 245fdf9b3e8Sbellard uint32_t start, end; 246fdf9b3e8Sbellard uint8_t asid; 247fdf9b3e8Sbellard int i; 248fdf9b3e8Sbellard 249fdf9b3e8Sbellard asid = env->pteh & 0xff; 250fdf9b3e8Sbellard 251fdf9b3e8Sbellard for (i = 0; i < nbtlb; i++) { 252fdf9b3e8Sbellard if (!entries[i].v) 253fdf9b3e8Sbellard continue; /* Invalid entry */ 254fdf9b3e8Sbellard if (use_asid && entries[i].asid != asid && !entries[i].sh) 255fdf9b3e8Sbellard continue; /* Bad ASID */ 256fdf9b3e8Sbellard #if 0 257fdf9b3e8Sbellard switch (entries[i].sz) { 258fdf9b3e8Sbellard case 0: 259fdf9b3e8Sbellard size = 1024; /* 1kB */ 260fdf9b3e8Sbellard break; 261fdf9b3e8Sbellard case 1: 262fdf9b3e8Sbellard size = 4 * 1024; /* 4kB */ 263fdf9b3e8Sbellard break; 264fdf9b3e8Sbellard case 2: 265fdf9b3e8Sbellard size = 64 * 1024; /* 64kB */ 266fdf9b3e8Sbellard break; 267fdf9b3e8Sbellard case 3: 268fdf9b3e8Sbellard size = 1024 * 1024; /* 1MB */ 269fdf9b3e8Sbellard break; 270fdf9b3e8Sbellard default: 271fdf9b3e8Sbellard assert(0); 272fdf9b3e8Sbellard } 273fdf9b3e8Sbellard #endif 274fdf9b3e8Sbellard start = (entries[i].vpn << 10) & ~(entries[i].size - 1); 275fdf9b3e8Sbellard end = start + entries[i].size - 1; 276fdf9b3e8Sbellard if (address >= start && address <= end) { /* Match */ 277ea2b542aSaurel32 if (match != MMU_DTLB_MISS) 278fdf9b3e8Sbellard return MMU_DTLB_MULTIPLE; /* Multiple match */ 279fdf9b3e8Sbellard match = i; 280fdf9b3e8Sbellard } 281fdf9b3e8Sbellard } 282fdf9b3e8Sbellard return match; 283fdf9b3e8Sbellard } 284fdf9b3e8Sbellard 285fdf9b3e8Sbellard /* Find itlb entry - update itlb from utlb if necessary and asked for 286fdf9b3e8Sbellard Return entry, MMU_ITLB_MISS, MMU_ITLB_MULTIPLE or MMU_DTLB_MULTIPLE 287fdf9b3e8Sbellard Update the itlb from utlb if update is not 0 288fdf9b3e8Sbellard */ 289fdf9b3e8Sbellard int find_itlb_entry(CPUState * env, target_ulong address, 290fdf9b3e8Sbellard int use_asid, int update) 291fdf9b3e8Sbellard { 292fdf9b3e8Sbellard int e, n; 293fdf9b3e8Sbellard 294fdf9b3e8Sbellard e = find_tlb_entry(env, address, env->itlb, ITLB_SIZE, use_asid); 295fdf9b3e8Sbellard if (e == MMU_DTLB_MULTIPLE) 296fdf9b3e8Sbellard e = MMU_ITLB_MULTIPLE; 297fdf9b3e8Sbellard else if (e == MMU_DTLB_MISS && update) { 298fdf9b3e8Sbellard e = find_tlb_entry(env, address, env->utlb, UTLB_SIZE, use_asid); 299fdf9b3e8Sbellard if (e >= 0) { 300fdf9b3e8Sbellard n = itlb_replacement(env); 301fdf9b3e8Sbellard env->itlb[n] = env->utlb[e]; 302fdf9b3e8Sbellard e = n; 303ea2b542aSaurel32 } else if (e == MMU_DTLB_MISS) 304ea2b542aSaurel32 e = MMU_ITLB_MISS; 305ea2b542aSaurel32 } else if (e == MMU_DTLB_MISS) 306ea2b542aSaurel32 e = MMU_ITLB_MISS; 307fdf9b3e8Sbellard if (e >= 0) 308fdf9b3e8Sbellard update_itlb_use(env, e); 309fdf9b3e8Sbellard return e; 310fdf9b3e8Sbellard } 311fdf9b3e8Sbellard 312fdf9b3e8Sbellard /* Find utlb entry 313fdf9b3e8Sbellard Return entry, MMU_DTLB_MISS, MMU_DTLB_MULTIPLE */ 314fdf9b3e8Sbellard int find_utlb_entry(CPUState * env, target_ulong address, int use_asid) 315fdf9b3e8Sbellard { 316fdf9b3e8Sbellard uint8_t urb, urc; 317fdf9b3e8Sbellard 318fdf9b3e8Sbellard /* Increment URC */ 319fdf9b3e8Sbellard urb = ((env->mmucr) >> 18) & 0x3f; 320fdf9b3e8Sbellard urc = ((env->mmucr) >> 10) & 0x3f; 321fdf9b3e8Sbellard urc++; 322fdf9b3e8Sbellard if (urc == urb || urc == UTLB_SIZE - 1) 323fdf9b3e8Sbellard urc = 0; 324fdf9b3e8Sbellard env->mmucr = (env->mmucr & 0xffff03ff) | (urc << 10); 325fdf9b3e8Sbellard 326fdf9b3e8Sbellard /* Return entry */ 327fdf9b3e8Sbellard return find_tlb_entry(env, address, env->utlb, UTLB_SIZE, use_asid); 328fdf9b3e8Sbellard } 329fdf9b3e8Sbellard 330fdf9b3e8Sbellard /* Match address against MMU 331fdf9b3e8Sbellard Return MMU_OK, MMU_DTLB_MISS_READ, MMU_DTLB_MISS_WRITE, 332fdf9b3e8Sbellard MMU_DTLB_INITIAL_WRITE, MMU_DTLB_VIOLATION_READ, 333fdf9b3e8Sbellard MMU_DTLB_VIOLATION_WRITE, MMU_ITLB_MISS, 334fdf9b3e8Sbellard MMU_ITLB_MULTIPLE, MMU_ITLB_VIOLATION 335fdf9b3e8Sbellard */ 336fdf9b3e8Sbellard static int get_mmu_address(CPUState * env, target_ulong * physical, 337fdf9b3e8Sbellard int *prot, target_ulong address, 338fdf9b3e8Sbellard int rw, int access_type) 339fdf9b3e8Sbellard { 340fdf9b3e8Sbellard int use_asid, is_code, n; 341fdf9b3e8Sbellard tlb_t *matching = NULL; 342fdf9b3e8Sbellard 343fdf9b3e8Sbellard use_asid = (env->mmucr & MMUCR_SV) == 0 && (env->sr & SR_MD) == 0; 344fdf9b3e8Sbellard is_code = env->pc == address; /* Hack */ 345fdf9b3e8Sbellard 346fdf9b3e8Sbellard /* Use a hack to find if this is an instruction or data access */ 347fdf9b3e8Sbellard if (env->pc == address && !(rw & PAGE_WRITE)) { 348fdf9b3e8Sbellard n = find_itlb_entry(env, address, use_asid, 1); 349fdf9b3e8Sbellard if (n >= 0) { 350fdf9b3e8Sbellard matching = &env->itlb[n]; 351fdf9b3e8Sbellard if ((env->sr & SR_MD) & !(matching->pr & 2)) 352fdf9b3e8Sbellard n = MMU_ITLB_VIOLATION; 353fdf9b3e8Sbellard else 354fdf9b3e8Sbellard *prot = PAGE_READ; 355fdf9b3e8Sbellard } 356fdf9b3e8Sbellard } else { 357fdf9b3e8Sbellard n = find_utlb_entry(env, address, use_asid); 358fdf9b3e8Sbellard if (n >= 0) { 359fdf9b3e8Sbellard matching = &env->utlb[n]; 360fdf9b3e8Sbellard switch ((matching->pr << 1) | ((env->sr & SR_MD) ? 1 : 0)) { 361fdf9b3e8Sbellard case 0: /* 000 */ 362fdf9b3e8Sbellard case 2: /* 010 */ 363fdf9b3e8Sbellard n = (rw & PAGE_WRITE) ? MMU_DTLB_VIOLATION_WRITE : 364fdf9b3e8Sbellard MMU_DTLB_VIOLATION_READ; 365fdf9b3e8Sbellard break; 366fdf9b3e8Sbellard case 1: /* 001 */ 367fdf9b3e8Sbellard case 4: /* 100 */ 368fdf9b3e8Sbellard case 5: /* 101 */ 369fdf9b3e8Sbellard if (rw & PAGE_WRITE) 370fdf9b3e8Sbellard n = MMU_DTLB_VIOLATION_WRITE; 371fdf9b3e8Sbellard else 372fdf9b3e8Sbellard *prot = PAGE_READ; 373fdf9b3e8Sbellard break; 374fdf9b3e8Sbellard case 3: /* 011 */ 375fdf9b3e8Sbellard case 6: /* 110 */ 376fdf9b3e8Sbellard case 7: /* 111 */ 377fdf9b3e8Sbellard *prot = rw & (PAGE_READ | PAGE_WRITE); 378fdf9b3e8Sbellard break; 379fdf9b3e8Sbellard } 380fdf9b3e8Sbellard } else if (n == MMU_DTLB_MISS) { 381fdf9b3e8Sbellard n = (rw & PAGE_WRITE) ? MMU_DTLB_MISS_WRITE : 382fdf9b3e8Sbellard MMU_DTLB_MISS_READ; 383fdf9b3e8Sbellard } 384fdf9b3e8Sbellard } 385fdf9b3e8Sbellard if (n >= 0) { 386fdf9b3e8Sbellard *physical = ((matching->ppn << 10) & ~(matching->size - 1)) | 387fdf9b3e8Sbellard (address & (matching->size - 1)); 388fdf9b3e8Sbellard if ((rw & PAGE_WRITE) & !matching->d) 389fdf9b3e8Sbellard n = MMU_DTLB_INITIAL_WRITE; 390fdf9b3e8Sbellard else 391fdf9b3e8Sbellard n = MMU_OK; 392fdf9b3e8Sbellard } 393fdf9b3e8Sbellard return n; 394fdf9b3e8Sbellard } 395fdf9b3e8Sbellard 396fdf9b3e8Sbellard int get_physical_address(CPUState * env, target_ulong * physical, 397fdf9b3e8Sbellard int *prot, target_ulong address, 398fdf9b3e8Sbellard int rw, int access_type) 399fdf9b3e8Sbellard { 400fdf9b3e8Sbellard /* P1, P2 and P4 areas do not use translation */ 401fdf9b3e8Sbellard if ((address >= 0x80000000 && address < 0xc0000000) || 402fdf9b3e8Sbellard address >= 0xe0000000) { 403fdf9b3e8Sbellard if (!(env->sr & SR_MD) 404fdf9b3e8Sbellard && (address < 0xe0000000 || address > 0xe4000000)) { 405fdf9b3e8Sbellard /* Unauthorized access in user mode (only store queues are available) */ 406fdf9b3e8Sbellard fprintf(stderr, "Unauthorized access\n"); 407fdf9b3e8Sbellard return (rw & PAGE_WRITE) ? MMU_DTLB_MISS_WRITE : 408fdf9b3e8Sbellard MMU_DTLB_MISS_READ; 409fdf9b3e8Sbellard } 410fdf9b3e8Sbellard /* Mask upper 3 bits */ 411fdf9b3e8Sbellard *physical = address & 0x1FFFFFFF; 412fdf9b3e8Sbellard *prot = PAGE_READ | PAGE_WRITE; 413fdf9b3e8Sbellard return MMU_OK; 414fdf9b3e8Sbellard } 415fdf9b3e8Sbellard 416fdf9b3e8Sbellard /* If MMU is disabled, return the corresponding physical page */ 417fdf9b3e8Sbellard if (!env->mmucr & MMUCR_AT) { 418fdf9b3e8Sbellard *physical = address & 0x1FFFFFFF; 419fdf9b3e8Sbellard *prot = PAGE_READ | PAGE_WRITE; 420fdf9b3e8Sbellard return MMU_OK; 421fdf9b3e8Sbellard } 422fdf9b3e8Sbellard 423fdf9b3e8Sbellard /* We need to resort to the MMU */ 424fdf9b3e8Sbellard return get_mmu_address(env, physical, prot, address, rw, access_type); 425fdf9b3e8Sbellard } 426fdf9b3e8Sbellard 427fdf9b3e8Sbellard int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, 4286ebbf390Sj_mayer int mmu_idx, int is_softmmu) 429fdf9b3e8Sbellard { 430fdf9b3e8Sbellard target_ulong physical, page_offset, page_size; 431fdf9b3e8Sbellard int prot, ret, access_type; 432fdf9b3e8Sbellard 433ea2b542aSaurel32 switch (rw) { 434ea2b542aSaurel32 case 0: 435ea2b542aSaurel32 rw = PAGE_READ; 436ea2b542aSaurel32 break; 437ea2b542aSaurel32 case 1: 438ea2b542aSaurel32 rw = PAGE_WRITE; 439ea2b542aSaurel32 break; 440ea2b542aSaurel32 case 2: /* READ_ACCESS_TYPE == 2 defined in softmmu_template.h */ 441ea2b542aSaurel32 rw = PAGE_READ; 442ea2b542aSaurel32 break; 443ea2b542aSaurel32 default: 444ea2b542aSaurel32 /* fatal error */ 445ea2b542aSaurel32 assert(0); 446ea2b542aSaurel32 } 447ea2b542aSaurel32 448fdf9b3e8Sbellard /* XXXXX */ 449fdf9b3e8Sbellard #if 0 4506ebbf390Sj_mayer fprintf(stderr, "%s pc %08x ad %08x rw %d mmu_idx %d smmu %d\n", 4516ebbf390Sj_mayer __func__, env->pc, address, rw, mmu_idx, is_softmmu); 452fdf9b3e8Sbellard #endif 453fdf9b3e8Sbellard 454fdf9b3e8Sbellard access_type = ACCESS_INT; 455fdf9b3e8Sbellard ret = 456fdf9b3e8Sbellard get_physical_address(env, &physical, &prot, address, rw, 457fdf9b3e8Sbellard access_type); 458fdf9b3e8Sbellard 459fdf9b3e8Sbellard if (ret != MMU_OK) { 460fdf9b3e8Sbellard env->tea = address; 461fdf9b3e8Sbellard switch (ret) { 462fdf9b3e8Sbellard case MMU_ITLB_MISS: 463fdf9b3e8Sbellard case MMU_DTLB_MISS_READ: 464fdf9b3e8Sbellard env->exception_index = 0x040; 465fdf9b3e8Sbellard break; 466fdf9b3e8Sbellard case MMU_DTLB_MULTIPLE: 467fdf9b3e8Sbellard case MMU_ITLB_MULTIPLE: 468fdf9b3e8Sbellard env->exception_index = 0x140; 469fdf9b3e8Sbellard break; 470fdf9b3e8Sbellard case MMU_ITLB_VIOLATION: 471fdf9b3e8Sbellard env->exception_index = 0x0a0; 472fdf9b3e8Sbellard break; 473fdf9b3e8Sbellard case MMU_DTLB_MISS_WRITE: 474fdf9b3e8Sbellard env->exception_index = 0x060; 475fdf9b3e8Sbellard break; 476fdf9b3e8Sbellard case MMU_DTLB_INITIAL_WRITE: 477fdf9b3e8Sbellard env->exception_index = 0x080; 478fdf9b3e8Sbellard break; 479fdf9b3e8Sbellard case MMU_DTLB_VIOLATION_READ: 480fdf9b3e8Sbellard env->exception_index = 0x0a0; 481fdf9b3e8Sbellard break; 482fdf9b3e8Sbellard case MMU_DTLB_VIOLATION_WRITE: 483fdf9b3e8Sbellard env->exception_index = 0x0c0; 484fdf9b3e8Sbellard break; 485fdf9b3e8Sbellard default: 486fdf9b3e8Sbellard assert(0); 487fdf9b3e8Sbellard } 488fdf9b3e8Sbellard return 1; 489fdf9b3e8Sbellard } 490fdf9b3e8Sbellard 491fdf9b3e8Sbellard page_size = TARGET_PAGE_SIZE; 492fdf9b3e8Sbellard page_offset = 493fdf9b3e8Sbellard (address - (address & TARGET_PAGE_MASK)) & ~(page_size - 1); 494fdf9b3e8Sbellard address = (address & TARGET_PAGE_MASK) + page_offset; 495fdf9b3e8Sbellard physical = (physical & TARGET_PAGE_MASK) + page_offset; 496fdf9b3e8Sbellard 4976ebbf390Sj_mayer return tlb_set_page(env, address, physical, prot, mmu_idx, is_softmmu); 498fdf9b3e8Sbellard } 499355fb23dSpbrook 5009b3c35e0Sj_mayer target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) 501355fb23dSpbrook { 502355fb23dSpbrook target_ulong physical; 503355fb23dSpbrook int prot; 504355fb23dSpbrook 505355fb23dSpbrook get_physical_address(env, &physical, &prot, addr, PAGE_READ, 0); 506355fb23dSpbrook return physical; 507355fb23dSpbrook } 508355fb23dSpbrook 509ea2b542aSaurel32 void cpu_load_tlb(CPUState * env) 510ea2b542aSaurel32 { 511ea2b542aSaurel32 int n = cpu_mmucr_urc(env->mmucr); 512ea2b542aSaurel32 tlb_t * entry = &env->utlb[n]; 513ea2b542aSaurel32 514ea2b542aSaurel32 /* Take values into cpu status from registers. */ 515ea2b542aSaurel32 entry->asid = (uint8_t)cpu_pteh_asid(env->pteh); 516ea2b542aSaurel32 entry->vpn = cpu_pteh_vpn(env->pteh); 517ea2b542aSaurel32 entry->v = (uint8_t)cpu_ptel_v(env->ptel); 518ea2b542aSaurel32 entry->ppn = cpu_ptel_ppn(env->ptel); 519ea2b542aSaurel32 entry->sz = (uint8_t)cpu_ptel_sz(env->ptel); 520ea2b542aSaurel32 switch (entry->sz) { 521ea2b542aSaurel32 case 0: /* 00 */ 522ea2b542aSaurel32 entry->size = 1024; /* 1K */ 523ea2b542aSaurel32 break; 524ea2b542aSaurel32 case 1: /* 01 */ 525ea2b542aSaurel32 entry->size = 1024 * 4; /* 4K */ 526ea2b542aSaurel32 break; 527ea2b542aSaurel32 case 2: /* 10 */ 528ea2b542aSaurel32 entry->size = 1024 * 64; /* 64K */ 529ea2b542aSaurel32 break; 530ea2b542aSaurel32 case 3: /* 11 */ 531ea2b542aSaurel32 entry->size = 1024 * 1024; /* 1M */ 532ea2b542aSaurel32 break; 533ea2b542aSaurel32 default: 534ea2b542aSaurel32 assert(0); 535ea2b542aSaurel32 break; 536ea2b542aSaurel32 } 537ea2b542aSaurel32 entry->sh = (uint8_t)cpu_ptel_sh(env->ptel); 538ea2b542aSaurel32 entry->c = (uint8_t)cpu_ptel_c(env->ptel); 539ea2b542aSaurel32 entry->pr = (uint8_t)cpu_ptel_pr(env->ptel); 540ea2b542aSaurel32 entry->d = (uint8_t)cpu_ptel_d(env->ptel); 541ea2b542aSaurel32 entry->wt = (uint8_t)cpu_ptel_wt(env->ptel); 542ea2b542aSaurel32 entry->sa = (uint8_t)cpu_ptea_sa(env->ptea); 543ea2b542aSaurel32 entry->tc = (uint8_t)cpu_ptea_tc(env->ptea); 544ea2b542aSaurel32 } 545ea2b542aSaurel32 546355fb23dSpbrook #endif 547