|
|
1.1.1.5 root 1: /* $Id: sun2-mmu.c,v 1.14 2009/08/30 14:39:47 fredette Exp $ */
1.1 root 2:
3: /* machine/sun2/sun2-mmu.c - implementation of Sun 2 MMU emulation: */
4:
5: /*
6: * Copyright (c) 2003 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>
1.1.1.5 root 37: _TME_RCSID("$Id: sun2-mmu.c,v 1.14 2009/08/30 14:39:47 fredette Exp $");
1.1 root 38:
39: /* includes: */
40: #include "sun2-impl.h"
41:
42: /* macros: */
43:
44: /* real PTE entry bits: */
45: #define TME_SUN2_PTE_VALID 0x80000000
46: #define TME_SUN2_PTE_PROT 0x7C000000
47: #define TME_SUN2_PTE_FOD 0x02000000
48: #define TME_SUN2_PTE_PGTYPE 0x00C00000
49: #define TME_SUN2_PTE_PGTYPE_MASK 0x00000003
50: #define TME_SUN2_PTE_REF 0x00200000
51: #define TME_SUN2_PTE_MOD 0x00100000
52: #define TME_SUN2_PTE_PGFRAME 0x00000FFF
53:
54: /* real PTE page types: */
55: #define TME_SUN2_PGTYPE_OBMEM (0)
56: #define TME_SUN2_PGTYPE_OBIO (1)
57: #define TME_SUN2_PGTYPE_MBMEM (2)
58: #define TME_SUN2_PGTYPE_VME0 (2)
59: #define TME_SUN2_PGTYPE_MBIO (3)
60: #define TME_SUN2_PGTYPE_VME8 (3)
61:
62: /* real bus error register bits: */
63: #define TME_SUN2_BUSERR_PARERR_L TME_BIT(0) /* parity error, lower byte */
64: #define TME_SUN2_BUSERR_PARERR_U TME_BIT(1) /* parity error, upper byte */
65: #define TME_SUN2_BUSERR_TIMEOUT TME_BIT(2) /* bus access timed out */
66: #define TME_SUN2_BUSERR_PROTERR TME_BIT(3) /* protection error */
67: #define TME_SUN2_BUSERR_VMEBUSERR TME_BIT(6) /* bus error signaled on VMEbus */
68: #define TME_SUN2_BUSERR_VALID TME_BIT(7) /* page map was valid */
69:
1.1.1.5 root 70: /* real context count: */
71: #define TME_SUN2_CONTEXT_COUNT (8)
72:
1.1.1.6 ! root 73: int bradshow;
! 74: int jamdelay;
! 75:
1.1 root 76: /* this logs a bus error: */
77: #ifndef TME_NO_LOG
78: static void
79: _tme_sun2_bus_fault_log(struct tme_sun2 *sun2, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle)
80: {
1.1.1.5 root 81: tme_bus_addr32_t virtual_address;
1.1 root 82: struct tme_sun_mmu_pte pte;
83: tme_uint32_t pte_sun2;
84: const char *bus_name;
1.1.1.5 root 85: tme_bus_addr32_t physical_address;
1.1 root 86: int rc;
87:
1.1.1.2 root 88: /* this silences gcc -Wuninitialized: */
89: bus_name = NULL;
90:
1.1 root 91: /* recover the virtual address used: */
92: virtual_address = cycle->tme_bus_cycle_address - tlb->tme_bus_tlb_addr_offset;
93:
94: /* look up the PTE involved. since this is a real bus error, and
95: not a protection violation or page not present bus error, we
96: assume the system context: */
97: rc = tme_sun_mmu_pte_get(sun2->tme_sun2_mmu,
98: sun2->tme_sun2_context_system,
99: virtual_address,
100: &pte);
101: assert(rc == TME_OK);
102: pte_sun2 = pte.tme_sun_mmu_pte_raw;
103:
104: /* form the physical address and get the bus name: */
105: physical_address = (((pte_sun2 & TME_SUN2_PTE_PGFRAME) << TME_SUN2_PAGE_SIZE_LOG2)
106: | (virtual_address & (TME_SUN2_PAGE_SIZE - 1)));
107: switch ((pte_sun2 & TME_SUN2_PTE_PGTYPE) / (TME_SUN2_PTE_PGTYPE / TME_SUN2_PTE_PGTYPE_MASK)) {
108: case TME_SUN2_PGTYPE_OBMEM: bus_name = "obmem"; break;
109: case TME_SUN2_PGTYPE_OBIO: bus_name = "obio"; break;
110: case TME_SUN2_PGTYPE_MBMEM:
111: if (sun2->tme_sun2_has_vme) {
112: bus_name = "VME";
113: }
114: else {
115: bus_name = "mbmem";
116: }
117: break;
118: case TME_SUN2_PGTYPE_MBIO:
119: if (sun2->tme_sun2_has_vme) {
120: bus_name = "VME";
121: physical_address |= 0x800000;
122: }
123: else {
124: bus_name = "mbio";
125: }
126: break;
127: }
128:
129: /* log this bus error: */
130: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK,
131: (TME_SUN2_LOG_HANDLE(sun2),
132: _("%s bus error, physical 0x%08x, virtual 0x%08x, buserr = 0x%02x"),
133: bus_name,
134: physical_address,
135: virtual_address,
136: sun2->tme_sun2_buserr));
137: }
138: #else /* TME_NO_LOG */
139: #define _tme_sun2_bus_fault_log(a, b, c) do { } while (/* CONSTCOND */ 0)
140: #endif /* TME_NO_LOG */
141:
142: /* our general bus fault handler: */
143: static int
144: _tme_sun2_bus_fault_handler(struct tme_sun2 *sun2,
145: struct tme_bus_tlb *tlb,
146: struct tme_bus_cycle *cycle,
147: int rc)
148: {
149: tme_uint16_t buserr;
150:
151: /* dispatch on our fault code: */
152: switch (rc) {
153:
154: /* bus address nonexistent: */
155: case ENOENT:
156: buserr = TME_SUN2_BUSERR_VALID | TME_SUN2_BUSERR_TIMEOUT;
157: break;
158:
159: /* anything else is just a fault: */
160: default:
161: buserr = TME_SUN2_BUSERR_VALID;
162: break;
163: }
164:
165: /* set the bus error register: */
166: sun2->tme_sun2_buserr = buserr;
167:
168: /* log the fault: */
169: _tme_sun2_bus_fault_log(sun2, tlb, cycle);
170:
171: return (rc);
172: }
173:
174: /* our obio bus fault handler: */
175: static int
176: _tme_sun2_obio_fault_handler(void *_sun2, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc)
177: {
178: tme_uint8_t all_bits_one[sizeof(tme_uint16_t)];
179:
1.1.1.6 ! root 180: #if 0
! 181: {
! 182: extern int printf(const char *format, ...);
! 183: printf("_tme_sun2_obio_fault_handler() %08x\n", (int)cycle->tme_bus_cycle_address);
! 184: }
! 185: #endif
1.1 root 186: /* the sun2 obio bus doesn't generate bus errors, it just reads
187: all-bits-one: */
188: memset(all_bits_one, 0xff, sizeof(all_bits_one));
189: tme_bus_cycle_xfer_memory(cycle,
190: &all_bits_one[0] - cycle->tme_bus_cycle_address,
191: cycle->tme_bus_cycle_address + sizeof(all_bits_one));
192: return (TME_OK);
193: }
194:
195: /* our obmem bus fault handler: */
196: static int
197: _tme_sun2_obmem_fault_handler(void *_sun2, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc)
198: {
199: tme_uint8_t all_bits_one[sizeof(tme_uint16_t)];
200:
201: /* the sun2 obmem bus apparently doesn't generate bus errors below
202: 0x700000, and instead just reads all-bits-one: */
1.1.1.6 ! root 203: #if 0
! 204: {
! 205: extern int printf(const char *format, ...);
! 206: printf("_tme_sun2_obmem_fault_handler() %08x\n", (int)cycle->tme_bus_cycle_address);
! 207: }
! 208: #endif
1.1 root 209: if (cycle->tme_bus_cycle_address < 0x700000) {
210: memset(all_bits_one, 0xff, sizeof(all_bits_one));
211: tme_bus_cycle_xfer_memory(cycle,
212: &all_bits_one[0] - cycle->tme_bus_cycle_address,
213: cycle->tme_bus_cycle_address + sizeof(all_bits_one));
214: return (TME_OK);
215: }
216:
217: /* call the common bus fault handler: */
218: return (_tme_sun2_bus_fault_handler((struct tme_sun2 *) _sun2, tlb, cycle, rc));
219: }
220:
221: /* our Multibus fault handler: */
222: static int
223: _tme_sun2_multibus_fault_handler(void *_sun2, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc)
224: {
225:
1.1.1.6 ! root 226: #if 1
! 227: {
! 228: extern int printf(const char *format, ...);
! 229: printf("_tme_sun2_multibus_fault_handler() %08x, rc %d\n", (int)cycle->tme_bus_cycle_address, rc);
! 230: }
! 231: if ((int)cycle->tme_bus_cycle_address == 0)
! 232: rc = ENOENT;
! 233: #endif
! 234:
1.1 root 235: /* call the common bus fault handler: */
236: return (_tme_sun2_bus_fault_handler((struct tme_sun2 *) _sun2, tlb, cycle, rc));
237: }
238:
239: /* our VMEbus fault handler: */
240: static int
241: _tme_sun2_vmebus_fault_handler(void *_sun2, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc)
242: {
243: struct tme_sun2 *sun2;
244:
245: /* recover our sun2: */
246: sun2 = (struct tme_sun2 *) _sun2;
247:
248: /* call the common bus fault handler: */
249: rc = _tme_sun2_bus_fault_handler((struct tme_sun2 *) _sun2, tlb, cycle, rc);
250:
251: /* this bus fault happened on the VMEbus: */
252: sun2->tme_sun2_buserr |= TME_SUN2_BUSERR_VMEBUSERR;
253:
254: /* return the fault: */
255: return (rc);
256: }
257:
258: /* our page-invalid cycle handler: */
259: static int
260: _tme_sun2_mmu_invalid(void *_sun2, struct tme_bus_cycle *cycle)
261: {
262: struct tme_sun2 *sun2;
263:
264: /* recover our sun2: */
265: sun2 = (struct tme_sun2 *) _sun2;
266:
267: /* log this bus error: */
268: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK,
269: (TME_SUN2_LOG_HANDLE(sun2),
270: _("page invalid bus error")));
271:
272: /* set the bus error register: */
273: sun2->tme_sun2_buserr = TME_SUN2_BUSERR_PROTERR;
274:
275: /* return the fault: */
276: return (EFAULT);
277: }
278:
279: /* our protection error cycle handler: */
280: static int
281: _tme_sun2_mmu_proterr(void *_sun2, struct tme_bus_cycle *cycle)
282: {
283: struct tme_sun2 *sun2;
284:
285: /* recover our sun2: */
286: sun2 = (struct tme_sun2 *) _sun2;
287:
288: /* log this bus error: */
289: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK,
290: (TME_SUN2_LOG_HANDLE(sun2),
291: _("page protection bus error")));
292:
293: /* set the bus error register: */
294: sun2->tme_sun2_buserr = TME_SUN2_BUSERR_VALID | TME_SUN2_BUSERR_PROTERR;
295:
296: /* return the fault: */
297: return (EFAULT);
298: }
299:
300: /* our m68k TLB filler: */
301: int
302: _tme_sun2_m68k_tlb_fill(struct tme_m68k_bus_connection *conn_m68k, struct tme_m68k_tlb *tlb_m68k,
303: unsigned int function_code, tme_uint32_t address, unsigned int cycles)
304: {
305: struct tme_sun2 *sun2;
306: struct tme_bus_tlb *tlb;
1.1.1.5 root 307: unsigned int function_codes_mask;
308: struct tme_bus_tlb tlb_mapping;
309: tme_uint32_t context;
310: tme_uint32_t access;
1.1 root 311: unsigned short tlb_flags;
312:
313: /* recover our sun2: */
314: sun2 = (struct tme_sun2 *) conn_m68k->tme_m68k_bus_connection.tme_bus_connection.tme_connection_element->tme_element_private;
315:
316: /* get the generic bus TLB: */
317: tlb = &tlb_m68k->tme_m68k_tlb_bus_tlb;
318:
319: /* if this is function code three, we handle this ourselves: */
320: if (function_code == TME_M68K_FC_3) {
321:
322: /* initialize the TLB entry: */
323: tme_bus_tlb_initialize(tlb);
324:
325: /* we cover the entire address space: */
1.1.1.4 root 326: tlb->tme_bus_tlb_addr_first = 0;
1.1.1.5 root 327: tlb->tme_bus_tlb_addr_last = 0 - (tme_bus_addr32_t) 1;
1.1 root 328:
329: /* we allow reading and writing: */
330: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
331:
332: /* our bus cycle handler: */
333: tlb->tme_bus_tlb_cycle_private = sun2;
334: tlb->tme_bus_tlb_cycle = _tme_sun2_control_cycle_handler;
335:
336: /* this is good for function code three only: */
337: tlb_m68k->tme_m68k_tlb_function_codes_mask = TME_BIT(TME_M68K_FC_3);
1.1.1.5 root 338:
339: /* done: */
340: return (TME_OK);
1.1 root 341: }
342:
1.1.1.5 root 343: /* this must be or a user or supervisor program or data function
344: code: */
345: assert(function_code == TME_M68K_FC_UD
346: || function_code == TME_M68K_FC_UP
347: || function_code == TME_M68K_FC_SD
348: || function_code == TME_M68K_FC_SP);
349:
350: /* assume that if this TLB entry ends up good for the supervisor,
351: it's good for the supervisor program function code: */
352: function_codes_mask = TME_BIT(TME_M68K_FC_SP);
353:
354: /* if we're in the boot state: */
355: if (__tme_predict_false((sun2->tme_sun2_enable & TME_SUN2_ENA_NOTBOOT) == 0)) {
356:
357: /* if this is the supervisor program function code: */
358: if (function_code == TME_M68K_FC_SP) {
359:
360: /* fill this TLB entry directly from the obmem bus: */
361: (*sun2->tme_sun2_obmem->tme_bus_tlb_fill)
362: (sun2->tme_sun2_obmem,
363: tlb,
364: TME_SUN2_PROM_BASE | (address & (TME_SUN2_PROM_SIZE - 1)),
365: cycles);
366:
367: /* create the mapping TLB entry: */
368: tlb_mapping.tme_bus_tlb_addr_first = address & (((tme_bus_addr32_t) 0) - TME_SUN2_PROM_SIZE);
369: tlb_mapping.tme_bus_tlb_addr_last = address | (TME_SUN2_PROM_SIZE - 1);
370: tlb_mapping.tme_bus_tlb_cycles_ok
371: = TME_BUS_CYCLE_READ;
372:
373: /* map the filled TLB entry: */
374: tme_bus_tlb_map(tlb, TME_SUN2_PROM_BASE | (address & (TME_SUN2_PROM_SIZE - 1)), &tlb_mapping, address);
375:
376: /* this is good for the supervisor program function code only: */
377: tlb_m68k->tme_m68k_tlb_function_codes_mask
378: = TME_BIT(TME_M68K_FC_SP);
379:
380: /* done: */
381: return(TME_OK);
382: }
383:
384: /* if this TLB entry ends up good for the supervisor, it's not
385: good for the supervisor program function code: */
386: function_codes_mask = 0;
1.1 root 387: }
388:
1.1.1.5 root 389: /* start the access: */
390: access
391: = ((cycles & TME_BUS_CYCLE_WRITE)
392: ? TME_SUN_MMU_PTE_PROT_RW
393: : TME_SUN_MMU_PTE_PROT_RO);
1.1 root 394:
1.1.1.5 root 395: /* if this is a user program or data function code: */
396: if (function_code == TME_M68K_FC_UD
397: || function_code == TME_M68K_FC_UP) {
398: context = sun2->tme_sun2_context_user;
399: access = TME_SUN_MMU_PTE_PROT_USER(access);
400: function_codes_mask = (TME_BIT(TME_M68K_FC_UD) + TME_BIT(TME_M68K_FC_UP));
401: }
402:
403: /* otherwise, this is a supervisor program or data function code: */
404: else {
405: context = sun2->tme_sun2_context_system;
406: access = TME_SUN_MMU_PTE_PROT_SYSTEM(access);
407: function_codes_mask += TME_BIT(TME_M68K_FC_SD);
1.1 root 408: }
409:
1.1.1.5 root 410: /* fill this TLB entry from the MMU: */
411: tlb_flags
412: = tme_sun_mmu_tlb_fill(sun2->tme_sun2_mmu,
413: tlb,
414: context,
415: address,
416: access);
417:
418: /* TLB entries are good only for the program and data function
419: codes for the user or supervisor, but never both, because
420: the two types of accesses go through different contexts: */
421: tlb_m68k->tme_m68k_tlb_function_codes_mask = function_codes_mask;
422:
1.1 root 423: return (TME_OK);
424: }
425:
426: /* our bus TLB filler: */
427: int
428: _tme_sun2_bus_tlb_fill(struct tme_bus_connection *conn_bus, struct tme_bus_tlb *tlb,
1.1.1.5 root 429: tme_bus_addr_t address_wider, unsigned int cycles)
1.1 root 430: {
431: struct tme_sun2 *sun2;
1.1.1.5 root 432: tme_bus_addr32_t address;
1.1.1.2 root 433: struct tme_sun2_bus_connection *conn_sun2;
434: tme_uint32_t base, size;
435: struct tme_bus_tlb tlb_bus;
1.1 root 436:
437: /* recover our sun2: */
438: sun2 = (struct tme_sun2 *) conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
439:
1.1.1.5 root 440: /* get the normal-width address: */
441: address = address_wider;
442: assert (address == address_wider);
443:
1.1.1.2 root 444: /* recover the sun2 internal mainbus connection: */
445: conn_sun2 = (struct tme_sun2_bus_connection *) conn_bus;
446:
447: /* turn the bus address into a DVMA address: */
448: switch (conn_sun2->tme_sun2_bus_connection_which) {
449:
450: /* obio devices can actually see the whole address space: */
451: case TME_SUN2_BUS_OBIO:
452: base = 0x000000;
453: size = 0x1000000;
454: break;
455:
456: case TME_SUN2_BUS_MBMEM:
457: base = 0xf00000;
458: size = TME_SUN2_DVMA_SIZE_MBMEM;
1.1.1.6 ! root 459:
! 460: #if 0
! 461: if (1) {
! 462: extern int printf(const char *format, ...);
! 463: printf("_tme_sun2_bus_tlb_fill; address %x\n", (int)address);
! 464: }
! 465: #endif
! 466:
1.1.1.2 root 467: break;
468:
469: case TME_SUN2_BUS_VME:
470: base = 0xf00000;
471: size = TME_SUN2_DVMA_SIZE_VME;
472: break;
473:
474: default: abort();
475: }
476:
477: assert (!(address & base)
478: && (address < size));
479:
1.1 root 480: /* fill this TLB entry from the MMU: */
481: tme_sun_mmu_tlb_fill(sun2->tme_sun2_mmu,
482: tlb,
483: sun2->tme_sun2_context_system,
1.1.1.2 root 484: address | base,
1.1 root 485: ((cycles & TME_BUS_CYCLE_WRITE)
486: ? TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RW)
487: : TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RO)));
1.1.1.2 root 488:
489: /* create the mapping TLB entry. we do this even if base == 0,
490: because the TLB entry as currently filled may cover more address
491: space than DVMA space on this machine is supposed to cover: */
1.1.1.4 root 492: tlb_bus.tme_bus_tlb_addr_first = 0;
493: tlb_bus.tme_bus_tlb_addr_last = size - 1;
1.1.1.2 root 494: tlb_bus.tme_bus_tlb_cycles_ok
495: = (TME_BUS_CYCLE_READ
496: | TME_BUS_CYCLE_WRITE);
497:
498: /* map the filled TLB entry: */
499: tme_bus_tlb_map(tlb, address | base, &tlb_bus, address);
500:
1.1 root 501: return (TME_OK);
502: }
503:
1.1.1.6 ! root 504: //#include "m68k-impl.h"
! 505:
1.1 root 506: /* our post-MMU TLB filler: */
507: static int
508: _tme_sun2_tlb_fill_mmu(void *_sun2, struct tme_bus_tlb *tlb,
509: struct tme_sun_mmu_pte *pte,
510: tme_uint32_t *_address,
511: unsigned int cycles)
512: {
513: struct tme_sun2 *sun2;
514: tme_uint32_t address;
515: unsigned int bus_type;
516: struct tme_bus_connection *conn_bus;
517: tme_bus_fault_handler bus_fault_handler;
518: int rc;
519:
520: /* recover our sun2: */
521: sun2 = (struct tme_sun2 *) _sun2;
522:
523: /* get the physical page frame and bus type: */
524: address = ((pte->tme_sun_mmu_pte_raw & TME_SUN2_PTE_PGFRAME) << TME_SUN2_PAGE_SIZE_LOG2);
525: bus_type = (pte->tme_sun_mmu_pte_raw & TME_SUN2_PTE_PGTYPE) / (TME_SUN2_PTE_PGTYPE / TME_SUN2_PTE_PGTYPE_MASK);
526:
527: /* any mapping of the *first* page of obio space means the PROM.
528: the virtual page frame is actually used to form the physical
529: address: */
530: if (address == 0
531: && bus_type == TME_SUN2_PGTYPE_OBIO) {
532: address = TME_SUN2_PROM_BASE | (*_address & ((TME_SUN2_PROM_SIZE - 1) & ~(TME_SUN2_PAGE_SIZE - 1)));
533: bus_type = TME_SUN2_PGTYPE_OBMEM;
534: }
535:
536: /* add in the page offset to finish the address: */
537: address |= *_address & (TME_SUN2_PAGE_SIZE - 1);
1.1.1.6 ! root 538: #if 0
! 539: if ((int)address > 0xffffff || (int)address < 0xef0000)
! 540: {
! 541: extern int printf(const char *format, ...);
! 542: struct tme_sun2 *s2 = (struct tme_sun2 *)sun2;
! 543: struct tme_m68k *m68k;
! 544: extern unsigned int _tme_m68010_get_pc(struct tme_m68k *ic);
! 545:
! 546: m68k = s2->tme_sun2_m68k->tme_m68k_bus_connection.tme_bus_connection.tme_connection_element->tme_element_private;
! 547:
! 548: if (_tme_m68010_get_pc(m68k) == 0x3c3bc) bradshow = 1;
! 549:
! 550: if (_tme_m68010_get_pc(m68k) == 0x3c3bc && address == 0 && jamdelay == 0) {
! 551: jamdelay = 2;
! 552: }
! 553:
! 554: if (bradshow)
! 555: printf("_tme_sun2_tlb_fill_mmu; address %08x, vir %08x, bus_type %d, boot %x, pc %08x\n",
! 556: (int)address, (int)_address, (int)bus_type,
! 557: (s2->tme_sun2_enable & TME_SUN2_ENA_NOTBOOT) ? 1 : 0,
! 558: _tme_m68010_get_pc(m68k));
! 559: }
! 560: #endif
1.1 root 561: *_address = address;
562:
1.1.1.6 ! root 563:
1.1 root 564: /* if this is obio: */
565: if (bus_type == TME_SUN2_PGTYPE_OBIO) {
566: conn_bus = sun2->tme_sun2_obio;
567: bus_fault_handler = _tme_sun2_obio_fault_handler;
568: }
569:
570: /* if this is obmem: */
571: else if (bus_type == TME_SUN2_PGTYPE_OBMEM) {
572: conn_bus = sun2->tme_sun2_obmem;
573: bus_fault_handler = _tme_sun2_obmem_fault_handler;
574: }
575:
576: /* if this is the VME bus: */
577: else if (sun2->tme_sun2_has_vme) {
578:
579: if (bus_type == TME_SUN2_PGTYPE_VME8) {
580: address |= 0x800000;
581: }
582: else {
583: assert(bus_type == TME_SUN2_PGTYPE_VME0);
584: }
585:
586: bus_fault_handler = _tme_sun2_vmebus_fault_handler;
587:
588: /* TBD: */
589: abort();
590: }
591:
592: /* if this is mbmem: */
593: else if (bus_type == TME_SUN2_PGTYPE_MBMEM) {
594: conn_bus = sun2->tme_sun2_mbmem;
595: bus_fault_handler = _tme_sun2_multibus_fault_handler;
596: }
597:
598: /* otherwise, this is mbio: */
599: else {
600: assert(bus_type == TME_SUN2_PGTYPE_MBIO);
601: conn_bus = sun2->tme_sun2_mbio;
602: bus_fault_handler = _tme_sun2_multibus_fault_handler;
603: }
604:
605: /* call the bus TLB filler: */
606: rc = ((*conn_bus->tme_bus_tlb_fill)
607: (conn_bus, tlb, address, cycles));
608:
1.1.1.6 ! root 609: #if 0
! 610: if (bus_type == TME_SUN2_PGTYPE_MBMEM && bradshow) {
! 611: extern int printf(const char *format, ...);
! 612: printf("_tme_sun2_tlb_fill_mmu; rc %d\n", rc);
! 613: }
! 614: #endif
! 615:
1.1 root 616: /* if the bus TLB filler succeeded, add our bus fault handler: */
617: if (rc == TME_OK) {
618: TME_BUS_TLB_FAULT_HANDLER(tlb, bus_fault_handler, sun2);
619: }
620:
1.1.1.6 ! root 621: #if 0
! 622: if (rc == TME_OK) {
! 623: if (jamdelay) {
! 624: jamdelay--;
! 625: if (jamdelay == 0) {
! 626: // tlb->tme_bus_tlb_cycles_ok &= ~(TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE);
! 627:
! 628: struct tme_bus_cycle c;
! 629: c.tme_bus_cycle_address = address;
! 630: _tme_sun2_bus_fault_handler(sun2, tlb, &c, ENOENT);
! 631: bradshow = 0;
! 632: // rc = ENOENT;
! 633:
! 634: extern int printf(const char *format, ...);
! 635: printf("waah. jamdelay went off\n");
! 636: }
! 637: }
! 638: }
! 639: #endif
! 640:
1.1 root 641: return (rc);
642: }
643:
644: /* this gets a PTE from the MMU: */
645: int
646: _tme_sun2_mmu_pte_get(struct tme_sun2 *sun2, tme_uint32_t address, tme_uint32_t *_pte_sun2)
647: {
648: struct tme_sun_mmu_pte pte;
649: tme_uint32_t pte_sun2;
650: unsigned int pte_flags;
651: int rc;
652:
653: /* get the PTE from the MMU: */
654: rc = tme_sun_mmu_pte_get(sun2->tme_sun2_mmu,
655: sun2->tme_sun2_context_user,
656: address,
657: &pte);
658: assert(rc == TME_OK);
659:
660: /* form the Sun-2 PTE: */
661: pte_sun2 = pte.tme_sun_mmu_pte_raw;
662: pte_flags = pte.tme_sun_mmu_pte_flags;
663: if (pte_flags & TME_SUN_MMU_PTE_REF) {
664: pte_sun2 |= TME_SUN2_PTE_REF;
665: }
666: if (pte_flags & TME_SUN_MMU_PTE_MOD) {
667: pte_sun2 |= TME_SUN2_PTE_MOD;
668: }
669:
670: /* done: */
671: *_pte_sun2 = pte_sun2;
672: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK,
673: (TME_SUN2_LOG_HANDLE(sun2),
674: _("pte_get: PGMAP[%d:0x%08x] -> 0x%08x"),
675: sun2->tme_sun2_context_user,
676: address,
677: pte_sun2));
678: return (TME_OK);
679: }
680:
681: /* this sets a PTE into the MMU: */
682: int
683: _tme_sun2_mmu_pte_set(struct tme_sun2 *sun2, tme_uint32_t address, tme_uint32_t pte_sun2)
684: {
685: struct tme_sun_mmu_pte pte;
686: unsigned int pte_flags;
687: #ifndef TME_NO_LOG
688: const char *bus_name;
1.1.1.5 root 689: tme_bus_addr32_t physical_address;
1.1 root 690:
1.1.1.2 root 691: /* this silences gcc -Wuninitialized: */
692: bus_name = NULL;
693:
1.1 root 694: /* log this setting: */
695: physical_address = ((pte_sun2 & TME_SUN2_PTE_PGFRAME) << TME_SUN2_PAGE_SIZE_LOG2);
696: switch ((pte_sun2 & TME_SUN2_PTE_PGTYPE) / (TME_SUN2_PTE_PGTYPE / TME_SUN2_PTE_PGTYPE_MASK)) {
697: case TME_SUN2_PGTYPE_OBMEM: bus_name = "obmem"; break;
698: case TME_SUN2_PGTYPE_OBIO: bus_name = "obio"; break;
699: case TME_SUN2_PGTYPE_MBMEM:
700: if (sun2->tme_sun2_has_vme) {
701: bus_name = "VME";
702: }
703: else {
704: bus_name = "mbmem";
705: }
706: break;
707: case TME_SUN2_PGTYPE_MBIO:
708: if (sun2->tme_sun2_has_vme) {
709: bus_name = "VME";
710: physical_address |= 0x800000;
711: }
712: else {
713: bus_name = "mbio";
714: }
715: break;
716: }
717: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK,
718: (TME_SUN2_LOG_HANDLE(sun2),
719: _("pte_set: PGMAP[%d:0x%08x] <- 0x%08x (%s 0x%08x)"),
720: sun2->tme_sun2_context_user,
721: address,
722: pte_sun2,
723: bus_name,
724: physical_address));
725: #endif /* !TME_NO_LOG */
726:
727: pte.tme_sun_mmu_pte_raw = pte_sun2;
728:
729: pte_flags = 0;
730: if (pte_sun2 & TME_SUN2_PTE_MOD) {
731: pte_flags |= TME_SUN_MMU_PTE_MOD;
732: }
733: if (pte_sun2 & TME_SUN2_PTE_REF) {
734: pte_flags |= TME_SUN_MMU_PTE_REF;
735: }
736: switch (pte_sun2 & TME_SUN2_PTE_PROT) {
737:
738: /* with this protection, the system can read and write,
739: and the user gets a protection error: */
740: case 0x70000000:
741: case 0x74000000:
742: case 0x60000000:
743: pte_flags |=
744: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RW)
745: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_ERROR));
746: break;
747:
748: /* with this protection, the system gets a protection error,
749: and the user gets a protection error: */
750: case 0x30000000:
751: case 0x20000000:
752: case 0x10000000:
753: case 0x00000000:
754: case 0x04000000:
755: pte_flags |=
756: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_ERROR)
757: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_ERROR));
758: break;
759:
760: /* with this protection, the system can read and write,
761: and the user can read and write: */
762: case 0x7C000000:
763: case 0x6C000000:
764: pte_flags |=
765: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RW)
766: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RW));
767: break;
768:
769: /* with this protection, the system can read and write,
770: and the user can read: */
771: case 0x78000000:
772: pte_flags |=
773: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RW)
774: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RO));
775: break;
776:
777: /* with this protection, the system can read,
778: and the user can read: */
779: case 0x58000000:
780: pte_flags |=
781: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RO)
782: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RO));
783: break;
784:
785: /* with this protection, the system can read,
786: and the user can read and write: */
787: case 0x5C000000:
788: case 0x4C000000:
789: pte_flags |=
790: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RO)
791: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RW));
792: break;
793:
794: /* with this protection, the system can read,
795: and the user gets a protection error: */
796: case 0x50000000:
797: case 0x40000000:
798: pte_flags |=
799: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RO)
800: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_ERROR));
801: break;
802:
803: /* with this protection, the system gets a protection error,
804: and the user can read and write: */
805: case 0x3c000000:
1.1.1.2 root 806: case 0x0c000000:
1.1 root 807: pte_flags |=
808: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_ERROR)
809: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RW));
810: break;
811:
812: /* with this protection, the system gets a protection error,
813: and the user can read: */
814: case 0x08000000:
815: pte_flags |=
816: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_ERROR)
817: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RO));
818: break;
819:
820: default: abort();
821: }
822: if (pte_sun2 & TME_SUN2_PTE_VALID) {
823: pte_flags |= TME_SUN_MMU_PTE_VALID;
824: }
825: pte.tme_sun_mmu_pte_flags = pte_flags;
826:
827: return (tme_sun_mmu_pte_set(sun2->tme_sun2_mmu,
828: sun2->tme_sun2_context_user,
829: address,
830: &pte));
831: }
832:
833: /* this is called when the system context register is set: */
834: void
835: _tme_sun2_mmu_context_system_set(struct tme_sun2 *sun2)
836: {
837: /* system context register changes are assumed to be rare. if they
838: were frequent, we'd have to allocate 64 TLB sets for each TLB
839: user - one for each possible combination of user context and
840: system context. instead, when the system context register
841: changes, we simply invalidate all TLB entries everywhere: */
842: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK,
843: (TME_SUN2_LOG_HANDLE(sun2),
844: _("system context now #%d"),
845: sun2->tme_sun2_context_system));
846: tme_sun_mmu_tlbs_invalidate(sun2->tme_sun2_mmu);
847: }
848:
849: /* this is called when the user context register is set: */
850: void
851: _tme_sun2_mmu_context_user_set(struct tme_sun2 *sun2)
852: {
1.1.1.5 root 853: tme_bus_context_t context_base;
1.1 root 854:
1.1.1.5 root 855: /* NB that even though user and supervisor references use the two
856: different context registers simultaneously, TLB entries for one
857: are never usable by the other. because of this, and because we
858: assume that the system context register rarely changes, we choose
859: not to factor the system context into the context seen by the
860: m68k: */
1.1 root 861:
1.1.1.5 root 862: /* there are sixteen total contexts. contexts zero through seven
863: are the not-boot (normal) contexts. contexts eight through
864: fifteen are the same contexts, but in the boot state.
1.1 root 865:
1.1.1.5 root 866: in the boot state, TLB fills for supervisor program references
867: bypass the MMU and are filled to reference the PROM, and data
868: fills are filled as normal using the current context: */
1.1 root 869:
1.1.1.5 root 870: /* in the not-boot (i.e., normal, state): */
871: if (__tme_predict_true(sun2->tme_sun2_enable & TME_SUN2_ENA_NOTBOOT)) {
1.1 root 872:
1.1.1.5 root 873: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK,
874: (TME_SUN2_LOG_HANDLE(sun2),
875: _("user context now #%d"),
876: sun2->tme_sun2_context_user));
1.1 root 877:
1.1.1.5 root 878: /* the normal state contexts are numbered from zero: */
879: context_base = 0;
880: }
1.1 root 881:
1.1.1.5 root 882: /* in the boot state: */
883: else {
1.1 root 884:
1.1.1.5 root 885: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK,
886: (TME_SUN2_LOG_HANDLE(sun2),
887: _("user context now #%d (boot state)"),
888: sun2->tme_sun2_context_user));
1.1 root 889:
1.1.1.5 root 890: /* the boot state contexts are numbered from eight: */
891: context_base = TME_SUN2_CONTEXT_COUNT;
1.1 root 892: }
893:
1.1.1.5 root 894: /* update the m68k bus context register: */
895: *sun2->tme_sun2_m68k_bus_context
896: = (context_base
897: + sun2->tme_sun2_context_user);
898:
899: /* NB: unlike the sun3, sun2 DVMA TLBS are always filled using the
900: system context, meaning they don't need to be invalidated when
901: the user context changes, so we don't need to call
902: tme_sun_mmu_context_switched() here: */
1.1 root 903: }
904:
1.1.1.5 root 905: /* this adds a new TLB set: */
1.1 root 906: int
1.1.1.5 root 907: _tme_sun2_mmu_tlb_set_add(struct tme_bus_connection *conn_bus_asker,
908: struct tme_bus_tlb_set_info *tlb_set_info)
1.1 root 909: {
1.1.1.5 root 910: struct tme_sun2 *sun2;
911: int rc;
912:
913: /* recover our sun2: */
914: sun2 = (struct tme_sun2 *) conn_bus_asker->tme_bus_connection.tme_connection_element->tme_element_private;
915:
916: /* add the TLB set to the MMU: */
917: rc = tme_sun_mmu_tlb_set_add(sun2->tme_sun2_mmu,
918: tlb_set_info);
919: assert (rc == TME_OK);
920:
921: /* if this is the TLB set from the m68k: */
922: if (conn_bus_asker->tme_bus_connection.tme_connection_type == TME_CONNECTION_BUS_M68K) {
923:
924: /* the m68k must expose a bus context register: */
925: assert (tlb_set_info->tme_bus_tlb_set_info_bus_context != NULL);
926:
927: /* save the pointer to the m68k bus context register, and
928: initialize it: */
929: sun2->tme_sun2_m68k_bus_context
930: = tlb_set_info->tme_bus_tlb_set_info_bus_context;
931: _tme_sun2_mmu_context_user_set(sun2);
932:
933: /* return the maximum context number. there are eight
934: contexts in the not-boot (normal) state, and each of
935: them has a boot state counterpart: */
936: tlb_set_info->tme_bus_tlb_set_info_bus_context_max
937: = (TME_SUN2_CONTEXT_COUNT
938: + TME_SUN2_CONTEXT_COUNT
939: - 1);
1.1 root 940: }
941:
1.1.1.5 root 942: return (rc);
1.1 root 943: }
944:
945: /* this creates a Sun-2 MMU: */
946: void
947: _tme_sun2_mmu_new(struct tme_sun2 *sun2)
948: {
949: struct tme_sun_mmu_info mmu_info;
950:
1.1.1.4 root 951: memset(&mmu_info, 0, sizeof(mmu_info));
1.1 root 952: mmu_info.tme_sun_mmu_info_element = sun2->tme_sun2_element;
953: mmu_info.tme_sun_mmu_info_address_bits = 24;
954: mmu_info.tme_sun_mmu_info_pgoffset_bits = TME_SUN2_PAGE_SIZE_LOG2;
955: mmu_info.tme_sun_mmu_info_pteindex_bits = 4;
1.1.1.5 root 956: mmu_info.tme_sun_mmu_info_contexts = TME_SUN2_CONTEXT_COUNT;
1.1 root 957: mmu_info.tme_sun_mmu_info_pmegs = 256;
958: mmu_info.tme_sun_mmu_info_tlb_fill_private = sun2;
959: mmu_info.tme_sun_mmu_info_tlb_fill = _tme_sun2_tlb_fill_mmu;
960: mmu_info.tme_sun_mmu_info_proterr_private = sun2;
961: mmu_info.tme_sun_mmu_info_proterr = _tme_sun2_mmu_proterr;
962: mmu_info.tme_sun_mmu_info_invalid_private = sun2;
963: mmu_info.tme_sun_mmu_info_invalid = _tme_sun2_mmu_invalid;
964: sun2->tme_sun2_mmu = tme_sun_mmu_new(&mmu_info);
965: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.