|
|
1.1 root 1: /* $Id: sun3-mmu.c,v 1.3 2005/04/30 15:09:44 fredette Exp $ */
2:
3: /* machine/sun3/sun3-mmu.c - implementation of Sun 3 MMU emulation: */
4:
5: /*
6: * Copyright (c) 2003, 2004 Matt Fredette
7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This product includes software developed by Matt Fredette.
20: * 4. The name of the author may not be used to endorse or promote products
21: * derived from this software without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33: * POSSIBILITY OF SUCH DAMAGE.
34: */
35:
36: #include <tme/common.h>
37: _TME_RCSID("$Id: sun3-mmu.c,v 1.3 2005/04/30 15:09:44 fredette Exp $");
38:
39: /* includes: */
40: #include "sun3-impl.h"
41:
42: /* macros: */
43:
44: /* real PTE entry bits: */
45: #define TME_SUN3_PTE_VALID (0x80000000)
46: #define TME_SUN3_PTE_WRITE (0x40000000)
47: #define TME_SUN3_PTE_SYSTEM (0x20000000)
48: #define TME_SUN3_PTE_NC (0x10000000)
49: #define TME_SUN3_PTE_PGTYPE (0x0C000000)
50: #define TME_SUN3_PTE_REF (0x02000000)
51: #define TME_SUN3_PTE_MOD (0x01000000)
52: #define TME_SUN3_PTE_PGFRAME (0x0007FFFF)
53:
54: /* real PTE page types: */
55: #define TME_SUN3_PGTYPE_OBMEM (0)
56: #define TME_SUN3_PGTYPE_OBIO (1)
57: #define TME_SUN3_PGTYPE_VME_D16 (2)
58: #define TME_SUN3_PGTYPE_VME_D32 (3)
59:
60: /* real bus error register bits: */
61: #define TME_SUN3_BUSERR_WATCHDOG TME_BIT(0) /* watchdog or user reset */
62: /* bit 1 unused */
63: #define TME_SUN3_BUSERR_FPAENERR TME_BIT(2) /* FPA enable error */
64: #define TME_SUN3_BUSERR_FPABERR TME_BIT(3) /* FPA bus error */
65: #define TME_SUN3_BUSERR_VMEBUSERR TME_BIT(4) /* VME bus error */
66: #define TME_SUN3_BUSERR_TIMEOUT TME_BIT(5) /* timeout error */
67: #define TME_SUN3_BUSERR_PROTERR TME_BIT(6) /* MMU protection error */
68: #define TME_SUN3_BUSERR_INVALID TME_BIT(7) /* MMU page invalid error */
69:
70: /* this logs a bus error: */
71: #ifndef TME_NO_LOG
72: static void
73: _tme_sun3_bus_fault_log(struct tme_sun3 *sun3, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle)
74: {
75: tme_bus_addr_t virtual_address;
76: struct tme_sun_mmu_pte pte;
77: tme_uint32_t pte_sun3;
78: const char *bus_name;
79: tme_bus_addr_t physical_address;
80: int rc;
81:
82: /* this silences gcc -Wuninitialized: */
83: bus_name = NULL;
84:
85: /* recover the virtual address used: */
86: virtual_address = cycle->tme_bus_cycle_address - tlb->tme_bus_tlb_addr_offset;
87:
88: /* look up the PTE involved: */
89: rc = tme_sun_mmu_pte_get(sun3->tme_sun3_mmu,
90: sun3->tme_sun3_context,
91: virtual_address,
92: &pte);
93: assert(rc == TME_OK);
94: pte_sun3 = pte.tme_sun_mmu_pte_raw;
95:
96: /* form the physical address and get the bus name: */
97: physical_address = (((pte_sun3 & TME_SUN3_PTE_PGFRAME) << TME_SUN3_PAGE_SIZE_LOG2)
98: | (virtual_address & (TME_SUN3_PAGE_SIZE - 1)));
99: switch (TME_FIELD_MASK_EXTRACTU(pte_sun3, TME_SUN3_PTE_PGTYPE)) {
100: case TME_SUN3_PGTYPE_OBMEM: bus_name = "obmem"; break;
101: case TME_SUN3_PGTYPE_OBIO: bus_name = "obio"; break;
102: case TME_SUN3_PGTYPE_VME_D16:
103: bus_name = "VME_D16";
104: break;
105: case TME_SUN3_PGTYPE_VME_D32:
106: bus_name = "VME_D32";
107: break;
108: }
109:
110: /* log this bus error: */
111: tme_log(TME_SUN3_LOG_HANDLE(sun3), 1000, TME_OK,
112: (TME_SUN3_LOG_HANDLE(sun3),
113: _("%s bus error, physical 0x%08x, virtual 0x%08x, buserr = 0x%02x"),
114: bus_name,
115: physical_address,
116: virtual_address,
117: sun3->tme_sun3_buserr));
118: }
119: #else /* TME_NO_LOG */
120: #define _tme_sun3_bus_fault_log(a, b, c) do { } while (/* CONSTCOND */ 0)
121: #endif /* TME_NO_LOG */
122:
123: /* our general bus fault handler: */
124: static int
125: _tme_sun3_bus_fault_handler(struct tme_sun3 *sun3,
126: struct tme_bus_tlb *tlb,
127: struct tme_bus_cycle *cycle,
128: int rc)
129: {
130: tme_uint8_t buserr;
131:
132: /* dispatch on our fault code: */
133: switch (rc) {
134:
135: /* bus address nonexistent: */
136: case ENOENT:
137: buserr = TME_SUN3_BUSERR_TIMEOUT;
138: break;
139:
140: /* anything else is just a fault: */
141: default:
142: buserr = 0;
143: break;
144: }
145:
146: /* set the bus error register: */
147: sun3->tme_sun3_buserr = buserr;
148:
149: /* log the fault: */
150: _tme_sun3_bus_fault_log(sun3, tlb, cycle);
151:
152: return (rc);
153: }
154:
155: /* our obio bus fault handler: */
156: static int
157: _tme_sun3_obio_fault_handler(void *_sun3, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc)
158: {
159:
160: /* call the common bus fault handler: */
161: return (_tme_sun3_bus_fault_handler((struct tme_sun3 *) _sun3, tlb, cycle, rc));
162: }
163:
164: /* our obmem bus fault handler: */
165: static int
166: _tme_sun3_obmem_fault_handler(void *_sun3, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc)
167: {
168:
169: /* call the common bus fault handler: */
170: return (_tme_sun3_bus_fault_handler((struct tme_sun3 *) _sun3, tlb, cycle, rc));
171: }
172:
173: /* our VMEbus fault handler: */
174: static int
175: _tme_sun3_vmebus_fault_handler(void *_sun3, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc)
176: {
177: struct tme_sun3 *sun3;
178:
179: /* recover our sun3: */
180: sun3 = (struct tme_sun3 *) _sun3;
181:
182: /* call the common bus fault handler: */
183: rc = _tme_sun3_bus_fault_handler((struct tme_sun3 *) _sun3, tlb, cycle, rc);
184:
185: /* this bus fault happened on the VMEbus: */
186: sun3->tme_sun3_buserr |= TME_SUN3_BUSERR_VMEBUSERR;
187:
188: /* return the fault: */
189: return (rc);
190: }
191:
192: /* our dummy cycle handler: */
193: static int
194: _tme_sun3_cycle_dummy(void *_sun3, struct tme_bus_cycle *cycle)
195: {
196: return (TME_OK);
197: }
198:
199: /* our page-invalid cycle handler: */
200: static int
201: _tme_sun3_mmu_invalid(void *_sun3, struct tme_bus_cycle *cycle)
202: {
203: struct tme_sun3 *sun3;
204:
205: /* recover our sun3: */
206: sun3 = (struct tme_sun3 *) _sun3;
207:
208: /* log this bus error: */
209: tme_log(TME_SUN3_LOG_HANDLE(sun3), 1000, TME_OK,
210: (TME_SUN3_LOG_HANDLE(sun3),
211: _("page invalid bus error")));
212:
213: /* set the bus error register: */
214: sun3->tme_sun3_buserr = TME_SUN3_BUSERR_INVALID;
215:
216: /* return the fault: */
217: return (EFAULT);
218: }
219:
220: /* our protection error cycle handler: */
221: static int
222: _tme_sun3_mmu_proterr(void *_sun3, struct tme_bus_cycle *cycle)
223: {
224: struct tme_sun3 *sun3;
225:
226: /* recover our sun3: */
227: sun3 = (struct tme_sun3 *) _sun3;
228:
229: /* log this bus error: */
230: tme_log(TME_SUN3_LOG_HANDLE(sun3), 1000, TME_OK,
231: (TME_SUN3_LOG_HANDLE(sun3),
232: _("page protection bus error")));
233:
234: /* set the bus error register: */
235: sun3->tme_sun3_buserr = TME_SUN3_BUSERR_PROTERR;
236:
237: /* return the fault: */
238: return (EFAULT);
239: }
240:
241: /* our SDVMA disabled cycle handler: */
242: static int
243: _tme_sun3_sdvma_disabled(void *_sun3, struct tme_bus_cycle *cycle)
244: {
245: return (ENOENT);
246: }
247:
248: /* our internal TLB filler: */
249: static int
250: _tme_sun3_tlb_fill(struct tme_sun3 *sun3, struct tme_bus_tlb *tlb, tme_uint8_t context,
251: unsigned int *_function_code_or_codes, tme_uint32_t address, unsigned int cycles)
252: {
253: unsigned int function_code;
254: unsigned int function_code_sp;
255: unsigned short access;
256: struct tme_bus_tlb tlb_bus;
257: unsigned int tlb_i;
258: unsigned short tlb_flags;
259:
260: /* recover the function code: */
261: function_code = *_function_code_or_codes;
262:
263: /* this must be a user or supervisor program or data function code: */
264: assert(function_code == TME_M68K_FC_UD
265: || function_code == TME_M68K_FC_UP
266: || function_code == TME_M68K_FC_SD
267: || function_code == TME_M68K_FC_SP);
268:
269: /* assume that if this TLB entry ends up good for the supervisor,
270: it's good for the supervisor program function code: */
271: function_code_sp = TME_BIT(TME_M68K_FC_SP);
272:
273: /* if we're in the boot state: */
274: if (__tme_predict_false((sun3->tme_sun3_enable & TME_SUN3_ENA_NOTBOOT) == 0)) {
275:
276: /* if this is the supervisor program function code: */
277: if (function_code == TME_M68K_FC_SP) {
278:
279: /* fill this TLB entry directly from the obmem bus: */
280: (*sun3->tme_sun3_obmem->tme_bus_tlb_fill)
281: (sun3->tme_sun3_obmem,
282: tlb,
283: TME_SUN3_PROM_BASE | (address & (TME_SUN3_PROM_SIZE - 1)),
284: cycles);
285:
286: /* create the mapping TLB entry: */
287: TME_ATOMIC_WRITE(tme_bus_addr_t,
288: tlb_bus.tme_bus_tlb_addr_first,
289: address & (((tme_bus_addr_t) 0) - TME_SUN3_PROM_SIZE));
290: TME_ATOMIC_WRITE(tme_bus_addr_t,
291: tlb_bus.tme_bus_tlb_addr_last,
292: address | (TME_SUN3_PROM_SIZE - 1));
293: tlb_bus.tme_bus_tlb_cycles_ok
294: = TME_BUS_CYCLE_READ;
295:
296: /* map the filled TLB entry: */
297: tme_bus_tlb_map(tlb, TME_SUN3_PROM_BASE | (address & (TME_SUN3_PROM_SIZE - 1)), &tlb_bus, address);
298:
299: /* this is good for the supervisor program function code only: */
300: *_function_code_or_codes = TME_BIT(TME_M68K_FC_SP);
301:
302: /* done: */
303: return(TME_OK);
304: }
305:
306: /* update the head pointer for the active boot state TLB entry
307: list: */
308: tlb_i = sun3->tme_sun3_boot_state_tlb_next
309: = ((sun3->tme_sun3_boot_state_tlb_next
310: + 1)
311: & (TME_SUN3_BOOT_STATE_TLBS - 1));
312:
313: /* if the new head pointer already has a TLB entry, and it doesn't
314: happen to be the same as this TLB entry, invalidate it: */
315: if (sun3->tme_sun3_boot_state_tlbs[tlb_i] != NULL
316: && (sun3->tme_sun3_boot_state_tlbs[tlb_i]
317: != TME_ATOMIC_READ(struct tme_bus_tlb *,
318: tlb->tme_bus_tlb_backing_reservation))) {
319: tme_bus_tlb_invalidate(sun3->tme_sun3_boot_state_tlbs[tlb_i]);
320: }
321:
322: /* add this TLB entry to the active list: */
323: sun3->tme_sun3_boot_state_tlbs[tlb_i] =
324: TME_ATOMIC_READ(struct tme_bus_tlb *,
325: tlb->tme_bus_tlb_backing_reservation);
326:
327: /* if this TLB entry ends up good for the supervisor, it's not
328: good for the supervisor program function code: */
329: function_code_sp = 0;
330: }
331:
332: /* fill this TLB entry from the MMU: */
333: access
334: = ((cycles & TME_BUS_CYCLE_WRITE)
335: ? TME_SUN_MMU_PTE_PROT_RW
336: : TME_SUN_MMU_PTE_PROT_RO);
337: access
338: = ((function_code == TME_M68K_FC_UD
339: || function_code == TME_M68K_FC_UP)
340: ? TME_SUN_MMU_PTE_PROT_USER(access)
341: : TME_SUN_MMU_PTE_PROT_SYSTEM(access));
342: tlb_flags = tme_sun_mmu_tlb_fill(sun3->tme_sun3_mmu,
343: tlb,
344: context,
345: address,
346: access);
347:
348: /* this TLB entry is good for the program and data function codes
349: for the user and/or the supervisor: */
350: *_function_code_or_codes
351: = (((tlb_flags & TME_SUN_MMU_TLB_USER)
352: ? (TME_BIT(TME_M68K_FC_UD)
353: | TME_BIT(TME_M68K_FC_UP))
354: : 0)
355: | ((tlb_flags & TME_SUN_MMU_TLB_SYSTEM)
356: ? (TME_BIT(TME_M68K_FC_SD)
357: | function_code_sp)
358: : 0));
359:
360: /* if the memory error register is being tested: */
361: if (__tme_predict_false(sun3->tme_sun3_memerr_csr & TME_SUN3_MEMERR_PAR_TEST)) {
362:
363: /* this must be a supervisor data access: */
364: if (function_code != TME_M68K_FC_SD) {
365: abort();
366: }
367:
368: /* if this TLB's bus cycle handler isn't for the memory error
369: register itself: */
370: if (tlb->tme_bus_tlb_cycle != _tme_sun3_memerr_cycle_handler) {
371:
372: /* there must be no other TLB entry already involved in the test: */
373: if (sun3->tme_sun3_memerr_tlb != NULL) {
374: abort();
375: }
376:
377: /* remember this TLB entry pointer, and its original bus cycle
378: handler: */
379: sun3->tme_sun3_memerr_tlb = TME_ATOMIC_READ(struct tme_bus_tlb *,
380: tlb->tme_bus_tlb_backing_reservation);
381: assert (sun3->tme_sun3_memerr_tlb != NULL);
382: sun3->tme_sun3_memerr_cycle_private = tlb->tme_bus_tlb_cycle_private;
383: sun3->tme_sun3_memerr_cycle = tlb->tme_bus_tlb_cycle;
384:
385: /* this TLB entry does not allow fast reading and writing, and
386: it now uses the memory error test cycle handler: */
387: tlb->tme_bus_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF;
388: tlb->tme_bus_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF;
389: tlb->tme_bus_tlb_rwlock = NULL;
390: tlb->tme_bus_tlb_cycle_private = sun3;
391: tlb->tme_bus_tlb_cycle = _tme_sun3_memerr_test_cycle_handler;
392:
393: /* reset other memory error test values: */
394: sun3->tme_sun3_memerr_pending_csr = 0;
395: }
396: }
397:
398: return (TME_OK);
399: }
400:
401: /* our m68k TLB filler: */
402: int
403: _tme_sun3_m68k_tlb_fill(struct tme_m68k_bus_connection *conn_m68k, struct tme_m68k_tlb *tlb_m68k,
404: unsigned int function_code, tme_uint32_t address, unsigned int cycles)
405: {
406: struct tme_sun3 *sun3;
407: struct tme_bus_tlb *tlb;
408: struct tme_bus_tlb tlb_bus;
409:
410: /* recover our sun3: */
411: sun3 = (struct tme_sun3 *) conn_m68k->tme_m68k_bus_connection.tme_bus_connection.tme_connection_element->tme_element_private;
412:
413: /* get the generic bus TLB: */
414: tlb = &tlb_m68k->tme_m68k_tlb_bus_tlb;
415:
416: /* if this is function code three: */
417: if (function_code == TME_M68K_FC_3) {
418:
419: /* if this address is within the UART bypass: */
420: if (address >= TME_SUN3_CONTROL_UART_BYPASS
421: && address < TME_SUN3_CONTROL_UART_BYPASS + TME_SUN_Z8530_SIZE) {
422:
423: /* fill this TLB entry directly from the obio bus: */
424: (*sun3->tme_sun3_obio->tme_bus_tlb_fill)
425: (sun3->tme_sun3_obio,
426: tlb,
427: (address - TME_SUN3_CONTROL_UART_BYPASS) + TME_SUN3_OBIO_ZS0,
428: cycles);
429:
430: /* create the mapping TLB entry: */
431: TME_ATOMIC_WRITE(tme_bus_addr_t,
432: tlb_bus.tme_bus_tlb_addr_first,
433: TME_SUN3_CONTROL_UART_BYPASS);
434: TME_ATOMIC_WRITE(tme_bus_addr_t,
435: tlb_bus.tme_bus_tlb_addr_last,
436: TME_SUN3_CONTROL_UART_BYPASS + TME_SUN_Z8530_SIZE - 1);
437: tlb_bus.tme_bus_tlb_cycles_ok
438: = (TME_BUS_CYCLE_READ
439: | TME_BUS_CYCLE_WRITE);
440:
441: /* map the filled TLB entry: */
442: tme_bus_tlb_map(tlb, (address - TME_SUN3_CONTROL_UART_BYPASS) + TME_SUN3_OBIO_ZS0, &tlb_bus, address);
443: }
444:
445: /* otherwise, this is something else in control space: */
446: else {
447:
448: /* initialize the TLB entry: */
449: tme_bus_tlb_initialize(tlb);
450:
451: /* we cover the entire address space up to the UART bypass: */
452: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, 0);
453: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, TME_SUN3_CONTROL_UART_BYPASS - 1);
454:
455: /* we allow reading and writing: */
456: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
457:
458: /* our bus cycle handler: */
459: tlb->tme_bus_tlb_cycle_private = sun3;
460: tlb->tme_bus_tlb_cycle = _tme_sun3_control_cycle_handler;
461: }
462:
463: /* this is good for function code three only: */
464: tlb_m68k->tme_m68k_tlb_function_codes_mask = TME_BIT(TME_M68K_FC_3);
465:
466: /* done: */
467: return (TME_OK);
468: }
469:
470: /* this is a normal function code: */
471: tlb_m68k->tme_m68k_tlb_function_codes_mask = function_code;
472: return (_tme_sun3_tlb_fill(sun3, tlb, sun3->tme_sun3_context,
473: &tlb_m68k->tme_m68k_tlb_function_codes_mask,
474: address, cycles));
475: }
476:
477: /* our bus TLB filler: */
478: int
479: _tme_sun3_bus_tlb_fill(struct tme_bus_connection *conn_bus, struct tme_bus_tlb *tlb,
480: tme_uint32_t address, unsigned int cycles)
481: {
482: struct tme_sun3 *sun3;
483: struct tme_sun3_bus_connection *conn_sun3;
484: tme_uint32_t base, size;
485: struct tme_bus_tlb tlb_bus;
486: tme_uint8_t context;
487: unsigned int function_code_or_codes;
488: unsigned int tlb_i;
489:
490: /* recover our sun3: */
491: sun3 = (struct tme_sun3 *) conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
492:
493: /* recover the sun3 internal mainbus connection: */
494: conn_sun3 = (struct tme_sun3_bus_connection *) conn_bus;
495:
496: /* dispatch on the internal connection. the bus address into a DVMA
497: address, context, and function code, except for the memory error
498: register and interrupt register connections, which are handled
499: specially: */
500: switch (conn_sun3->tme_sun3_bus_connection_which) {
501:
502: case TME_SUN3_CONN_OBIO_MASTER:
503: base = 0x0f000000;
504: size = TME_SUN3_DVMA_SIZE_OBIO;
505: context = sun3->tme_sun3_context;
506: function_code_or_codes = TME_M68K_FC_SD;
507: break;
508:
509: case TME_SUN3_CONN_BUS_VME:
510: base = 0x0ff00000;
511: size = TME_SUN3_DVMA_SIZE_VME;
512: context = sun3->tme_sun3_context;
513: function_code_or_codes = TME_M68K_FC_SD;
514: break;
515:
516: case TME_SUN3_CONN_REG_MEMERR:
517: case TME_SUN3_CONN_REG_INTREG:
518:
519: /* initialize the TLB entry: */
520: tme_bus_tlb_initialize(tlb);
521:
522: /* the address range: */
523: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, 0);
524: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last,
525: ((conn_sun3->tme_sun3_bus_connection_which == TME_SUN3_CONN_REG_MEMERR
526: ? TME_SUN3_MEMERR_SIZ_REG
527: : sizeof(sun3->tme_sun3_ints))
528: - 1));
529:
530: /* we allow reading and writing: */
531: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
532:
533: /* our bus cycle handler: */
534: tlb->tme_bus_tlb_cycle_private = sun3;
535: tlb->tme_bus_tlb_cycle
536: = (conn_sun3->tme_sun3_bus_connection_which == TME_SUN3_CONN_REG_MEMERR
537: ? _tme_sun3_memerr_cycle_handler
538: : _tme_sun3_intreg_cycle_handler);
539:
540: /* done: */
541: return (TME_OK);
542:
543: default: abort();
544: }
545:
546: /* update the head pointer for the active SDVMA TLB entry list: */
547: tlb_i = sun3->tme_sun3_sdvma_tlb_next
548: = ((sun3->tme_sun3_sdvma_tlb_next
549: + 1)
550: & (TME_SUN3_SDVMA_TLBS - 1));
551:
552: /* if the new head pointer already has a TLB entry, and it doesn't
553: happen to be the same as this TLB entry, invalidate it: */
554: if (sun3->tme_sun3_sdvma_tlbs[tlb_i] != NULL
555: && (sun3->tme_sun3_sdvma_tlbs[tlb_i]
556: != TME_ATOMIC_READ(struct tme_bus_tlb *,
557: tlb->tme_bus_tlb_backing_reservation))) {
558: tme_bus_tlb_invalidate(sun3->tme_sun3_sdvma_tlbs[tlb_i]);
559: }
560:
561: /* add this TLB entry to the active list: */
562: sun3->tme_sun3_sdvma_tlbs[tlb_i] =
563: TME_ATOMIC_READ(struct tme_bus_tlb *,
564: tlb->tme_bus_tlb_backing_reservation);
565:
566: /* if system DVMA is disabled: */
567: if (__tme_predict_false(!(sun3->tme_sun3_enable & TME_SUN3_ENA_SDVMA))) {
568:
569: /* return a TLB entry that will generate a VME bus fault: */
570: tme_bus_tlb_initialize(tlb);
571: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, 0);
572: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, size - 1);
573: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
574: tlb->tme_bus_tlb_cycle_private = sun3;
575: tlb->tme_bus_tlb_cycle = _tme_sun3_sdvma_disabled;
576: TME_BUS_TLB_FAULT_HANDLER(tlb, _tme_sun3_vmebus_fault_handler, sun3);
577: return (TME_OK);
578: }
579:
580: assert (!(address & base)
581: && (address < size));
582:
583: /* fill this TLB entry from the MMU: */
584: _tme_sun3_tlb_fill(sun3, tlb, context,
585: &function_code_or_codes,
586: address | base, cycles);
587:
588: /* create the mapping TLB entry. we do this even if base == 0,
589: because the TLB entry as currently filled may cover more address
590: space than DVMA space on this machine is supposed to cover: */
591: TME_ATOMIC_WRITE(tme_bus_addr_t,
592: tlb_bus.tme_bus_tlb_addr_first,
593: 0);
594: TME_ATOMIC_WRITE(tme_bus_addr_t,
595: tlb_bus.tme_bus_tlb_addr_last,
596: size - 1);
597: tlb_bus.tme_bus_tlb_cycles_ok
598: = (TME_BUS_CYCLE_READ
599: | TME_BUS_CYCLE_WRITE);
600:
601: /* map the filled TLB entry: */
602: tme_bus_tlb_map(tlb, address | base, &tlb_bus, address);
603:
604: /* XXX FIXME - what happens to a bus cycle to an unmapped DVMA
605: address? is the answer different for obio masters and the VME
606: bus? for now, these bus cycles get ignored in both cases: */
607: if (tlb->tme_bus_tlb_cycle == _tme_sun3_mmu_invalid) {
608: tlb->tme_bus_tlb_cycle = _tme_sun3_cycle_dummy;
609: }
610:
611: return (TME_OK);
612: }
613:
614: /* our post-MMU TLB filler: */
615: static int
616: _tme_sun3_tlb_fill_mmu(void *_sun3, struct tme_bus_tlb *tlb,
617: struct tme_sun_mmu_pte *pte,
618: tme_uint32_t *_address,
619: unsigned int cycles)
620: {
621: struct tme_sun3 *sun3;
622: tme_uint32_t address;
623: unsigned int bus_type;
624: struct tme_bus_connection *conn_bus;
625: tme_bus_fault_handler bus_fault_handler;
626: int rc;
627:
628: /* recover our sun3: */
629: sun3 = (struct tme_sun3 *) _sun3;
630:
631: /* get the physical page frame and bus type: */
632: address = ((pte->tme_sun_mmu_pte_raw & TME_SUN3_PTE_PGFRAME) << TME_SUN3_PAGE_SIZE_LOG2);
633: bus_type = TME_FIELD_MASK_EXTRACTU(pte->tme_sun_mmu_pte_raw, TME_SUN3_PTE_PGTYPE);
634:
635: /* any mapping of any address in a PROM-sized region starting at
636: 0x100000 in obio space means the PROM. the virtual page frame is
637: actually used to form the physical address: */
638: if ((address & -TME_SUN3_PROM_SIZE) == TME_SUN3_OBIO_PROM
639: && bus_type == TME_SUN3_PGTYPE_OBIO) {
640: address = TME_SUN3_PROM_BASE | (*_address & ((TME_SUN3_PROM_SIZE - 1) & ~(TME_SUN3_PAGE_SIZE - 1)));
641: bus_type = TME_SUN3_PGTYPE_OBMEM;
642: }
643:
644: #if 1 /* NetBSD/sun3 cgtwo bug */
645: /* XXX FIXME - this hack works around a bug in NetBSD/sun3, present
646: since revision 1.49 of src/sys/arch/sun3/conf/GENERIC (when the
647: sun3x port was merged into the sun3 port). in this revision, the
648: declaration for cgtwo0 changed:
649:
650: -cgtwo0 at vmes0 addr 0xff400000 level 4 vect 0xA8
651: +cgtwo0 at vme2 addr 0x400000 ipl 4 vect 0xA8
652:
653: because the cg2mmap() function in src/sys/arch/sun3/dev/cg2.c
654: doesn't add the 0xff000000 mask to the configured physical
655: address (needed because the cgtwo is an A24 device), when Xsun
656: mmap()s the cgtwo it gets a mapping of physical address 0x400000
657: in VME space instead of the correct 0xff400000. the sparc cgtwo
658: driver gets this right.
659:
660: so for now we force all accesses to VME D16 address 0x400000 to
661: 0xff400000. once the NetBSD bug has been fixed this code should
662: be removed: */
663: if (bus_type == TME_SUN3_PGTYPE_VME_D16
664: && ((address & 0xff400000) == 0x400000)) {
665: address |= 0xff000000;
666: }
667: #endif /* NetBSD/sun3 cgtwo bug */
668:
669: /* add in the page offset to finish the address: */
670: address |= *_address & (TME_SUN3_PAGE_SIZE - 1);
671: *_address = address;
672:
673: /* if this is obio: */
674: if (bus_type == TME_SUN3_PGTYPE_OBIO) {
675: conn_bus = sun3->tme_sun3_obio;
676: bus_fault_handler = _tme_sun3_obio_fault_handler;
677: }
678:
679: /* if this is obmem: */
680: else if (bus_type == TME_SUN3_PGTYPE_OBMEM) {
681: conn_bus = sun3->tme_sun3_obmem;
682: bus_fault_handler = _tme_sun3_obmem_fault_handler;
683: }
684:
685: /* if this is the VME bus: */
686: else {
687: assert(bus_type == TME_SUN3_PGTYPE_VME_D16
688: || bus_type == TME_SUN3_PGTYPE_VME_D32);
689: conn_bus = sun3->tme_sun3_vmebus;
690: bus_fault_handler = _tme_sun3_vmebus_fault_handler;
691: }
692:
693: /* call the bus TLB filler: */
694: rc = ((*conn_bus->tme_bus_tlb_fill)
695: (conn_bus, tlb, address, cycles));
696:
697: /* if the bus TLB filler succeeded, add our bus fault handler: */
698: if (rc == TME_OK) {
699: TME_BUS_TLB_FAULT_HANDLER(tlb, bus_fault_handler, sun3);
700: }
701:
702: return (rc);
703: }
704:
705: /* this gets a PTE from the MMU: */
706: int
707: _tme_sun3_mmu_pte_get(struct tme_sun3 *sun3, tme_uint32_t address, tme_uint32_t *_pte_sun3)
708: {
709: struct tme_sun_mmu_pte pte;
710: tme_uint32_t pte_sun3;
711: unsigned int pte_flags;
712: int rc;
713:
714: /* get the PTE from the MMU: */
715: rc = tme_sun_mmu_pte_get(sun3->tme_sun3_mmu,
716: sun3->tme_sun3_context,
717: address,
718: &pte);
719: assert(rc == TME_OK);
720:
721: /* form the Sun-3 PTE: */
722: pte_sun3 = pte.tme_sun_mmu_pte_raw;
723: pte_flags = pte.tme_sun_mmu_pte_flags;
724: if (pte_flags & TME_SUN_MMU_PTE_REF) {
725: pte_sun3 |= TME_SUN3_PTE_REF;
726: }
727: if (pte_flags & TME_SUN_MMU_PTE_MOD) {
728: pte_sun3 |= TME_SUN3_PTE_MOD;
729: }
730:
731: /* done: */
732: *_pte_sun3 = pte_sun3;
733: tme_log(TME_SUN3_LOG_HANDLE(sun3), 1000, TME_OK,
734: (TME_SUN3_LOG_HANDLE(sun3),
735: _("pte_get: PGMAP[%d:0x%08x] -> 0x%08x"),
736: sun3->tme_sun3_context,
737: address,
738: pte_sun3));
739: return (TME_OK);
740: }
741:
742: /* this sets a PTE into the MMU: */
743: int
744: _tme_sun3_mmu_pte_set(struct tme_sun3 *sun3, tme_uint32_t address, tme_uint32_t pte_sun3)
745: {
746: struct tme_sun_mmu_pte pte;
747: unsigned int pte_flags;
748: #ifndef TME_NO_LOG
749: const char *bus_name;
750: tme_bus_addr_t physical_address;
751:
752: /* this silences gcc -Wuninitialized: */
753: bus_name = NULL;
754:
755: /* log this setting: */
756: physical_address = ((pte_sun3 & TME_SUN3_PTE_PGFRAME) << TME_SUN3_PAGE_SIZE_LOG2);
757: switch (TME_FIELD_MASK_EXTRACTU(pte_sun3, TME_SUN3_PTE_PGTYPE)) {
758: case TME_SUN3_PGTYPE_OBMEM: bus_name = "obmem"; break;
759: case TME_SUN3_PGTYPE_OBIO: bus_name = "obio"; break;
760: case TME_SUN3_PGTYPE_VME_D16: bus_name = "VME_D16"; break;
761: case TME_SUN3_PGTYPE_VME_D32: bus_name = "VME_D32"; break;
762: }
763: tme_log(TME_SUN3_LOG_HANDLE(sun3), 1000, TME_OK,
764: (TME_SUN3_LOG_HANDLE(sun3),
765: _("pte_set: PGMAP[%d:0x%08x] <- 0x%08x (%s 0x%08x)"),
766: sun3->tme_sun3_context,
767: address,
768: pte_sun3,
769: bus_name,
770: physical_address));
771: #endif /* !TME_NO_LOG */
772:
773: pte.tme_sun_mmu_pte_raw = pte_sun3;
774:
775: pte_flags = (pte_sun3 & TME_SUN3_PTE_WRITE
776: ? TME_SUN_MMU_PTE_PROT_RW
777: : TME_SUN_MMU_PTE_PROT_RO);
778: pte_flags = (TME_SUN_MMU_PTE_PROT_SYSTEM(pte_flags)
779: | TME_SUN_MMU_PTE_PROT_USER(pte_sun3 & TME_SUN3_PTE_SYSTEM
780: ? TME_SUN_MMU_PTE_PROT_ERROR
781: : pte_flags));
782: if (pte_sun3 & TME_SUN3_PTE_MOD) {
783: pte_flags |= TME_SUN_MMU_PTE_MOD;
784: }
785: if (pte_sun3 & TME_SUN3_PTE_REF) {
786: pte_flags |= TME_SUN_MMU_PTE_REF;
787: }
788: if (pte_sun3 & TME_SUN3_PTE_VALID) {
789: pte_flags |= TME_SUN_MMU_PTE_VALID;
790: }
791: pte.tme_sun_mmu_pte_flags = pte_flags;
792:
793: return (tme_sun_mmu_pte_set(sun3->tme_sun3_mmu,
794: sun3->tme_sun3_context,
795: address,
796: &pte));
797: }
798:
799: /* this is called when the SDVMA bit is changed in the enable register: */
800: void
801: _tme_sun3_mmu_sdvma_change(struct tme_sun3 *sun3)
802: {
803: unsigned int tlb_i;
804:
805: /* whenever the SDVMA bit changes, we have to invalidate all SDVMA
806: TLB entries: */
807: for (tlb_i = 0; tlb_i < TME_SUN3_SDVMA_TLBS; tlb_i++) {
808: if (sun3->tme_sun3_sdvma_tlbs[tlb_i] != NULL) {
809: tme_bus_tlb_invalidate(sun3->tme_sun3_sdvma_tlbs[tlb_i]);
810: sun3->tme_sun3_sdvma_tlbs[tlb_i] = NULL;
811: }
812: }
813: }
814:
815: /* this is called when the context register is set: */
816: void
817: _tme_sun3_mmu_context_set(struct tme_sun3 *sun3)
818: {
819: unsigned int tlb_i;
820:
821: /* every TLB set has nine contexts' worth of TLB entries. context
822: zero is used for the "boot state", and the remaining contexts
823: correspond to the eight possible MMU contexts.
824:
825: context zero is used for the boot state because at TLB set
826: allocation time, TLB sets are initialized pointing to the context
827: zero TLBs (by tme_sun_mmu_tlb_set_allocate), and TLBs must be
828: initialized to the boot state TLBs.
829:
830: in the boot state, TLB fills for supervisor program references
831: bypass the MMU and are filled to reference the PROM, and data
832: fills are filled as normal using the current context. since context
833: register changes can happen while in the boot state, but we only
834: have one boot state context in the TLB sets, we have to track
835: the data TLBs we fill in the boot state.
836:
837: we don't bother to track the supervisor program TLB fills, since
838: they never change. */
839:
840: /* in the not-boot (i.e., normal, state): */
841: if (__tme_predict_true(sun3->tme_sun3_enable & TME_SUN3_ENA_NOTBOOT)) {
842:
843: tme_log(TME_SUN3_LOG_HANDLE(sun3), 1000, TME_OK,
844: (TME_SUN3_LOG_HANDLE(sun3),
845: _("context now #%d"),
846: sun3->tme_sun3_context));
847:
848: /* update all TLB sets to reflect the context change: */
849: tme_sun_mmu_tlbs_context_set(sun3->tme_sun3_mmu, sun3->tme_sun3_context + 1);
850: }
851:
852: /* in the boot state: */
853: else {
854:
855: tme_log(TME_SUN3_LOG_HANDLE(sun3), 1000, TME_OK,
856: (TME_SUN3_LOG_HANDLE(sun3),
857: _("context now #%d (boot state)"),
858: sun3->tme_sun3_context));
859:
860: /* update all TLB sets to reflect the pseudo-context change: */
861: tme_sun_mmu_tlbs_context_set(sun3->tme_sun3_mmu, 0);
862:
863: /* invalidate all of the boot-state data TLBs: */
864: for (tlb_i = 0; tlb_i < TME_SUN3_BOOT_STATE_TLBS; tlb_i++) {
865: if (sun3->tme_sun3_boot_state_tlbs[tlb_i] != NULL) {
866: tme_bus_tlb_invalidate(sun3->tme_sun3_boot_state_tlbs[tlb_i]);
867: sun3->tme_sun3_boot_state_tlbs[tlb_i] = NULL;
868: }
869: }
870: }
871: }
872:
873: /* this allocates a new TLB set: */
874: int
875: _tme_sun3_mmu_tlb_set_allocate(struct tme_bus_connection *conn_bus_asker,
876: unsigned int count, unsigned int sizeof_one,
877: TME_ATOMIC_POINTER_TYPE(struct tme_bus_tlb *) _tlbs)
878: {
879: struct tme_sun3 *sun3;
880: int rc;
881:
882: /* recover our sun3: */
883: sun3 = (struct tme_sun3 *) conn_bus_asker->tme_bus_connection.tme_connection_element->tme_element_private;
884:
885: /* get the MMU to allocate the TLB set: */
886: rc = tme_sun_mmu_tlb_set_allocate(sun3->tme_sun3_mmu, count, sizeof_one, _tlbs);
887:
888: return (rc);
889: }
890:
891: /* this creates a Sun-3 MMU: */
892: void
893: _tme_sun3_mmu_new(struct tme_sun3 *sun3)
894: {
895: struct tme_sun_mmu_info mmu_info;
896:
897: mmu_info.tme_sun_mmu_info_element = sun3->tme_sun3_element;
898: mmu_info.tme_sun_mmu_info_address_bits = 28;
899: mmu_info.tme_sun_mmu_info_pgoffset_bits = TME_SUN3_PAGE_SIZE_LOG2;
900: mmu_info.tme_sun_mmu_info_pteindex_bits = 4;
901: mmu_info.tme_sun_mmu_info_contexts = 1 + 8; /* internal context zero is for the boot state */
902: mmu_info.tme_sun_mmu_info_pmegs = TME_SUN3_PMEGS;
903: mmu_info.tme_sun_mmu_info_seginv = 255;
904: mmu_info.tme_sun_mmu_info_tlb_fill_private = sun3;
905: mmu_info.tme_sun_mmu_info_tlb_fill = _tme_sun3_tlb_fill_mmu;
906: mmu_info.tme_sun_mmu_info_proterr_private = sun3;
907: mmu_info.tme_sun_mmu_info_proterr = _tme_sun3_mmu_proterr;
908: mmu_info.tme_sun_mmu_info_invalid_private = sun3;
909: mmu_info.tme_sun_mmu_info_invalid = _tme_sun3_mmu_invalid;
910: sun3->tme_sun3_mmu = tme_sun_mmu_new(&mmu_info);
911: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.