Home | History | Annotate | Line # | Download | only in m68k
      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