1 /* $NetBSD: mmu_tt.c,v 1.1 2026/04/24 11:24:32 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2025 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: mmu_tt.c,v 1.1 2026/04/24 11:24:32 thorpej Exp $"); 34 35 #include "opt_m68k_arch.h" 36 37 #include <sys/param.h> 38 #include <sys/cpu.h> 39 40 #include <uvm/uvm_extern.h> 41 42 #include <m68k/mmu.h> 43 #if defined(M68030) 44 #include <m68k/mmu_30.h> 45 #endif 46 #if defined(M68040) || defined(M68060) 47 #include <m68k/mmu_40.h> 48 #endif 49 50 #ifdef M68030 51 /* 52 * mmu_tt_chkpg30 -- 53 * Check that a given page is TT's on a 68030. 54 */ 55 static bool 56 mmu_tt_chkpg30(uint32_t ttreg, paddr_t pa, vm_prot_t prot, int *out_flags) 57 { 58 uint32_t lab = __SHIFTOUT(ttreg, TT30_LAB); 59 uint32_t lam = __SHIFTOUT(ttreg, TT30_LAM); 60 uint32_t pa_lab = __SHIFTOUT(pa, TT30_LAB); 61 uint32_t fcb = __SHIFTOUT(ttreg, TT30_FCBASE); 62 uint32_t fcm = __SHIFTOUT(ttreg, TT30_FCMASK); 63 64 if ((ttreg & TT30_E) == 0) { 65 /* This reg not enabled - not translated. */ 66 return false; 67 } 68 69 /* LAM and FCM are "ignore" bits. */ 70 lam = ~lam; 71 fcm = ~fcm; 72 73 if ((lab & lam) != (pa_lab & lam)) { 74 /* Addresses don't match. */ 75 return false; 76 } 77 78 /* Check function. */ 79 if ((prot & UVM_PROT_EXEC) != 0 && 80 (fcb & fcm) != (FC_SUPERP & fcm)) { 81 return false; 82 } 83 if ((prot & (UVM_PROT_READ|UVM_PROT_WRITE)) != 0 && 84 (fcb & fcm) != (FC_SUPERD & fcm)) { 85 return false; 86 } 87 88 if ((ttreg & TT30_RWM) == 0) { 89 if (ttreg & TT30_RW) { 90 if (prot & UVM_PROT_WRITE) { 91 return false; 92 } 93 } else { 94 if (prot & UVM_PROT_READ) { 95 return false; 96 } 97 } 98 } 99 100 if (ttreg & TT30_CI) { 101 *out_flags = PMAP_NOCACHE; 102 } else { 103 *out_flags = 0; 104 } 105 106 return true; 107 } 108 109 static bool 110 mmu_range_checkonett30(uint32_t ttreg, paddr_t firstpg, paddr_t lastpg, 111 vm_prot_t prot, int *out_flags) 112 { 113 paddr_t pg; 114 115 for (pg = firstpg; pg <= lastpg; pg++) { 116 if (! mmu_tt_chkpg30(ttreg, m68k_ptob(pg), prot, out_flags)) { 117 return false; 118 } 119 } 120 return true; 121 } 122 123 static bool 124 mmu_range_is_tt30(paddr_t firstpg, paddr_t lastpg, vm_prot_t prot, 125 int *out_flags) 126 { 127 return mmu_range_checkonett30(mmu_tt30[MMU_TTREG_TT0], firstpg, lastpg, 128 prot, out_flags) || 129 mmu_range_checkonett30(mmu_tt30[MMU_TTREG_TT1], firstpg, lastpg, 130 prot, out_flags); 131 } 132 #endif /* M68030 */ 133 134 #if defined(M68040) || defined(M68060) 135 static bool 136 mmu_tt_checkpg40(uint32_t ttreg, paddr_t pa, vm_prot_t prot, int *out_flags) 137 { 138 uint32_t lab = __SHIFTOUT(ttreg, TTR40_LAB); 139 uint32_t lam = __SHIFTOUT(ttreg, TTR40_LAM); 140 uint32_t pa_lab = __SHIFTOUT(pa, TTR40_LAB); 141 142 if ((ttreg & TTR40_E) == 0) { 143 /* This reg not enabled - not translated. */ 144 return false; 145 } 146 147 /* LAM are "ignore" bits. */ 148 lam = ~lam; 149 150 if ((lab & lam) != (pa_lab & lam)) { 151 /* Addresses don't match. */ 152 return false; 153 } 154 155 switch (ttreg & TTR40_SFIELD) { 156 case TTR40_USER: 157 /* Doesn't match Supervisor */ 158 return false; 159 default: 160 /* All other combinations do. */ 161 break; 162 } 163 164 if ((prot & UVM_PROT_WRITE) != 0 && (ttreg & TTR40_W) != 0) { 165 return false; 166 } 167 168 switch (ttreg & TTR40_CM) { 169 case PTE40_CM_NC_SER: 170 case PTE40_CM_NC: 171 *out_flags = PMAP_NOCACHE; 172 break; 173 default: 174 *out_flags = 0; 175 break; 176 } 177 178 return true; 179 } 180 181 static bool 182 mmu_range_checkonett40(uint32_t ttreg, paddr_t firstpg, paddr_t lastpg, 183 vm_prot_t prot, int *out_flags) 184 { 185 paddr_t pg; 186 187 for (pg = firstpg; pg <= lastpg; pg++) { 188 if (! mmu_tt_checkpg40(ttreg, m68k_ptob(pg), prot, out_flags)) { 189 return false; 190 } 191 } 192 return true; 193 } 194 195 static bool 196 mmu_range_is_tt40(paddr_t firstpg, paddr_t lastpg, vm_prot_t prot, 197 int *out_flags) 198 { 199 int rflag; 200 201 if ((prot & UVM_PROT_EXEC) && 202 !mmu_range_checkonett40(mmu_tt40[MMU_TTREG_ITT0], 203 firstpg, lastpg, UVM_PROT_EXEC, &rflag) && 204 !mmu_range_checkonett40(mmu_tt40[MMU_TTREG_ITT1], 205 firstpg, lastpg, UVM_PROT_EXEC, &rflag)) { 206 return false; 207 } 208 209 if ((prot & (UVM_PROT_READ|UVM_PROT_WRITE)) && 210 !mmu_range_checkonett40(mmu_tt40[MMU_TTREG_DTT0], 211 firstpg, lastpg, prot, &rflag) && 212 !mmu_range_checkonett40(mmu_tt40[MMU_TTREG_DTT1], 213 firstpg, lastpg, prot, &rflag)) { 214 return false; 215 } 216 217 *out_flags = rflag; 218 219 /* We know at least one space is selected. */ 220 return true; 221 } 222 #endif /* M68040 || M68060 */ 223 224 /* 225 * mmu_range_is_tt -- 226 * Check to see that a physical address range is transparently 227 * translated for the specified usage (data, prog). 228 */ 229 bool 230 mmu_range_is_tt(paddr_t pa, psize_t len, vm_prot_t prot, int *out_flags) 231 { 232 paddr_t lastpg = m68k_btop(pa + (len - 1)); 233 paddr_t firstpg = m68k_btop(pa); 234 235 if ((prot & (UVM_PROT_READ|UVM_PROT_WRITE|UVM_PROT_EXEC)) == 0) { 236 return false; 237 } 238 239 switch (mmutype) { 240 #ifdef M68030 241 case MMU_68030: 242 return mmu_range_is_tt30(firstpg, lastpg, prot, out_flags); 243 #endif 244 #if defined(M68040) || defined(M68060) 245 case MMU_68040: 246 case MMU_68060: 247 return mmu_range_is_tt40(firstpg, lastpg, prot, out_flags); 248 #endif 249 default: 250 return false; 251 } 252 } 253