| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  *  Sparc MMU helpers | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Copyright (c) 2003-2005 Fabrice Bellard | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This library is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU Lesser General Public | 
					
						
							|  |  |  |  * License as published by the Free Software Foundation; either | 
					
						
							| 
									
										
										
										
											2020-10-23 12:42:35 +00:00
										 |  |  |  * version 2.1 of the License, or (at your option) any later version. | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * This library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
					
						
							|  |  |  |  * Lesser General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU Lesser General Public | 
					
						
							|  |  |  |  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-26 18:16:59 +00:00
										 |  |  | #include "qemu/osdep.h"
 | 
					
						
							| 
									
										
										
										
											2022-02-07 09:27:56 +01:00
										 |  |  | #include "qemu/log.h"
 | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | #include "cpu.h"
 | 
					
						
							| 
									
										
										
										
											2016-03-15 13:18:37 +01:00
										 |  |  | #include "exec/exec-all.h"
 | 
					
						
							| 
									
										
										
										
											2019-04-17 21:17:58 +02:00
										 |  |  | #include "qemu/qemu-print.h"
 | 
					
						
							| 
									
										
										
										
											2011-09-11 14:51:24 +00:00
										 |  |  | #include "trace.h"
 | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* Sparc MMU emulation */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef TARGET_SPARC64
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Sparc V8 Reference MMU (SRMMU) | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static const int access_table[8][8] = { | 
					
						
							|  |  |  |     { 0, 0, 0, 0, 8, 0, 12, 12 }, | 
					
						
							|  |  |  |     { 0, 0, 0, 0, 8, 0, 0, 0 }, | 
					
						
							|  |  |  |     { 8, 8, 0, 0, 0, 8, 12, 12 }, | 
					
						
							|  |  |  |     { 8, 8, 0, 0, 0, 8, 0, 0 }, | 
					
						
							|  |  |  |     { 8, 0, 8, 0, 8, 8, 12, 12 }, | 
					
						
							|  |  |  |     { 8, 0, 8, 0, 8, 0, 8, 0 }, | 
					
						
							|  |  |  |     { 8, 8, 8, 0, 8, 8, 12, 12 }, | 
					
						
							|  |  |  |     { 8, 8, 8, 0, 8, 8, 8, 0 } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const int perm_table[2][8] = { | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         PAGE_READ, | 
					
						
							|  |  |  |         PAGE_READ | PAGE_WRITE, | 
					
						
							|  |  |  |         PAGE_READ | PAGE_EXEC, | 
					
						
							|  |  |  |         PAGE_READ | PAGE_WRITE | PAGE_EXEC, | 
					
						
							|  |  |  |         PAGE_EXEC, | 
					
						
							|  |  |  |         PAGE_READ | PAGE_WRITE, | 
					
						
							|  |  |  |         PAGE_READ | PAGE_EXEC, | 
					
						
							|  |  |  |         PAGE_READ | PAGE_WRITE | PAGE_EXEC | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         PAGE_READ, | 
					
						
							|  |  |  |         PAGE_READ | PAGE_WRITE, | 
					
						
							|  |  |  |         PAGE_READ | PAGE_EXEC, | 
					
						
							|  |  |  |         PAGE_READ | PAGE_WRITE | PAGE_EXEC, | 
					
						
							|  |  |  |         PAGE_EXEC, | 
					
						
							|  |  |  |         PAGE_READ, | 
					
						
							|  |  |  |         0, | 
					
						
							|  |  |  |         0, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  | static int get_physical_address(CPUSPARCState *env, CPUTLBEntryFull *full, | 
					
						
							|  |  |  |                                 int *access_index, target_ulong address, | 
					
						
							|  |  |  |                                 int rw, int mmu_idx) | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     int access_perms = 0; | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |     hwaddr pde_ptr; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     uint32_t pde; | 
					
						
							|  |  |  |     int error_code = 0, is_dirty, is_user; | 
					
						
							|  |  |  |     unsigned long page_offset; | 
					
						
							| 
									
										
										
										
											2019-03-22 19:36:20 -07:00
										 |  |  |     CPUState *cs = env_cpu(env); | 
					
						
							| 
									
										
										
										
											2019-08-01 19:30:09 +01:00
										 |  |  |     MemTxResult result; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     is_user = mmu_idx == MMU_USER_IDX; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-12 21:01:29 -07:00
										 |  |  |     if (mmu_idx == MMU_PHYS_IDX) { | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |         full->lg_page_size = TARGET_PAGE_BITS; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |         /* Boot mode: instruction fetches are taken from PROM */ | 
					
						
							| 
									
										
										
										
											2017-08-24 18:31:26 +02:00
										 |  |  |         if (rw == 2 && (env->mmuregs[0] & env->def.mmu_bm)) { | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |             full->phys_addr = env->prom_addr | (address & 0x7ffffULL); | 
					
						
							|  |  |  |             full->prot = PAGE_READ | PAGE_EXEC; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |             return 0; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |         full->phys_addr = address; | 
					
						
							|  |  |  |         full->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user ? 0 : 1); | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |     full->phys_addr = 0xffffffffffff0000ULL; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* SPARC reference MMU table walk: Context table->L1->L2->PTE */ | 
					
						
							|  |  |  |     /* Context base + context number */ | 
					
						
							|  |  |  |     pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); | 
					
						
							| 
									
										
										
										
											2019-08-01 19:30:09 +01:00
										 |  |  |     pde = address_space_ldl(cs->as, pde_ptr, MEMTXATTRS_UNSPECIFIED, &result); | 
					
						
							|  |  |  |     if (result != MEMTX_OK) { | 
					
						
							|  |  |  |         return 4 << 2; /* Translation fault, L = 0 */ | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* Ctx pde */ | 
					
						
							|  |  |  |     switch (pde & PTE_ENTRYTYPE_MASK) { | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |     case 0: /* Invalid */ | 
					
						
							|  |  |  |         return 1 << 2; | 
					
						
							|  |  |  |     case 2: /* L0 PTE, maybe should not happen? */ | 
					
						
							|  |  |  |     case 3: /* Reserved */ | 
					
						
							|  |  |  |         return 4 << 2; | 
					
						
							|  |  |  |     case 1: /* L0 PDE */ | 
					
						
							|  |  |  |         pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); | 
					
						
							| 
									
										
										
										
											2019-08-01 19:30:09 +01:00
										 |  |  |         pde = address_space_ldl(cs->as, pde_ptr, | 
					
						
							|  |  |  |                                 MEMTXATTRS_UNSPECIFIED, &result); | 
					
						
							|  |  |  |         if (result != MEMTX_OK) { | 
					
						
							|  |  |  |             return (1 << 8) | (4 << 2); /* Translation fault, L = 1 */ | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         switch (pde & PTE_ENTRYTYPE_MASK) { | 
					
						
							|  |  |  |         default: | 
					
						
							|  |  |  |         case 0: /* Invalid */ | 
					
						
							|  |  |  |             return (1 << 8) | (1 << 2); | 
					
						
							|  |  |  |         case 3: /* Reserved */ | 
					
						
							|  |  |  |             return (1 << 8) | (4 << 2); | 
					
						
							|  |  |  |         case 1: /* L1 PDE */ | 
					
						
							|  |  |  |             pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); | 
					
						
							| 
									
										
										
										
											2019-08-01 19:30:09 +01:00
										 |  |  |             pde = address_space_ldl(cs->as, pde_ptr, | 
					
						
							|  |  |  |                                     MEMTXATTRS_UNSPECIFIED, &result); | 
					
						
							|  |  |  |             if (result != MEMTX_OK) { | 
					
						
							|  |  |  |                 return (2 << 8) | (4 << 2); /* Translation fault, L = 2 */ | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             switch (pde & PTE_ENTRYTYPE_MASK) { | 
					
						
							|  |  |  |             default: | 
					
						
							|  |  |  |             case 0: /* Invalid */ | 
					
						
							|  |  |  |                 return (2 << 8) | (1 << 2); | 
					
						
							|  |  |  |             case 3: /* Reserved */ | 
					
						
							|  |  |  |                 return (2 << 8) | (4 << 2); | 
					
						
							|  |  |  |             case 1: /* L2 PDE */ | 
					
						
							|  |  |  |                 pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); | 
					
						
							| 
									
										
										
										
											2019-08-01 19:30:09 +01:00
										 |  |  |                 pde = address_space_ldl(cs->as, pde_ptr, | 
					
						
							|  |  |  |                                         MEMTXATTRS_UNSPECIFIED, &result); | 
					
						
							|  |  |  |                 if (result != MEMTX_OK) { | 
					
						
							|  |  |  |                     return (3 << 8) | (4 << 2); /* Translation fault, L = 3 */ | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 switch (pde & PTE_ENTRYTYPE_MASK) { | 
					
						
							|  |  |  |                 default: | 
					
						
							|  |  |  |                 case 0: /* Invalid */ | 
					
						
							|  |  |  |                     return (3 << 8) | (1 << 2); | 
					
						
							|  |  |  |                 case 1: /* PDE, should not happen */ | 
					
						
							|  |  |  |                 case 3: /* Reserved */ | 
					
						
							|  |  |  |                     return (3 << 8) | (4 << 2); | 
					
						
							|  |  |  |                 case 2: /* L3 PTE */ | 
					
						
							| 
									
										
										
										
											2012-03-18 11:31:23 +00:00
										 |  |  |                     page_offset = 0; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |                 full->lg_page_size = TARGET_PAGE_BITS; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |                 break; | 
					
						
							|  |  |  |             case 2: /* L2 PTE */ | 
					
						
							| 
									
										
										
										
											2012-03-18 11:31:23 +00:00
										 |  |  |                 page_offset = address & 0x3f000; | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |                 full->lg_page_size = 18; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case 2: /* L1 PTE */ | 
					
						
							| 
									
										
										
										
											2012-03-18 11:31:23 +00:00
										 |  |  |             page_offset = address & 0xfff000; | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |             full->lg_page_size = 24; | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* check access */ | 
					
						
							|  |  |  |     access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT; | 
					
						
							|  |  |  |     error_code = access_table[*access_index][access_perms]; | 
					
						
							|  |  |  |     if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user)) { | 
					
						
							|  |  |  |         return error_code; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* update page modified and dirty bits */ | 
					
						
							|  |  |  |     is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK); | 
					
						
							|  |  |  |     if (!(pde & PG_ACCESSED_MASK) || is_dirty) { | 
					
						
							|  |  |  |         pde |= PG_ACCESSED_MASK; | 
					
						
							|  |  |  |         if (is_dirty) { | 
					
						
							|  |  |  |             pde |= PG_MODIFIED_MASK; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-11-28 10:13:41 +01:00
										 |  |  |         stl_phys_notdirty(cs->as, pde_ptr, pde); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* the page can be put in the TLB */ | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |     full->prot = perm_table[is_user][access_perms]; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     if (!(pde & PG_MODIFIED_MASK)) { | 
					
						
							|  |  |  |         /* only set write access if already dirty... otherwise wait
 | 
					
						
							|  |  |  |            for dirty access */ | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |         full->prot &= ~PAGE_WRITE; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Even if large ptes, we map only one 4KB page in the cache to
 | 
					
						
							|  |  |  |        avoid filling it too fast */ | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |     full->phys_addr = ((hwaddr)(pde & PTE_ADDR_MASK) << 4) + page_offset; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     return error_code; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Perform address translation */ | 
					
						
							| 
									
										
										
										
											2019-04-03 07:16:41 +07:00
										 |  |  | bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, int size, | 
					
						
							|  |  |  |                         MMUAccessType access_type, int mmu_idx, | 
					
						
							|  |  |  |                         bool probe, uintptr_t retaddr) | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-08-26 03:01:33 +02:00
										 |  |  |     SPARCCPU *cpu = SPARC_CPU(cs); | 
					
						
							|  |  |  |     CPUSPARCState *env = &cpu->env; | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |     CPUTLBEntryFull full = {}; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     target_ulong vaddr; | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |     int error_code = 0, access_index; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-03 07:16:41 +07:00
										 |  |  |     /*
 | 
					
						
							|  |  |  |      * TODO: If we ever need tlb_vaddr_to_host for this target, | 
					
						
							|  |  |  |      * then we must figure out how to manipulate FSR and FAR | 
					
						
							|  |  |  |      * when both MMU_NF and probe are set.  In the meantime, | 
					
						
							|  |  |  |      * do not support this use case. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     assert(!probe); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-18 11:31:23 +00:00
										 |  |  |     address &= TARGET_PAGE_MASK; | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |     error_code = get_physical_address(env, &full, &access_index, | 
					
						
							|  |  |  |                                       address, access_type, mmu_idx); | 
					
						
							| 
									
										
										
										
											2012-03-18 11:31:23 +00:00
										 |  |  |     vaddr = address; | 
					
						
							| 
									
										
										
										
											2019-04-03 07:16:41 +07:00
										 |  |  |     if (likely(error_code == 0)) { | 
					
						
							| 
									
										
										
										
											2014-12-13 19:48:18 +03:00
										 |  |  |         qemu_log_mask(CPU_LOG_MMU, | 
					
						
							| 
									
										
										
										
											2019-04-03 07:16:41 +07:00
										 |  |  |                       "Translate at %" VADDR_PRIx " -> " | 
					
						
							| 
									
										
										
										
											2023-01-10 22:29:47 +01:00
										 |  |  |                       HWADDR_FMT_plx ", vaddr " TARGET_FMT_lx "\n", | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |                       address, full.phys_addr, vaddr); | 
					
						
							|  |  |  |         tlb_set_page_full(cs, mmu_idx, vaddr, &full); | 
					
						
							| 
									
										
										
										
											2019-04-03 07:16:41 +07:00
										 |  |  |         return true; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (env->mmuregs[3]) { /* Fault status register */ | 
					
						
							|  |  |  |         env->mmuregs[3] = 1; /* overflow (not read before another fault) */ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     env->mmuregs[3] |= (access_index << 5) | error_code | 2; | 
					
						
							|  |  |  |     env->mmuregs[4] = address; /* Fault address register */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ((env->mmuregs[0] & MMU_NF) || env->psret == 0)  { | 
					
						
							|  |  |  |         /* No fault mode: if a mapping is available, just override
 | 
					
						
							|  |  |  |            permissions. If no mapping is available, redirect accesses to | 
					
						
							|  |  |  |            neverland. Fake/overridden mappings will be flushed when | 
					
						
							|  |  |  |            switching to normal mode. */ | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |         full.prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; | 
					
						
							|  |  |  |         tlb_set_page_full(cs, mmu_idx, vaddr, &full); | 
					
						
							| 
									
										
										
										
											2019-04-03 07:16:41 +07:00
										 |  |  |         return true; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2019-04-03 07:16:41 +07:00
										 |  |  |         if (access_type == MMU_INST_FETCH) { | 
					
						
							| 
									
										
										
										
											2013-08-26 08:31:06 +02:00
										 |  |  |             cs->exception_index = TT_TFAULT; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2013-08-26 08:31:06 +02:00
										 |  |  |             cs->exception_index = TT_DFAULT; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-04-03 07:16:41 +07:00
										 |  |  |         cpu_loop_exit_restore(cs, retaddr); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-14 01:38:22 +01:00
										 |  |  | target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev) | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-03-22 19:36:20 -07:00
										 |  |  |     CPUState *cs = env_cpu(env); | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |     hwaddr pde_ptr; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     uint32_t pde; | 
					
						
							| 
									
										
										
										
											2019-08-01 19:30:10 +01:00
										 |  |  |     MemTxResult result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * TODO: MMU probe operations are supposed to set the fault | 
					
						
							|  |  |  |      * status registers, but we don't do this. | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* Context base + context number */ | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |     pde_ptr = (hwaddr)(env->mmuregs[1] << 4) + | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |         (env->mmuregs[2] << 2); | 
					
						
							| 
									
										
										
										
											2019-08-01 19:30:10 +01:00
										 |  |  |     pde = address_space_ldl(cs->as, pde_ptr, MEMTXATTRS_UNSPECIFIED, &result); | 
					
						
							|  |  |  |     if (result != MEMTX_OK) { | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     switch (pde & PTE_ENTRYTYPE_MASK) { | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |     case 0: /* Invalid */ | 
					
						
							|  |  |  |     case 2: /* PTE, maybe should not happen? */ | 
					
						
							|  |  |  |     case 3: /* Reserved */ | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     case 1: /* L1 PDE */ | 
					
						
							|  |  |  |         if (mmulev == 3) { | 
					
						
							|  |  |  |             return pde; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); | 
					
						
							| 
									
										
										
										
											2019-08-01 19:30:10 +01:00
										 |  |  |         pde = address_space_ldl(cs->as, pde_ptr, | 
					
						
							|  |  |  |                                 MEMTXATTRS_UNSPECIFIED, &result); | 
					
						
							|  |  |  |         if (result != MEMTX_OK) { | 
					
						
							|  |  |  |             return 0; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         switch (pde & PTE_ENTRYTYPE_MASK) { | 
					
						
							|  |  |  |         default: | 
					
						
							|  |  |  |         case 0: /* Invalid */ | 
					
						
							|  |  |  |         case 3: /* Reserved */ | 
					
						
							|  |  |  |             return 0; | 
					
						
							|  |  |  |         case 2: /* L1 PTE */ | 
					
						
							|  |  |  |             return pde; | 
					
						
							|  |  |  |         case 1: /* L2 PDE */ | 
					
						
							|  |  |  |             if (mmulev == 2) { | 
					
						
							|  |  |  |                 return pde; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); | 
					
						
							| 
									
										
										
										
											2019-08-01 19:30:10 +01:00
										 |  |  |             pde = address_space_ldl(cs->as, pde_ptr, | 
					
						
							|  |  |  |                                     MEMTXATTRS_UNSPECIFIED, &result); | 
					
						
							|  |  |  |             if (result != MEMTX_OK) { | 
					
						
							|  |  |  |                 return 0; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             switch (pde & PTE_ENTRYTYPE_MASK) { | 
					
						
							|  |  |  |             default: | 
					
						
							|  |  |  |             case 0: /* Invalid */ | 
					
						
							|  |  |  |             case 3: /* Reserved */ | 
					
						
							|  |  |  |                 return 0; | 
					
						
							|  |  |  |             case 2: /* L2 PTE */ | 
					
						
							|  |  |  |                 return pde; | 
					
						
							|  |  |  |             case 1: /* L3 PDE */ | 
					
						
							|  |  |  |                 if (mmulev == 1) { | 
					
						
							|  |  |  |                     return pde; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); | 
					
						
							| 
									
										
										
										
											2019-08-01 19:30:10 +01:00
										 |  |  |                 pde = address_space_ldl(cs->as, pde_ptr, | 
					
						
							|  |  |  |                                         MEMTXATTRS_UNSPECIFIED, &result); | 
					
						
							|  |  |  |                 if (result != MEMTX_OK) { | 
					
						
							|  |  |  |                     return 0; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 switch (pde & PTE_ENTRYTYPE_MASK) { | 
					
						
							|  |  |  |                 default: | 
					
						
							|  |  |  |                 case 0: /* Invalid */ | 
					
						
							|  |  |  |                 case 1: /* PDE, should not happen */ | 
					
						
							|  |  |  |                 case 3: /* Reserved */ | 
					
						
							|  |  |  |                     return 0; | 
					
						
							|  |  |  |                 case 2: /* L3 PTE */ | 
					
						
							|  |  |  |                     return pde; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 21:17:58 +02:00
										 |  |  | void dump_mmu(CPUSPARCState *env) | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-03-22 19:36:20 -07:00
										 |  |  |     CPUState *cs = env_cpu(env); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     target_ulong va, va1, va2; | 
					
						
							|  |  |  |     unsigned int n, m, o; | 
					
						
							| 
									
										
										
										
											2019-08-01 19:30:11 +01:00
										 |  |  |     hwaddr pa; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     uint32_t pde; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-10 22:29:47 +01:00
										 |  |  |     qemu_printf("Root ptr: " HWADDR_FMT_plx ", ctx: %d\n", | 
					
						
							| 
									
										
										
										
											2019-04-17 21:17:58 +02:00
										 |  |  |                 (hwaddr)env->mmuregs[1] << 4, env->mmuregs[2]); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) { | 
					
						
							|  |  |  |         pde = mmu_probe(env, va, 2); | 
					
						
							|  |  |  |         if (pde) { | 
					
						
							| 
									
										
										
										
											2013-06-29 18:55:54 +02:00
										 |  |  |             pa = cpu_get_phys_page_debug(cs, va); | 
					
						
							| 
									
										
										
										
											2023-01-10 22:29:47 +01:00
										 |  |  |             qemu_printf("VA: " TARGET_FMT_lx ", PA: " HWADDR_FMT_plx | 
					
						
							| 
									
										
										
										
											2019-04-17 21:17:58 +02:00
										 |  |  |                         " PDE: " TARGET_FMT_lx "\n", va, pa, pde); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |             for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) { | 
					
						
							|  |  |  |                 pde = mmu_probe(env, va1, 1); | 
					
						
							|  |  |  |                 if (pde) { | 
					
						
							| 
									
										
										
										
											2013-06-29 18:55:54 +02:00
										 |  |  |                     pa = cpu_get_phys_page_debug(cs, va1); | 
					
						
							| 
									
										
										
										
											2019-04-17 21:17:58 +02:00
										 |  |  |                     qemu_printf(" VA: " TARGET_FMT_lx ", PA: " | 
					
						
							| 
									
										
										
										
											2023-01-10 22:29:47 +01:00
										 |  |  |                                 HWADDR_FMT_plx " PDE: " TARGET_FMT_lx "\n", | 
					
						
							| 
									
										
										
										
											2019-04-17 21:17:58 +02:00
										 |  |  |                                 va1, pa, pde); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |                     for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) { | 
					
						
							|  |  |  |                         pde = mmu_probe(env, va2, 0); | 
					
						
							|  |  |  |                         if (pde) { | 
					
						
							| 
									
										
										
										
											2013-06-29 18:55:54 +02:00
										 |  |  |                             pa = cpu_get_phys_page_debug(cs, va2); | 
					
						
							| 
									
										
										
										
											2019-04-17 21:17:58 +02:00
										 |  |  |                             qemu_printf("  VA: " TARGET_FMT_lx ", PA: " | 
					
						
							| 
									
										
										
										
											2023-01-10 22:29:47 +01:00
										 |  |  |                                         HWADDR_FMT_plx " PTE: " | 
					
						
							| 
									
										
										
										
											2019-04-17 21:17:58 +02:00
										 |  |  |                                         TARGET_FMT_lx "\n", | 
					
						
							|  |  |  |                                         va2, pa, pde); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Gdb expects all registers windows to be flushed in ram. This function handles
 | 
					
						
							|  |  |  |  * reads (and only reads) in stack frames as if windows were flushed. We assume | 
					
						
							|  |  |  |  * that the sparc ABI is followed. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2013-06-27 19:09:09 +02:00
										 |  |  | int sparc_cpu_memory_rw_debug(CPUState *cs, vaddr address, | 
					
						
							|  |  |  |                               uint8_t *buf, int len, bool is_write) | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-06-27 19:09:09 +02:00
										 |  |  |     SPARCCPU *cpu = SPARC_CPU(cs); | 
					
						
							|  |  |  |     CPUSPARCState *env = &cpu->env; | 
					
						
							|  |  |  |     target_ulong addr = address; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     int i; | 
					
						
							|  |  |  |     int len1; | 
					
						
							|  |  |  |     int cwp = env->cwp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!is_write) { | 
					
						
							|  |  |  |         for (i = 0; i < env->nwindows; i++) { | 
					
						
							|  |  |  |             int off; | 
					
						
							|  |  |  |             target_ulong fp = env->regbase[cwp * 16 + 22]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             /* Assume fp == 0 means end of frame.  */ | 
					
						
							|  |  |  |             if (fp == 0) { | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             cwp = cpu_cwp_inc(env, cwp + 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             /* Invalid window ? */ | 
					
						
							|  |  |  |             if (env->wim & (1 << cwp)) { | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             /* According to the ABI, the stack is growing downward.  */ | 
					
						
							|  |  |  |             if (addr + len < fp) { | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             /* Not in this frame.  */ | 
					
						
							|  |  |  |             if (addr > fp + 64) { | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             /* Handle access before this window.  */ | 
					
						
							|  |  |  |             if (addr < fp) { | 
					
						
							|  |  |  |                 len1 = fp - addr; | 
					
						
							| 
									
										
										
										
											2013-06-29 19:40:58 +02:00
										 |  |  |                 if (cpu_memory_rw_debug(cs, addr, buf, len1, is_write) != 0) { | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |                     return -1; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 addr += len1; | 
					
						
							|  |  |  |                 len -= len1; | 
					
						
							|  |  |  |                 buf += len1; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             /* Access byte per byte to registers. Not very efficient but speed
 | 
					
						
							|  |  |  |              * is not critical. | 
					
						
							|  |  |  |              */ | 
					
						
							|  |  |  |             off = addr - fp; | 
					
						
							|  |  |  |             len1 = 64 - off; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (len1 > len) { | 
					
						
							|  |  |  |                 len1 = len; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for (; len1; len1--) { | 
					
						
							|  |  |  |                 int reg = cwp * 16 + 8 + (off >> 2); | 
					
						
							|  |  |  |                 union { | 
					
						
							|  |  |  |                     uint32_t v; | 
					
						
							|  |  |  |                     uint8_t c[4]; | 
					
						
							|  |  |  |                 } u; | 
					
						
							|  |  |  |                 u.v = cpu_to_be32(env->regbase[reg]); | 
					
						
							|  |  |  |                 *buf++ = u.c[off & 3]; | 
					
						
							|  |  |  |                 addr++; | 
					
						
							|  |  |  |                 len--; | 
					
						
							|  |  |  |                 off++; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (len == 0) { | 
					
						
							|  |  |  |                 return 0; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-06-29 19:40:58 +02:00
										 |  |  |     return cpu_memory_rw_debug(cs, addr, buf, len, is_write); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #else /* !TARGET_SPARC64 */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* 41 bit physical address space */ | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | static inline hwaddr ultrasparc_truncate_physical(uint64_t x) | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     return x & 0x1ffffffffffULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * UltraSparc IIi I/DMMUs | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Returns true if TTE tag is valid and matches virtual address value
 | 
					
						
							|  |  |  |    in context requires virtual address mask value calculated from TTE | 
					
						
							|  |  |  |    entry size */ | 
					
						
							|  |  |  | static inline int ultrasparc_tag_match(SparcTLBEntry *tlb, | 
					
						
							|  |  |  |                                        uint64_t address, uint64_t context, | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |                                        hwaddr *physical) | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-03-03 14:03:41 +01:00
										 |  |  |     uint64_t mask = -(8192ULL << 3 * TTE_PGSIZE(tlb->tte)); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* valid, context match, virtual address match? */ | 
					
						
							|  |  |  |     if (TTE_IS_VALID(tlb->tte) && | 
					
						
							|  |  |  |         (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context)) | 
					
						
							|  |  |  |         && compare_masked(address, tlb->tag, mask)) { | 
					
						
							|  |  |  |         /* decode physical address */ | 
					
						
							|  |  |  |         *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL; | 
					
						
							|  |  |  |         return 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-30 07:55:06 -10:00
										 |  |  | static uint64_t build_sfsr(CPUSPARCState *env, int mmu_idx, int rw) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     uint64_t sfsr = SFSR_VALID_BIT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (mmu_idx) { | 
					
						
							|  |  |  |     case MMU_PHYS_IDX: | 
					
						
							|  |  |  |         sfsr |= SFSR_CT_NOTRANS; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case MMU_USER_IDX: | 
					
						
							|  |  |  |     case MMU_KERNEL_IDX: | 
					
						
							|  |  |  |         sfsr |= SFSR_CT_PRIMARY; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case MMU_USER_SECONDARY_IDX: | 
					
						
							|  |  |  |     case MMU_KERNEL_SECONDARY_IDX: | 
					
						
							|  |  |  |         sfsr |= SFSR_CT_SECONDARY; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case MMU_NUCLEUS_IDX: | 
					
						
							|  |  |  |         sfsr |= SFSR_CT_NUCLEUS; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         g_assert_not_reached(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (rw == 1) { | 
					
						
							|  |  |  |         sfsr |= SFSR_WRITE_BIT; | 
					
						
							|  |  |  |     } else if (rw == 4) { | 
					
						
							|  |  |  |         sfsr |= SFSR_NF_BIT; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (env->pstate & PS_PRIV) { | 
					
						
							|  |  |  |         sfsr |= SFSR_PR_BIT; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */ | 
					
						
							|  |  |  |         sfsr |= SFSR_OW_BIT; /* overflow (not read before another fault) */ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* FIXME: ASI field in SFSR must be set */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return sfsr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  | static int get_physical_address_data(CPUSPARCState *env, CPUTLBEntryFull *full, | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |                                      target_ulong address, int rw, int mmu_idx) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-03-22 19:36:20 -07:00
										 |  |  |     CPUState *cs = env_cpu(env); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     unsigned int i; | 
					
						
							| 
									
										
										
										
											2021-07-30 07:55:06 -10:00
										 |  |  |     uint64_t sfsr; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     uint64_t context; | 
					
						
							| 
									
										
										
										
											2016-07-12 21:01:29 -07:00
										 |  |  |     bool is_user = false; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-30 07:55:06 -10:00
										 |  |  |     sfsr = build_sfsr(env, mmu_idx, rw); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     switch (mmu_idx) { | 
					
						
							| 
									
										
										
										
											2016-07-12 21:01:29 -07:00
										 |  |  |     case MMU_PHYS_IDX: | 
					
						
							|  |  |  |         g_assert_not_reached(); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     case MMU_USER_IDX: | 
					
						
							| 
									
										
										
										
											2016-07-12 21:01:29 -07:00
										 |  |  |         is_user = true; | 
					
						
							|  |  |  |         /* fallthru */ | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     case MMU_KERNEL_IDX: | 
					
						
							|  |  |  |         context = env->dmmu.mmu_primary_context & 0x1fff; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case MMU_USER_SECONDARY_IDX: | 
					
						
							| 
									
										
										
										
											2016-07-12 21:01:29 -07:00
										 |  |  |         is_user = true; | 
					
						
							|  |  |  |         /* fallthru */ | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     case MMU_KERNEL_SECONDARY_IDX: | 
					
						
							|  |  |  |         context = env->dmmu.mmu_secondary_context & 0x1fff; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         context = 0; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (i = 0; i < 64; i++) { | 
					
						
							|  |  |  |         /* ctx match, vaddr match, valid? */ | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |         if (ultrasparc_tag_match(&env->dtlb[i], address, context, | 
					
						
							|  |  |  |                                  &full->phys_addr)) { | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |             int do_fault = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-24 04:36:58 +10:00
										 |  |  |             if (TTE_IS_IE(env->dtlb[i].tte)) { | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |                 full->attrs.byte_swap = true; | 
					
						
							| 
									
										
										
										
											2019-08-24 04:36:58 +10:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |             /* access ok? */ | 
					
						
							|  |  |  |             /* multiple bits in SFSR.FT may be set on TT_DFAULT */ | 
					
						
							|  |  |  |             if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) { | 
					
						
							|  |  |  |                 do_fault = 1; | 
					
						
							|  |  |  |                 sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */ | 
					
						
							| 
									
										
										
										
											2011-09-11 14:51:24 +00:00
										 |  |  |                 trace_mmu_helper_dfault(address, context, mmu_idx, env->tl); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |             if (rw == 4) { | 
					
						
							|  |  |  |                 if (TTE_IS_SIDEEFFECT(env->dtlb[i].tte)) { | 
					
						
							|  |  |  |                     do_fault = 1; | 
					
						
							|  |  |  |                     sfsr |= SFSR_FT_NF_E_BIT; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 if (TTE_IS_NFO(env->dtlb[i].tte)) { | 
					
						
							|  |  |  |                     do_fault = 1; | 
					
						
							|  |  |  |                     sfsr |= SFSR_FT_NFO_BIT; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (do_fault) { | 
					
						
							|  |  |  |                 /* faults above are reported with TT_DFAULT. */ | 
					
						
							| 
									
										
										
										
											2013-08-26 08:31:06 +02:00
										 |  |  |                 cs->exception_index = TT_DFAULT; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |             } else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) { | 
					
						
							|  |  |  |                 do_fault = 1; | 
					
						
							| 
									
										
										
										
											2013-08-26 08:31:06 +02:00
										 |  |  |                 cs->exception_index = TT_DPROT; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-11 14:51:24 +00:00
										 |  |  |                 trace_mmu_helper_dprot(address, context, mmu_idx, env->tl); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (!do_fault) { | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |                 full->prot = PAGE_READ; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |                 if (TTE_IS_W_OK(env->dtlb[i].tte)) { | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |                     full->prot |= PAGE_WRITE; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 TTE_SET_USED(env->dtlb[i].tte); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 return 0; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-30 07:55:06 -10:00
										 |  |  |             env->dmmu.sfsr = sfsr; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |             env->dmmu.sfar = address; /* Fault address register */ | 
					
						
							|  |  |  |             env->dmmu.tag_access = (address & ~0x1fffULL) | context; | 
					
						
							|  |  |  |             return 1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-11 14:51:24 +00:00
										 |  |  |     trace_mmu_helper_dmiss(address, context); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * On MMU misses: | 
					
						
							|  |  |  |      * - UltraSPARC IIi: SFSR and SFAR unmodified | 
					
						
							|  |  |  |      * - JPS1: SFAR updated and some fields of SFSR updated | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     env->dmmu.tag_access = (address & ~0x1fffULL) | context; | 
					
						
							| 
									
										
										
										
											2013-08-26 08:31:06 +02:00
										 |  |  |     cs->exception_index = TT_DMISS; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  | static int get_physical_address_code(CPUSPARCState *env, CPUTLBEntryFull *full, | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |                                      target_ulong address, int mmu_idx) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-03-22 19:36:20 -07:00
										 |  |  |     CPUState *cs = env_cpu(env); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     unsigned int i; | 
					
						
							|  |  |  |     uint64_t context; | 
					
						
							| 
									
										
										
										
											2016-07-12 21:01:29 -07:00
										 |  |  |     bool is_user = false; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-12 21:01:29 -07:00
										 |  |  |     switch (mmu_idx) { | 
					
						
							|  |  |  |     case MMU_PHYS_IDX: | 
					
						
							|  |  |  |     case MMU_USER_SECONDARY_IDX: | 
					
						
							|  |  |  |     case MMU_KERNEL_SECONDARY_IDX: | 
					
						
							|  |  |  |         g_assert_not_reached(); | 
					
						
							|  |  |  |     case MMU_USER_IDX: | 
					
						
							|  |  |  |         is_user = true; | 
					
						
							|  |  |  |         /* fallthru */ | 
					
						
							|  |  |  |     case MMU_KERNEL_IDX: | 
					
						
							|  |  |  |         context = env->dmmu.mmu_primary_context & 0x1fff; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         context = 0; | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (env->tl == 0) { | 
					
						
							|  |  |  |         /* PRIMARY context */ | 
					
						
							|  |  |  |         context = env->dmmu.mmu_primary_context & 0x1fff; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         /* NUCLEUS context */ | 
					
						
							|  |  |  |         context = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (i = 0; i < 64; i++) { | 
					
						
							|  |  |  |         /* ctx match, vaddr match, valid? */ | 
					
						
							|  |  |  |         if (ultrasparc_tag_match(&env->itlb[i], | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |                                  address, context, &full->phys_addr)) { | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |             /* access ok? */ | 
					
						
							|  |  |  |             if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) { | 
					
						
							|  |  |  |                 /* Fault status register */ | 
					
						
							|  |  |  |                 if (env->immu.sfsr & SFSR_VALID_BIT) { | 
					
						
							|  |  |  |                     env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before
 | 
					
						
							|  |  |  |                                                      another fault) */ | 
					
						
							|  |  |  |                 } else { | 
					
						
							|  |  |  |                     env->immu.sfsr = 0; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 if (env->pstate & PS_PRIV) { | 
					
						
							|  |  |  |                     env->immu.sfsr |= SFSR_PR_BIT; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 if (env->tl > 0) { | 
					
						
							|  |  |  |                     env->immu.sfsr |= SFSR_CT_NUCLEUS; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 /* FIXME: ASI field in SFSR must be set */ | 
					
						
							|  |  |  |                 env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT; | 
					
						
							| 
									
										
										
										
											2013-08-26 08:31:06 +02:00
										 |  |  |                 cs->exception_index = TT_TFAULT; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 env->immu.tag_access = (address & ~0x1fffULL) | context; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-11 14:51:24 +00:00
										 |  |  |                 trace_mmu_helper_tfault(address, context); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 return 1; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |             full->prot = PAGE_EXEC; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |             TTE_SET_USED(env->itlb[i].tte); | 
					
						
							|  |  |  |             return 0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-11 14:51:24 +00:00
										 |  |  |     trace_mmu_helper_tmiss(address, context); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */ | 
					
						
							|  |  |  |     env->immu.tag_access = (address & ~0x1fffULL) | context; | 
					
						
							| 
									
										
										
										
											2013-08-26 08:31:06 +02:00
										 |  |  |     cs->exception_index = TT_TMISS; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  | static int get_physical_address(CPUSPARCState *env, CPUTLBEntryFull *full, | 
					
						
							|  |  |  |                                 int *access_index, target_ulong address, | 
					
						
							|  |  |  |                                 int rw, int mmu_idx) | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     /* ??? We treat everything as a small page, then explicitly flush
 | 
					
						
							|  |  |  |        everything when an entry is evicted.  */ | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |     full->lg_page_size = TARGET_PAGE_BITS; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* safety net to catch wrong softmmu index use from dynamic code */ | 
					
						
							|  |  |  |     if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) { | 
					
						
							| 
									
										
										
										
											2011-09-11 14:51:24 +00:00
										 |  |  |         if (rw == 2) { | 
					
						
							|  |  |  |             trace_mmu_helper_get_phys_addr_code(env->tl, mmu_idx, | 
					
						
							|  |  |  |                                                 env->dmmu.mmu_primary_context, | 
					
						
							|  |  |  |                                                 env->dmmu.mmu_secondary_context, | 
					
						
							|  |  |  |                                                 address); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             trace_mmu_helper_get_phys_addr_data(env->tl, mmu_idx, | 
					
						
							|  |  |  |                                                 env->dmmu.mmu_primary_context, | 
					
						
							|  |  |  |                                                 env->dmmu.mmu_secondary_context, | 
					
						
							|  |  |  |                                                 address); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-12 21:01:29 -07:00
										 |  |  |     if (mmu_idx == MMU_PHYS_IDX) { | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |         full->phys_addr = ultrasparc_truncate_physical(address); | 
					
						
							|  |  |  |         full->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; | 
					
						
							| 
									
										
										
										
											2016-07-12 21:01:29 -07:00
										 |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     if (rw == 2) { | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |         return get_physical_address_code(env, full, address, mmu_idx); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |         return get_physical_address_data(env, full, address, rw, mmu_idx); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Perform address translation */ | 
					
						
							| 
									
										
										
										
											2019-04-03 07:16:41 +07:00
										 |  |  | bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, int size, | 
					
						
							|  |  |  |                         MMUAccessType access_type, int mmu_idx, | 
					
						
							|  |  |  |                         bool probe, uintptr_t retaddr) | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-08-26 03:01:33 +02:00
										 |  |  |     SPARCCPU *cpu = SPARC_CPU(cs); | 
					
						
							|  |  |  |     CPUSPARCState *env = &cpu->env; | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |     CPUTLBEntryFull full = {}; | 
					
						
							|  |  |  |     int error_code = 0, access_index; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-18 11:31:23 +00:00
										 |  |  |     address &= TARGET_PAGE_MASK; | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |     error_code = get_physical_address(env, &full, &access_index, | 
					
						
							|  |  |  |                                       address, access_type, mmu_idx); | 
					
						
							| 
									
										
										
										
											2019-04-03 07:16:41 +07:00
										 |  |  |     if (likely(error_code == 0)) { | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |         trace_mmu_helper_mmu_fault(address, full.phys_addr, mmu_idx, env->tl, | 
					
						
							| 
									
										
										
										
											2011-09-11 14:51:24 +00:00
										 |  |  |                                    env->dmmu.mmu_primary_context, | 
					
						
							|  |  |  |                                    env->dmmu.mmu_secondary_context); | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |         tlb_set_page_full(cs, mmu_idx, address, &full); | 
					
						
							| 
									
										
										
										
											2019-04-03 07:16:41 +07:00
										 |  |  |         return true; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-03 07:16:41 +07:00
										 |  |  |     if (probe) { | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     cpu_loop_exit_restore(cs, retaddr); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 21:17:58 +02:00
										 |  |  | void dump_mmu(CPUSPARCState *env) | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     unsigned int i; | 
					
						
							|  |  |  |     const char *mask; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 21:17:58 +02:00
										 |  |  |     qemu_printf("MMU contexts: Primary: %" PRId64 ", Secondary: %" | 
					
						
							|  |  |  |                 PRId64 "\n", | 
					
						
							|  |  |  |                 env->dmmu.mmu_primary_context, | 
					
						
							|  |  |  |                 env->dmmu.mmu_secondary_context); | 
					
						
							|  |  |  |     qemu_printf("DMMU Tag Access: %" PRIx64 ", TSB Tag Target: %" PRIx64 | 
					
						
							|  |  |  |                 "\n", env->dmmu.tag_access, env->dmmu.tsb_tag_target); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     if ((env->lsu & DMMU_E) == 0) { | 
					
						
							| 
									
										
										
										
											2019-04-17 21:17:58 +02:00
										 |  |  |         qemu_printf("DMMU disabled\n"); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2019-04-17 21:17:58 +02:00
										 |  |  |         qemu_printf("DMMU dump\n"); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |         for (i = 0; i < 64; i++) { | 
					
						
							|  |  |  |             switch (TTE_PGSIZE(env->dtlb[i].tte)) { | 
					
						
							|  |  |  |             default: | 
					
						
							|  |  |  |             case 0x0: | 
					
						
							|  |  |  |                 mask = "  8k"; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 0x1: | 
					
						
							|  |  |  |                 mask = " 64k"; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 0x2: | 
					
						
							|  |  |  |                 mask = "512k"; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 0x3: | 
					
						
							|  |  |  |                 mask = "  4M"; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (TTE_IS_VALID(env->dtlb[i].tte)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 21:17:58 +02:00
										 |  |  |                 qemu_printf("[%02u] VA: %" PRIx64 ", PA: %llx" | 
					
						
							| 
									
										
										
										
											2019-08-24 04:36:58 +10:00
										 |  |  |                             ", %s, %s, %s, %s, ie %s, ctx %" PRId64 " %s\n", | 
					
						
							| 
									
										
										
										
											2019-04-17 21:17:58 +02:00
										 |  |  |                             i, | 
					
						
							|  |  |  |                             env->dtlb[i].tag & (uint64_t)~0x1fffULL, | 
					
						
							|  |  |  |                             TTE_PA(env->dtlb[i].tte), | 
					
						
							|  |  |  |                             mask, | 
					
						
							|  |  |  |                             TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user", | 
					
						
							|  |  |  |                             TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO", | 
					
						
							|  |  |  |                             TTE_IS_LOCKED(env->dtlb[i].tte) ? | 
					
						
							|  |  |  |                             "locked" : "unlocked", | 
					
						
							| 
									
										
										
										
											2019-08-24 04:36:58 +10:00
										 |  |  |                             TTE_IS_IE(env->dtlb[i].tte) ? | 
					
						
							|  |  |  |                             "yes" : "no", | 
					
						
							| 
									
										
										
										
											2019-04-17 21:17:58 +02:00
										 |  |  |                             env->dtlb[i].tag & (uint64_t)0x1fffULL, | 
					
						
							|  |  |  |                             TTE_IS_GLOBAL(env->dtlb[i].tte) ? | 
					
						
							|  |  |  |                             "global" : "local"); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if ((env->lsu & IMMU_E) == 0) { | 
					
						
							| 
									
										
										
										
											2019-04-17 21:17:58 +02:00
										 |  |  |         qemu_printf("IMMU disabled\n"); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2019-04-17 21:17:58 +02:00
										 |  |  |         qemu_printf("IMMU dump\n"); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |         for (i = 0; i < 64; i++) { | 
					
						
							|  |  |  |             switch (TTE_PGSIZE(env->itlb[i].tte)) { | 
					
						
							|  |  |  |             default: | 
					
						
							|  |  |  |             case 0x0: | 
					
						
							|  |  |  |                 mask = "  8k"; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 0x1: | 
					
						
							|  |  |  |                 mask = " 64k"; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 0x2: | 
					
						
							|  |  |  |                 mask = "512k"; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 0x3: | 
					
						
							|  |  |  |                 mask = "  4M"; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (TTE_IS_VALID(env->itlb[i].tte)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 21:17:58 +02:00
										 |  |  |                 qemu_printf("[%02u] VA: %" PRIx64 ", PA: %llx" | 
					
						
							|  |  |  |                             ", %s, %s, %s, ctx %" PRId64 " %s\n", | 
					
						
							|  |  |  |                             i, | 
					
						
							|  |  |  |                             env->itlb[i].tag & (uint64_t)~0x1fffULL, | 
					
						
							|  |  |  |                             TTE_PA(env->itlb[i].tte), | 
					
						
							|  |  |  |                             mask, | 
					
						
							|  |  |  |                             TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user", | 
					
						
							|  |  |  |                             TTE_IS_LOCKED(env->itlb[i].tte) ? | 
					
						
							|  |  |  |                             "locked" : "unlocked", | 
					
						
							|  |  |  |                             env->itlb[i].tag & (uint64_t)0x1fffULL, | 
					
						
							|  |  |  |                             TTE_IS_GLOBAL(env->itlb[i].tte) ? | 
					
						
							|  |  |  |                             "global" : "local"); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif /* TARGET_SPARC64 */
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | static int cpu_sparc_get_phys_page(CPUSPARCState *env, hwaddr *phys, | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |                                    target_ulong addr, int rw, int mmu_idx) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |     CPUTLBEntryFull full = {}; | 
					
						
							|  |  |  |     int access_index, ret; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-22 14:31:40 -10:00
										 |  |  |     ret = get_physical_address(env, &full, &access_index, addr, rw, mmu_idx); | 
					
						
							|  |  |  |     if (ret == 0) { | 
					
						
							|  |  |  |         *phys = full.phys_addr; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return ret; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if defined(TARGET_SPARC64)
 | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | hwaddr cpu_get_phys_page_nofault(CPUSPARCState *env, target_ulong addr, | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  |                                            int mmu_idx) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |     hwaddr phys_addr; | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 4, mmu_idx) != 0) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return phys_addr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-29 18:55:54 +02:00
										 |  |  | hwaddr sparc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-06-29 18:55:54 +02:00
										 |  |  |     SPARCCPU *cpu = SPARC_CPU(cs); | 
					
						
							|  |  |  |     CPUSPARCState *env = &cpu->env; | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |     hwaddr phys_addr; | 
					
						
							| 
									
										
										
										
											2015-08-17 17:34:10 +10:00
										 |  |  |     int mmu_idx = cpu_mmu_index(env, false); | 
					
						
							| 
									
										
										
										
											2011-09-11 11:30:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) { | 
					
						
							|  |  |  |         if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) { | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return phys_addr; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-07-23 13:55:05 -10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-20 17:26:02 +04:00
										 |  |  | G_NORETURN void sparc_cpu_do_unaligned_access(CPUState *cs, vaddr addr, | 
					
						
							|  |  |  |                                               MMUAccessType access_type, | 
					
						
							|  |  |  |                                               int mmu_idx, | 
					
						
							|  |  |  |                                               uintptr_t retaddr) | 
					
						
							| 
									
										
										
										
											2021-07-23 13:55:05 -10:00
										 |  |  | { | 
					
						
							|  |  |  |     SPARCCPU *cpu = SPARC_CPU(cs); | 
					
						
							|  |  |  |     CPUSPARCState *env = &cpu->env; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef TARGET_SPARC64
 | 
					
						
							|  |  |  |     env->dmmu.sfsr = build_sfsr(env, mmu_idx, access_type); | 
					
						
							|  |  |  |     env->dmmu.sfar = addr; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |     env->mmuregs[4] = addr; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cpu_raise_exception_ra(env, TT_UNALIGNED, retaddr); | 
					
						
							|  |  |  | } |