|
|
1.1 root 1: /* $Id: sun2-mmu.c,v 1.7 2003/05/16 21:48:13 fredette Exp $ */
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>
37: _TME_RCSID("$Id: sun2-mmu.c,v 1.7 2003/05/16 21:48:13 fredette Exp $");
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:
70: /* this logs a bus error: */
71: #ifndef TME_NO_LOG
72: static void
73: _tme_sun2_bus_fault_log(struct tme_sun2 *sun2, 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_sun2;
78: const char *bus_name;
79: tme_bus_addr_t physical_address;
80: int rc;
81:
82: /* recover the virtual address used: */
83: virtual_address = cycle->tme_bus_cycle_address - tlb->tme_bus_tlb_addr_offset;
84:
85: /* look up the PTE involved. since this is a real bus error, and
86: not a protection violation or page not present bus error, we
87: assume the system context: */
88: rc = tme_sun_mmu_pte_get(sun2->tme_sun2_mmu,
89: sun2->tme_sun2_context_system,
90: virtual_address,
91: &pte);
92: assert(rc == TME_OK);
93: pte_sun2 = pte.tme_sun_mmu_pte_raw;
94:
95: /* form the physical address and get the bus name: */
96: physical_address = (((pte_sun2 & TME_SUN2_PTE_PGFRAME) << TME_SUN2_PAGE_SIZE_LOG2)
97: | (virtual_address & (TME_SUN2_PAGE_SIZE - 1)));
98: switch ((pte_sun2 & TME_SUN2_PTE_PGTYPE) / (TME_SUN2_PTE_PGTYPE / TME_SUN2_PTE_PGTYPE_MASK)) {
99: case TME_SUN2_PGTYPE_OBMEM: bus_name = "obmem"; break;
100: case TME_SUN2_PGTYPE_OBIO: bus_name = "obio"; break;
101: case TME_SUN2_PGTYPE_MBMEM:
102: if (sun2->tme_sun2_has_vme) {
103: bus_name = "VME";
104: }
105: else {
106: bus_name = "mbmem";
107: }
108: break;
109: case TME_SUN2_PGTYPE_MBIO:
110: if (sun2->tme_sun2_has_vme) {
111: bus_name = "VME";
112: physical_address |= 0x800000;
113: }
114: else {
115: bus_name = "mbio";
116: }
117: break;
118: }
119:
120: /* log this bus error: */
121: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK,
122: (TME_SUN2_LOG_HANDLE(sun2),
123: _("%s bus error, physical 0x%08x, virtual 0x%08x, buserr = 0x%02x"),
124: bus_name,
125: physical_address,
126: virtual_address,
127: sun2->tme_sun2_buserr));
128: }
129: #else /* TME_NO_LOG */
130: #define _tme_sun2_bus_fault_log(a, b, c) do { } while (/* CONSTCOND */ 0)
131: #endif /* TME_NO_LOG */
132:
133: /* our general bus fault handler: */
134: static int
135: _tme_sun2_bus_fault_handler(struct tme_sun2 *sun2,
136: struct tme_bus_tlb *tlb,
137: struct tme_bus_cycle *cycle,
138: int rc)
139: {
140: tme_uint16_t buserr;
141:
142: /* dispatch on our fault code: */
143: switch (rc) {
144:
145: /* bus address nonexistent: */
146: case ENOENT:
147: buserr = TME_SUN2_BUSERR_VALID | TME_SUN2_BUSERR_TIMEOUT;
148: break;
149:
150: /* anything else is just a fault: */
151: default:
152: buserr = TME_SUN2_BUSERR_VALID;
153: break;
154: }
155:
156: /* set the bus error register: */
157: sun2->tme_sun2_buserr = buserr;
158:
159: /* log the fault: */
160: _tme_sun2_bus_fault_log(sun2, tlb, cycle);
161:
162: return (rc);
163: }
164:
165: /* our obio bus fault handler: */
166: static int
167: _tme_sun2_obio_fault_handler(void *_sun2, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc)
168: {
169: tme_uint8_t all_bits_one[sizeof(tme_uint16_t)];
170:
171: /* the sun2 obio bus doesn't generate bus errors, it just reads
172: all-bits-one: */
173: memset(all_bits_one, 0xff, sizeof(all_bits_one));
174: tme_bus_cycle_xfer_memory(cycle,
175: &all_bits_one[0] - cycle->tme_bus_cycle_address,
176: cycle->tme_bus_cycle_address + sizeof(all_bits_one));
177: return (TME_OK);
178: }
179:
180: /* our obmem bus fault handler: */
181: static int
182: _tme_sun2_obmem_fault_handler(void *_sun2, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc)
183: {
184: tme_uint8_t all_bits_one[sizeof(tme_uint16_t)];
185:
186: /* the sun2 obmem bus apparently doesn't generate bus errors below
187: 0x700000, and instead just reads all-bits-one: */
188: if (cycle->tme_bus_cycle_address < 0x700000) {
189: memset(all_bits_one, 0xff, sizeof(all_bits_one));
190: tme_bus_cycle_xfer_memory(cycle,
191: &all_bits_one[0] - cycle->tme_bus_cycle_address,
192: cycle->tme_bus_cycle_address + sizeof(all_bits_one));
193: return (TME_OK);
194: }
195:
196: /* call the common bus fault handler: */
197: return (_tme_sun2_bus_fault_handler((struct tme_sun2 *) _sun2, tlb, cycle, rc));
198: }
199:
200: /* our Multibus fault handler: */
201: static int
202: _tme_sun2_multibus_fault_handler(void *_sun2, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc)
203: {
204:
205: /* call the common bus fault handler: */
206: return (_tme_sun2_bus_fault_handler((struct tme_sun2 *) _sun2, tlb, cycle, rc));
207: }
208:
209: /* our VMEbus fault handler: */
210: static int
211: _tme_sun2_vmebus_fault_handler(void *_sun2, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc)
212: {
213: struct tme_sun2 *sun2;
214:
215: /* recover our sun2: */
216: sun2 = (struct tme_sun2 *) _sun2;
217:
218: /* call the common bus fault handler: */
219: rc = _tme_sun2_bus_fault_handler((struct tme_sun2 *) _sun2, tlb, cycle, rc);
220:
221: /* this bus fault happened on the VMEbus: */
222: sun2->tme_sun2_buserr |= TME_SUN2_BUSERR_VMEBUSERR;
223:
224: /* return the fault: */
225: return (rc);
226: }
227:
228: /* our page-invalid cycle handler: */
229: static int
230: _tme_sun2_mmu_invalid(void *_sun2, struct tme_bus_cycle *cycle)
231: {
232: struct tme_sun2 *sun2;
233:
234: /* recover our sun2: */
235: sun2 = (struct tme_sun2 *) _sun2;
236:
237: /* log this bus error: */
238: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK,
239: (TME_SUN2_LOG_HANDLE(sun2),
240: _("page invalid bus error")));
241:
242: /* set the bus error register: */
243: sun2->tme_sun2_buserr = TME_SUN2_BUSERR_PROTERR;
244:
245: /* return the fault: */
246: return (EFAULT);
247: }
248:
249: /* our protection error cycle handler: */
250: static int
251: _tme_sun2_mmu_proterr(void *_sun2, struct tme_bus_cycle *cycle)
252: {
253: struct tme_sun2 *sun2;
254:
255: /* recover our sun2: */
256: sun2 = (struct tme_sun2 *) _sun2;
257:
258: /* log this bus error: */
259: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK,
260: (TME_SUN2_LOG_HANDLE(sun2),
261: _("page protection bus error")));
262:
263: /* set the bus error register: */
264: sun2->tme_sun2_buserr = TME_SUN2_BUSERR_VALID | TME_SUN2_BUSERR_PROTERR;
265:
266: /* return the fault: */
267: return (EFAULT);
268: }
269:
270: /* our m68k TLB filler: */
271: int
272: _tme_sun2_m68k_tlb_fill(struct tme_m68k_bus_connection *conn_m68k, struct tme_m68k_tlb *tlb_m68k,
273: unsigned int function_code, tme_uint32_t address, unsigned int cycles)
274: {
275: struct tme_sun2 *sun2;
276: struct tme_bus_tlb *tlb;
277: unsigned short tlb_flags;
278:
279: /* recover our sun2: */
280: sun2 = (struct tme_sun2 *) conn_m68k->tme_m68k_bus_connection.tme_bus_connection.tme_connection_element->tme_element_private;
281:
282: /* get the generic bus TLB: */
283: tlb = &tlb_m68k->tme_m68k_tlb_bus_tlb;
284:
285: /* if this is function code three, we handle this ourselves: */
286: if (function_code == TME_M68K_FC_3) {
287:
288: /* initialize the TLB entry: */
289: tme_bus_tlb_initialize(tlb);
290:
291: /* we cover the entire address space: */
292: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, 0);
293: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, -1);
294:
295: /* we allow reading and writing: */
296: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
297:
298: /* our bus cycle handler: */
299: tlb->tme_bus_tlb_cycle_private = sun2;
300: tlb->tme_bus_tlb_cycle = _tme_sun2_control_cycle_handler;
301:
302: /* this is good for function code three only: */
303: tlb_m68k->tme_m68k_tlb_function_codes_mask = TME_BIT(TME_M68K_FC_3);
304: }
305:
306: /* if this is a supervisor function code and we're in the PROM
307: address range, we handle this ourselves: */
308: else if ((function_code == TME_M68K_FC_SD
309: || function_code == TME_M68K_FC_SP)
310: && address >= TME_SUN2_PROM_BASE
311: && address < (TME_SUN2_PROM_BASE + TME_SUN2_PROM_SIZE)) {
312:
313: /* fill this TLB entry directly from the obmem bus: */
314: (*sun2->tme_sun2_obmem->tme_bus_tlb_fill)
315: (sun2->tme_sun2_obmem,
316: tlb,
317: address,
318: cycles);
319:
320: /* this is good for supervisor data and supervisor program function codes: */
321: tlb_m68k->tme_m68k_tlb_function_codes_mask = (TME_BIT(TME_M68K_FC_SD)
322: | TME_BIT(TME_M68K_FC_SP));
323: }
324:
325: /* this is a normal function code: */
326: else {
327:
328: /* fill this TLB entry from the MMU: */
329: tlb_flags = ((function_code == TME_M68K_FC_UD
330: || function_code == TME_M68K_FC_UP)
331: ? tme_sun_mmu_tlb_fill(sun2->tme_sun2_mmu,
332: tlb,
333: sun2->tme_sun2_context_user,
334: address,
335: ((cycles & TME_BUS_CYCLE_WRITE)
336: ? TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RW)
337: : TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RO)))
338: : tme_sun_mmu_tlb_fill(sun2->tme_sun2_mmu,
339: tlb,
340: sun2->tme_sun2_context_system,
341: address,
342: ((cycles & TME_BUS_CYCLE_WRITE)
343: ? TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RW)
344: : TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RO))));
345:
346: /* TLB entries are good only for the program and data function
347: codes for the user or supervisor, but never both, because
348: the two types of accesses go through different contexts: */
349: tlb_m68k->tme_m68k_tlb_function_codes_mask =
350: ((function_code == TME_M68K_FC_UD
351: || function_code == TME_M68K_FC_UP)
352: ? (TME_BIT(TME_M68K_FC_UD)
353: | TME_BIT(TME_M68K_FC_UP))
354: : (TME_BIT(TME_M68K_FC_SD)
355: | TME_BIT(TME_M68K_FC_SP)));
356: }
357:
358: return (TME_OK);
359: }
360:
361: /* our bus TLB filler: */
362: int
363: _tme_sun2_bus_tlb_fill(struct tme_bus_connection *conn_bus, struct tme_bus_tlb *tlb,
364: tme_uint32_t address, unsigned int cycles)
365: {
366: struct tme_sun2 *sun2;
367:
368: /* recover our sun2: */
369: sun2 = (struct tme_sun2 *) conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
370:
371: /* fill this TLB entry from the MMU: */
372: tme_sun_mmu_tlb_fill(sun2->tme_sun2_mmu,
373: tlb,
374: sun2->tme_sun2_context_system,
375: address,
376: ((cycles & TME_BUS_CYCLE_WRITE)
377: ? TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RW)
378: : TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RO)));
379: return (TME_OK);
380: }
381:
382: /* our post-MMU TLB filler: */
383: static int
384: _tme_sun2_tlb_fill_mmu(void *_sun2, struct tme_bus_tlb *tlb,
385: struct tme_sun_mmu_pte *pte,
386: tme_uint32_t *_address,
387: unsigned int cycles)
388: {
389: struct tme_sun2 *sun2;
390: tme_uint32_t address;
391: unsigned int bus_type;
392: struct tme_bus_connection *conn_bus;
393: tme_bus_fault_handler bus_fault_handler;
394: int rc;
395:
396: /* recover our sun2: */
397: sun2 = (struct tme_sun2 *) _sun2;
398:
399: /* get the physical page frame and bus type: */
400: address = ((pte->tme_sun_mmu_pte_raw & TME_SUN2_PTE_PGFRAME) << TME_SUN2_PAGE_SIZE_LOG2);
401: bus_type = (pte->tme_sun_mmu_pte_raw & TME_SUN2_PTE_PGTYPE) / (TME_SUN2_PTE_PGTYPE / TME_SUN2_PTE_PGTYPE_MASK);
402:
403: /* any mapping of the *first* page of obio space means the PROM.
404: the virtual page frame is actually used to form the physical
405: address: */
406: if (address == 0
407: && bus_type == TME_SUN2_PGTYPE_OBIO) {
408: address = TME_SUN2_PROM_BASE | (*_address & ((TME_SUN2_PROM_SIZE - 1) & ~(TME_SUN2_PAGE_SIZE - 1)));
409: bus_type = TME_SUN2_PGTYPE_OBMEM;
410: }
411:
412: /* add in the page offset to finish the address: */
413: address |= *_address & (TME_SUN2_PAGE_SIZE - 1);
414: *_address = address;
415:
416: /* if this is obio: */
417: if (bus_type == TME_SUN2_PGTYPE_OBIO) {
418: conn_bus = sun2->tme_sun2_obio;
419: bus_fault_handler = _tme_sun2_obio_fault_handler;
420: }
421:
422: /* if this is obmem: */
423: else if (bus_type == TME_SUN2_PGTYPE_OBMEM) {
424: conn_bus = sun2->tme_sun2_obmem;
425: bus_fault_handler = _tme_sun2_obmem_fault_handler;
426: }
427:
428: /* if this is the VME bus: */
429: else if (sun2->tme_sun2_has_vme) {
430:
431: if (bus_type == TME_SUN2_PGTYPE_VME8) {
432: address |= 0x800000;
433: }
434: else {
435: assert(bus_type == TME_SUN2_PGTYPE_VME0);
436: }
437:
438: bus_fault_handler = _tme_sun2_vmebus_fault_handler;
439:
440: /* TBD: */
441: abort();
442: }
443:
444: /* if this is mbmem: */
445: else if (bus_type == TME_SUN2_PGTYPE_MBMEM) {
446: conn_bus = sun2->tme_sun2_mbmem;
447: bus_fault_handler = _tme_sun2_multibus_fault_handler;
448: }
449:
450: /* otherwise, this is mbio: */
451: else {
452: assert(bus_type == TME_SUN2_PGTYPE_MBIO);
453: conn_bus = sun2->tme_sun2_mbio;
454: bus_fault_handler = _tme_sun2_multibus_fault_handler;
455: }
456:
457: /* call the bus TLB filler: */
458: rc = ((*conn_bus->tme_bus_tlb_fill)
459: (conn_bus, tlb, address, cycles));
460:
461: /* if the bus TLB filler succeeded, add our bus fault handler: */
462: if (rc == TME_OK) {
463: TME_BUS_TLB_FAULT_HANDLER(tlb, bus_fault_handler, sun2);
464: }
465:
466: return (rc);
467: }
468:
469: /* this gets a PTE from the MMU: */
470: int
471: _tme_sun2_mmu_pte_get(struct tme_sun2 *sun2, tme_uint32_t address, tme_uint32_t *_pte_sun2)
472: {
473: struct tme_sun_mmu_pte pte;
474: tme_uint32_t pte_sun2;
475: unsigned int pte_flags;
476: int rc;
477:
478: /* get the PTE from the MMU: */
479: rc = tme_sun_mmu_pte_get(sun2->tme_sun2_mmu,
480: sun2->tme_sun2_context_user,
481: address,
482: &pte);
483: assert(rc == TME_OK);
484:
485: /* form the Sun-2 PTE: */
486: pte_sun2 = pte.tme_sun_mmu_pte_raw;
487: pte_flags = pte.tme_sun_mmu_pte_flags;
488: if (pte_flags & TME_SUN_MMU_PTE_REF) {
489: pte_sun2 |= TME_SUN2_PTE_REF;
490: }
491: if (pte_flags & TME_SUN_MMU_PTE_MOD) {
492: pte_sun2 |= TME_SUN2_PTE_MOD;
493: }
494:
495: /* done: */
496: *_pte_sun2 = pte_sun2;
497: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK,
498: (TME_SUN2_LOG_HANDLE(sun2),
499: _("pte_get: PGMAP[%d:0x%08x] -> 0x%08x"),
500: sun2->tme_sun2_context_user,
501: address,
502: pte_sun2));
503: return (TME_OK);
504: }
505:
506: /* this sets a PTE into the MMU: */
507: int
508: _tme_sun2_mmu_pte_set(struct tme_sun2 *sun2, tme_uint32_t address, tme_uint32_t pte_sun2)
509: {
510: struct tme_sun_mmu_pte pte;
511: unsigned int pte_flags;
512: #ifndef TME_NO_LOG
513: const char *bus_name;
514: tme_bus_addr_t physical_address;
515:
516: /* log this setting: */
517: physical_address = ((pte_sun2 & TME_SUN2_PTE_PGFRAME) << TME_SUN2_PAGE_SIZE_LOG2);
518: switch ((pte_sun2 & TME_SUN2_PTE_PGTYPE) / (TME_SUN2_PTE_PGTYPE / TME_SUN2_PTE_PGTYPE_MASK)) {
519: case TME_SUN2_PGTYPE_OBMEM: bus_name = "obmem"; break;
520: case TME_SUN2_PGTYPE_OBIO: bus_name = "obio"; break;
521: case TME_SUN2_PGTYPE_MBMEM:
522: if (sun2->tme_sun2_has_vme) {
523: bus_name = "VME";
524: }
525: else {
526: bus_name = "mbmem";
527: }
528: break;
529: case TME_SUN2_PGTYPE_MBIO:
530: if (sun2->tme_sun2_has_vme) {
531: bus_name = "VME";
532: physical_address |= 0x800000;
533: }
534: else {
535: bus_name = "mbio";
536: }
537: break;
538: }
539: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK,
540: (TME_SUN2_LOG_HANDLE(sun2),
541: _("pte_set: PGMAP[%d:0x%08x] <- 0x%08x (%s 0x%08x)"),
542: sun2->tme_sun2_context_user,
543: address,
544: pte_sun2,
545: bus_name,
546: physical_address));
547: #endif /* !TME_NO_LOG */
548:
549: pte.tme_sun_mmu_pte_raw = pte_sun2;
550:
551: pte_flags = 0;
552: if (pte_sun2 & TME_SUN2_PTE_MOD) {
553: pte_flags |= TME_SUN_MMU_PTE_MOD;
554: }
555: if (pte_sun2 & TME_SUN2_PTE_REF) {
556: pte_flags |= TME_SUN_MMU_PTE_REF;
557: }
558: switch (pte_sun2 & TME_SUN2_PTE_PROT) {
559:
560: /* with this protection, the system can read and write,
561: and the user gets a protection error: */
562: case 0x70000000:
563: case 0x74000000:
564: case 0x60000000:
565: pte_flags |=
566: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RW)
567: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_ERROR));
568: break;
569:
570: /* with this protection, the system gets a protection error,
571: and the user gets a protection error: */
572: case 0x30000000:
573: case 0x20000000:
574: case 0x10000000:
575: case 0x00000000:
576: case 0x04000000:
577: pte_flags |=
578: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_ERROR)
579: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_ERROR));
580: break;
581:
582: /* with this protection, the system can read and write,
583: and the user can read and write: */
584: case 0x7C000000:
585: case 0x6C000000:
586: pte_flags |=
587: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RW)
588: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RW));
589: break;
590:
591: /* with this protection, the system can read and write,
592: and the user can read: */
593: case 0x78000000:
594: pte_flags |=
595: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RW)
596: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RO));
597: break;
598:
599: /* with this protection, the system can read,
600: and the user can read: */
601: case 0x58000000:
602: pte_flags |=
603: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RO)
604: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RO));
605: break;
606:
607: /* with this protection, the system can read,
608: and the user can read and write: */
609: case 0x5C000000:
610: case 0x4C000000:
611: pte_flags |=
612: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RO)
613: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RW));
614: break;
615:
616: /* with this protection, the system can read,
617: and the user gets a protection error: */
618: case 0x50000000:
619: case 0x40000000:
620: pte_flags |=
621: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_RO)
622: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_ERROR));
623: break;
624:
625: /* with this protection, the system gets a protection error,
626: and the user can read and write: */
627: case 0x3c000000:
628: pte_flags |=
629: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_ERROR)
630: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RW));
631: break;
632:
633: /* with this protection, the system gets a protection error,
634: and the user can read: */
635: case 0x08000000:
636: pte_flags |=
637: (TME_SUN_MMU_PTE_PROT_SYSTEM(TME_SUN_MMU_PTE_PROT_ERROR)
638: | TME_SUN_MMU_PTE_PROT_USER(TME_SUN_MMU_PTE_PROT_RO));
639: break;
640:
641: default: abort();
642: }
643: if (pte_sun2 & TME_SUN2_PTE_VALID) {
644: pte_flags |= TME_SUN_MMU_PTE_VALID;
645: }
646: pte.tme_sun_mmu_pte_flags = pte_flags;
647:
648: return (tme_sun_mmu_pte_set(sun2->tme_sun2_mmu,
649: sun2->tme_sun2_context_user,
650: address,
651: &pte));
652: }
653:
654: /* this is called when the system context register is set: */
655: void
656: _tme_sun2_mmu_context_system_set(struct tme_sun2 *sun2)
657: {
658: /* system context register changes are assumed to be rare. if they
659: were frequent, we'd have to allocate 64 TLB sets for each TLB
660: user - one for each possible combination of user context and
661: system context. instead, when the system context register
662: changes, we simply invalidate all TLB entries everywhere: */
663: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK,
664: (TME_SUN2_LOG_HANDLE(sun2),
665: _("system context now #%d"),
666: sun2->tme_sun2_context_system));
667: tme_sun_mmu_tlbs_invalidate(sun2->tme_sun2_mmu);
668: }
669:
670: /* this is called when the user context register is set: */
671: void
672: _tme_sun2_mmu_context_user_set(struct tme_sun2 *sun2)
673: {
674: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK,
675: (TME_SUN2_LOG_HANDLE(sun2),
676: _("user context now #%d"),
677: sun2->tme_sun2_context_user));
678: tme_sun_mmu_tlbs_context_set(sun2->tme_sun2_mmu, sun2->tme_sun2_context_user);
679: }
680:
681: /* this allocates a new TLB set: */
682: int
683: _tme_sun2_mmu_tlb_set_allocate(struct tme_bus_connection *conn_bus_asker,
684: unsigned int count, unsigned int sizeof_one,
685: TME_ATOMIC_POINTER_TYPE(struct tme_bus_tlb **) _tlbs)
686: {
687: struct tme_sun2 *sun2;
688: int rc;
689:
690: /* recover our sun2: */
691: sun2 = (struct tme_sun2 *) conn_bus_asker->tme_bus_connection.tme_connection_element->tme_element_private;
692:
693: /* get the MMU to allocate the TLB set: */
694: rc = tme_sun_mmu_tlb_set_allocate(sun2->tme_sun2_mmu, count, sizeof_one, _tlbs);
695:
696: /* if this is the TLB set for our CPU, remember where the context
697: zero TLBs are, and try to reset the MMU now: */
698: /* FIXME - this assumes that the *first* TLB set allocated by
699: the CPU is for its data: */
700: if (rc == TME_OK
701: && conn_bus_asker->tme_bus_connection.tme_connection_type == TME_CONNECTION_BUS_M68K
702: && sun2->tme_sun2_reset_tlbs == NULL) {
703: assert(sizeof_one == sizeof(struct tme_m68k_tlb));
704: sun2->tme_sun2_reset_tlbs = (struct tme_m68k_tlb *) TME_ATOMIC_READ(struct tme_bus_tlb *, *_tlbs);
705: sun2->tme_sun2_reset_tlb_count = count;
706: _tme_sun2_mmu_reset(sun2);
707: }
708:
709: return (rc);
710: }
711:
712: /* the first four 16-bit read cycles that the m68010 does after it comes
713: out of reset are to fetch the reset vector (one 32-bit word for the
714: initial SSP, one 32-bit word for the initial PC).
715:
716: apparently the Sun-2 reset circuitry has some special logic that
717: is able to direct these read cycles to the PROM, where the reset
718: vector is located. we simulate this logic by forcing the CPU's
719: context zero TLB entries to all point to ROM for addresses 0-7,
720: but only for the first four cycles, after which we invalidate
721: all of the CPU TLB entries. */
722:
723: /* this is a special bus cycle handling function used at reset time.
724: it is used only for the first four m68010 read cycles: */
725: static int
726: _tme_sun2_reset_cycle(void *_sun2, struct tme_bus_cycle *cycle)
727: {
728: struct tme_sun2 *sun2;
729: int rc;
730:
731: /* recover our sun2: */
732: sun2 = (struct tme_sun2 *) _sun2;
733:
734: /* this must be a 16-bit read: */
735: assert(cycle->tme_bus_cycle_size == sizeof(tme_uint16_t));
736: tme_log(TME_SUN2_LOG_HANDLE(sun2), 1000, TME_OK,
737: (TME_SUN2_LOG_HANDLE(sun2),
738: _("reset cycle #%d"),
739: sun2->tme_sun2_reset_cycles));
740:
741: /* run the real cycle: */
742: rc = ((*sun2->tme_sun2_reset_cycle)
743: (sun2->tme_sun2_reset_cycle_private,
744: cycle));
745:
746: /* after the fourth read cycle, invalidate all of the TLBs
747: that the CPU holds, ending these abnormal reset reads: */
748: if (rc == TME_OK) {
749: sun2->tme_sun2_reset_cycles++;
750: if (sun2->tme_sun2_reset_cycles == 4) {
751: tme_sun_mmu_tlbs_invalidate(sun2->tme_sun2_mmu);
752: }
753: }
754:
755: return (rc);
756: }
757:
758: /* this initialize the context zero part of the CPU's TLB set to
759: support four slow 16-bit reads from ROM at addresses 0, 2, 4, 6,
760: respectively. this emulates how the Sun-2 behaves as it comes out
761: of reset: */
762: int
763: _tme_sun2_mmu_reset(struct tme_sun2 *sun2)
764: {
765: struct tme_m68k_tlb *tlb_m68k;
766: struct tme_bus_tlb *tlb, tlb_virtual;
767: unsigned long tlb_i;
768:
769: /* we can only do this initialization once we have both
770: the obmem bus and the CPU's TLBs: */
771: tlb_m68k = sun2->tme_sun2_reset_tlbs;
772: if (tlb_m68k == NULL
773: || sun2->tme_sun2_obmem == NULL) {
774: return (TME_OK);
775: }
776: sun2->tme_sun2_reset_tlbs = NULL;
777: tlb = &tlb_m68k->tme_m68k_tlb_bus_tlb;
778:
779: /* fill the TLB entry: */
780: (*sun2->tme_sun2_obmem->tme_bus_tlb_fill)
781: (sun2->tme_sun2_obmem,
782: tlb,
783: TME_SUN2_PROM_BASE,
784: TME_BUS_CYCLE_READ);
785:
786: /* map the TLB entry: */
787: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb_virtual.tme_bus_tlb_addr_first, 0);
788: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb_virtual.tme_bus_tlb_addr_last, 7);
789: tlb_virtual.tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ;
790: tme_bus_tlb_map(tlb, TME_SUN2_PROM_BASE, &tlb_virtual, 0);
791:
792: /* this TLB entry must allow slow reads from exactly the reset
793: range: */
794: if (!(tlb->tme_bus_tlb_cycles_ok & TME_BUS_CYCLE_READ)
795: || TME_ATOMIC_READ(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first) != 0
796: || TME_ATOMIC_READ(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last) != 7) {
797: abort();
798: }
799:
800: /* take over this TLB entry: */
801: sun2->tme_sun2_reset_cycles = 0;
802: sun2->tme_sun2_reset_cycle_private = tlb->tme_bus_tlb_cycle_private;
803: sun2->tme_sun2_reset_cycle = tlb->tme_bus_tlb_cycle;
804: tlb->tme_bus_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF;
805: tlb->tme_bus_tlb_cycle_private = sun2;
806: tlb->tme_bus_tlb_cycle = _tme_sun2_reset_cycle;
807:
808: /* this TLB entry is usable by the supervisor: */
809: tlb_m68k->tme_m68k_tlb_function_codes_mask = (TME_BIT(TME_M68K_FC_SD)
810: | TME_BIT(TME_M68K_FC_SP));
811:
812: /* now copy this TLB entry into all of the others: */
813: for (tlb_i = sun2->tme_sun2_reset_tlb_count - 1; tlb_i-- > 0; ) {
814: tlb_m68k[1] = tlb_m68k[0];
815: tlb_m68k++;
816: }
817:
818: return (TME_OK);
819: }
820:
821: /* this creates a Sun-2 MMU: */
822: void
823: _tme_sun2_mmu_new(struct tme_sun2 *sun2)
824: {
825: struct tme_sun_mmu_info mmu_info;
826:
827: mmu_info.tme_sun_mmu_info_element = sun2->tme_sun2_element;
828: mmu_info.tme_sun_mmu_info_address_bits = 24;
829: mmu_info.tme_sun_mmu_info_pgoffset_bits = TME_SUN2_PAGE_SIZE_LOG2;
830: mmu_info.tme_sun_mmu_info_pteindex_bits = 4;
831: mmu_info.tme_sun_mmu_info_contexts = 8;
832: mmu_info.tme_sun_mmu_info_pmegs = 256;
833: mmu_info.tme_sun_mmu_info_seginv = 255;
834: mmu_info.tme_sun_mmu_info_tlb_fill_private = sun2;
835: mmu_info.tme_sun_mmu_info_tlb_fill = _tme_sun2_tlb_fill_mmu;
836: mmu_info.tme_sun_mmu_info_proterr_private = sun2;
837: mmu_info.tme_sun_mmu_info_proterr = _tme_sun2_mmu_proterr;
838: mmu_info.tme_sun_mmu_info_invalid_private = sun2;
839: mmu_info.tme_sun_mmu_info_invalid = _tme_sun2_mmu_invalid;
840: sun2->tme_sun2_mmu = tme_sun_mmu_new(&mmu_info);
841: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.