1/* $OpenBSD: m88100_machdep.c,v 1.12 2014/05/31 11:19:06 miod Exp $ */ 2/* 3 * Mach Operating System 4 * Copyright (c) 1993-1991 Carnegie Mellon University 5 * Copyright (c) 1991 OMRON Corporation 6 * All Rights Reserved. 7 * 8 * Permission to use, copy, modify and distribute this software and its 9 * documentation is hereby granted, provided that both the copyright 10 * notice and this permission notice appear in all copies of the 11 * software, derivative works or modified versions, and any portions 12 * thereof, and that both notices appear in supporting documentation. 13 * 14 * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" 15 * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND 16 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 17 * 18 * Carnegie Mellon requests users of this software to return to 19 * 20 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 21 * School of Computer Science 22 * Carnegie Mellon University 23 * Pittsburgh PA 15213-3890 24 * 25 * any improvements or extensions that they make and grant Carnegie the 26 * rights to redistribute these changes. 27 */ 28 29#include <sys/param.h> 30#include <sys/systm.h> 31 32#include <machine/asm_macro.h> 33#include <m88k/m88100.h> 34 35#ifdef MULTIPROCESSOR 36uint32_t m88100_mp_atomic_begin(__cpu_simple_lock_t *, uint *); 37void m88100_mp_atomic_end(uint32_t, __cpu_simple_lock_t *, uint); 38#endif 39 40/* 41 * Data Access Emulation for M88100 exceptions 42 */ 43 44#define DMT_BYTE 1 45#define DMT_HALF 2 46#define DMT_WORD 4 47 48const struct { 49 unsigned char offset; 50 unsigned char size; 51} dmt_en_info[16] = { 52 {0, 0}, 53 {3, DMT_BYTE}, 54 {2, DMT_BYTE}, 55 {2, DMT_HALF}, 56 {1, DMT_BYTE}, 57 {0, 0}, 58 {0, 0}, 59 {0, 0}, 60 {0, DMT_BYTE}, 61 {0, 0}, 62 {0, 0}, 63 {0, 0}, 64 {0, DMT_HALF}, 65 {0, 0}, 66 {0, 0}, 67 {0, DMT_WORD} 68}; 69 70#ifdef DATA_DEBUG 71int data_access_emulation_debug = 0; 72#define DAE_DEBUG(stuff) \ 73 do { \ 74 if (data_access_emulation_debug != 0) { \ 75 stuff; \ 76 } \ 77 } while (0) 78#else 79#define DAE_DEBUG(stuff) 80#endif 81 82void dae_print_one(u_int, u_int, u_int, u_int); 83void dae_process(struct trapframe *, u_int, u_int, u_int, u_int); 84 85void 86dae_print(u_int *f) 87{ 88 struct trapframe *eframe = (void *)f; 89 90 if (!ISSET(eframe->tf_dmt0, DMT_VALID)) 91 return; 92 93 dae_print_one(0, eframe->tf_dma0, eframe->tf_dmd0, eframe->tf_dmt0); 94 dae_print_one(1, eframe->tf_dma1, eframe->tf_dmd1, eframe->tf_dmt1); 95 dae_print_one(2, eframe->tf_dma2, eframe->tf_dmd2, eframe->tf_dmt2); 96} 97 98void 99dae_print_one(u_int x, u_int dmax, u_int dmdx, u_int dmtx) 100{ 101 u_int enbits; 102 const char *width, *usr, *xmem; 103 104 if (!ISSET(dmtx, DMT_VALID)) 105 return; 106 107 enbits = DMT_ENBITS(dmtx); 108 dmax += dmt_en_info[enbits].offset; 109 110 if (dmtx & DMT_DOUB1) 111 width = ".d"; 112 else { 113 switch (dmt_en_info[enbits].size) { 114 case DMT_BYTE: 115 if (dmtx & DMT_SIGNED) 116 width = ".b"; 117 else 118 width = ".bu"; 119 break; 120 case DMT_HALF: 121 if (dmtx & DMT_SIGNED) 122 width = ".h"; 123 else 124 width = ".hu"; 125 break; 126 case DMT_WORD: 127 width = ""; 128 break; 129 default: 130 width = ".???"; 131 break; 132 } 133 } 134 if (dmtx & DMT_DAS) 135 usr = ""; 136 else 137 usr = ".usr"; 138 if (dmtx & DMT_LOCKBAR) 139 xmem = "(xmem)"; 140 else 141 xmem = ""; 142 143 if (ISSET(dmtx, DMT_WRITE)) 144 printf("[DMT%d=%x: %sst%s%s %08x to %08x]\n", 145 x, dmtx, xmem, width, usr, dmdx, dmax); 146 else 147 printf("[DMT%d=%x: %sld%s%s r%d <- %x]\n", 148 x, dmtx, xmem, width, usr, DMT_DREGBITS(dmtx), dmax); 149} 150 151void 152data_access_emulation(u_int *f) 153{ 154 struct trapframe *eframe = (void *)f; 155 156 if (!ISSET(eframe->tf_dmt0, DMT_VALID)) 157 return; 158 159 dae_process(eframe, 0, 160 eframe->tf_dma0, eframe->tf_dmd0, eframe->tf_dmt0); 161 dae_process(eframe, 1, 162 eframe->tf_dma1, eframe->tf_dmd1, eframe->tf_dmt1); 163 dae_process(eframe, 2, 164 eframe->tf_dma2, eframe->tf_dmd2, eframe->tf_dmt2); 165 166 eframe->tf_dmt0 = 0; 167} 168 169void 170dae_process(struct trapframe *eframe, u_int x, 171 u_int dmax, u_int dmdx, u_int dmtx) 172{ 173 u_int v, reg, enbits; 174 175 if (!ISSET(dmtx, DMT_VALID)) 176 return; 177 178 DAE_DEBUG(dae_print_one(x, dmax, dmdx, dmtx)); 179 180 enbits = DMT_ENBITS(dmtx); 181 dmax += dmt_en_info[enbits].offset; 182 reg = DMT_DREGBITS(dmtx); 183 184 if (!ISSET(dmtx, DMT_LOCKBAR)) { 185 /* the fault is not during an XMEM */ 186 187 if (x == 2 && ISSET(dmtx, DMT_DOUB1)) { 188 /* pipeline 2 (earliest stage) for a double */ 189 190 if (ISSET(dmtx, DMT_WRITE)) { 191 /* 192 * STORE DOUBLE WILL BE REINITIATED BY rte 193 */ 194 } else { 195 /* EMULATE ld.d INSTRUCTION */ 196 v = do_load_word(dmax, dmtx & DMT_DAS); 197 if (reg != 0) 198 eframe->tf_r[reg] = v; 199 v = do_load_word(dmax ^ 4, dmtx & DMT_DAS); 200 if (reg != 31) 201 eframe->tf_r[reg + 1] = v; 202 } 203 } else { 204 /* not pipeline #2 with a double */ 205 if (dmtx & DMT_WRITE) { 206 switch (dmt_en_info[enbits].size) { 207 case DMT_BYTE: 208 DAE_DEBUG( 209 printf("[byte %x -> %08x(%c)]\n", 210 dmdx & 0xff, dmax, 211 ISSET(dmtx, DMT_DAS) ? 's' : 'u') 212 ); 213 do_store_byte(dmax, dmdx, 214 dmtx & DMT_DAS); 215 break; 216 case DMT_HALF: 217 DAE_DEBUG( 218 printf("[half %x -> %08x(%c)]\n", 219 dmdx & 0xffff, dmax, 220 ISSET(dmtx, DMT_DAS) ? 's' : 'u') 221 ); 222 do_store_half(dmax, dmdx, 223 dmtx & DMT_DAS); 224 break; 225 case DMT_WORD: 226 DAE_DEBUG( 227 printf("[word %x -> %08x(%c)]\n", 228 dmdx, dmax, 229 ISSET(dmtx, DMT_DAS) ? 's' : 'u') 230 ); 231 do_store_word(dmax, dmdx, 232 dmtx & DMT_DAS); 233 break; 234 } 235 } else { 236 /* else it's a read */ 237 switch (dmt_en_info[enbits].size) { 238 case DMT_BYTE: 239 v = do_load_byte(dmax, dmtx & DMT_DAS); 240 if (!ISSET(dmtx, DMT_SIGNED)) 241 v &= 0x000000ff; 242 break; 243 case DMT_HALF: 244 v = do_load_half(dmax, dmtx & DMT_DAS); 245 if (!ISSET(dmtx, DMT_SIGNED)) 246 v &= 0x0000ffff; 247 break; 248 case DMT_WORD: 249 v = do_load_word(dmax, dmtx & DMT_DAS); 250 break; 251 } 252 DAE_DEBUG( 253 if (reg == 0) 254 printf("[no write to r0 done]\n"); 255 else 256 printf("[r%d <- %08x]\n", reg, v); 257 ); 258 if (reg != 0) 259 eframe->tf_r[reg] = v; 260 } 261 } 262 } else { 263 /* if lockbar is set... it's part of an XMEM */ 264 /* 265 * According to Motorola's "General Information", 266 * the DMT_DOUB1 bit is never set in this case, as it 267 * should be. 268 * If lockbar is set (as it is if we're here) and if 269 * the write is not set, then it's the same as if DOUB1 270 * was set... 271 */ 272 if (!ISSET(dmtx, DMT_WRITE)) { 273 if (x < 2) { 274 /* RERUN xmem WITH DMD(x+1) */ 275 dmdx = 276 x == 0 ? eframe->tf_dmd1 : eframe->tf_dmd2; 277 } else { 278 /* RERUN xmem WITH DMD2 */ 279 } 280 281 if (dmt_en_info[enbits].size == DMT_WORD) { 282 v = do_xmem_word(dmax, dmdx, dmtx & DMT_DAS); 283 } else { 284 v = do_xmem_byte(dmax, dmdx, dmtx & DMT_DAS); 285 } 286 DAE_DEBUG( 287 if (reg == 0) 288 printf("[no write to r0 done]\n"); 289 else 290 printf("[r%d <- %08x]\n", reg, v); 291 ); 292 if (reg != 0) 293 eframe->tf_r[reg] = v; 294 } else { 295 if (x == 0) { 296 if (reg != 0) 297 eframe->tf_r[reg] = dmdx; 298 m88100_rewind_insn(&(eframe->tf_regs)); 299 /* xmem RERUN ON rte */ 300 eframe->tf_dmt0 = 0; 301 return; 302 } 303 } 304 } 305} 306 307/* 308 * Routines to patch the kernel code on 88100 systems not affected by 309 * the xxx.usr bug. 310 */ 311 312void 313m88100_apply_patches() 314{ 315#ifdef ERRATA__XXX_USR 316 if (((get_cpu_pid() & PID_VN) >> VN_SHIFT) > 10) { 317 /* 318 * Patch DAE helpers. 319 * before after 320 * branch branch 321 * NOP jmp.n r1 322 * xxx.usr xxx.usr 323 * NOP; NOP; NOP 324 * jmp r1 325 */ 326 ((u_int32_t *)(do_load_word))[1] = 0xf400c401; 327 ((u_int32_t *)(do_load_half))[1] = 0xf400c401; 328 ((u_int32_t *)(do_load_byte))[1] = 0xf400c401; 329 ((u_int32_t *)(do_store_word))[1] = 0xf400c401; 330 ((u_int32_t *)(do_store_half))[1] = 0xf400c401; 331 ((u_int32_t *)(do_store_byte))[1] = 0xf400c401; 332 } 333#endif 334} 335 336#ifdef MULTIPROCESSOR 337void 338m88100_smp_setup(struct cpu_info *ci) 339{ 340 /* 341 * Setup function pointers for mplock operation. 342 */ 343 344 ci->ci_mp_atomic_begin = m88100_mp_atomic_begin; 345 ci->ci_mp_atomic_end = m88100_mp_atomic_end; 346} 347 348uint32_t 349m88100_mp_atomic_begin(__cpu_simple_lock_t *lock, uint *csr) 350{ 351 uint32_t psr; 352 353 psr = get_psr(); 354 set_psr(psr | PSR_IND); 355 __cpu_simple_lock(lock); 356 357 return psr; 358} 359 360void 361m88100_mp_atomic_end(uint32_t psr, __cpu_simple_lock_t *lock, uint csr) 362{ 363 __cpu_simple_unlock(lock); 364 set_psr(psr); 365} 366#endif 367