helper.c 15.6 KB
Newer Older
1 2 3
/*
 *  sparc helpers
 * 
bellard's avatar
bellard committed
4
 *  Copyright (c) 2003-2005 Fabrice Bellard
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
20 21 22 23 24 25 26 27 28 29
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <signal.h>
#include <assert.h>

#include "cpu.h"
#include "exec-all.h"
30

bellard's avatar
bellard committed
31
//#define DEBUG_MMU
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48

/* Sparc MMU emulation */

/* thread support */

spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;

void cpu_lock(void)
{
    spin_lock(&global_cpu_lock);
}

void cpu_unlock(void)
{
    spin_unlock(&global_cpu_lock);
}

bellard's avatar
bellard committed
49 50 51 52 53
#if defined(CONFIG_USER_ONLY) 

int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
                               int is_user, int is_softmmu)
{
bellard's avatar
bellard committed
54 55 56 57
    if (rw & 2)
        env->exception_index = TT_TFAULT;
    else
        env->exception_index = TT_DFAULT;
bellard's avatar
bellard committed
58 59 60 61
    return 1;
}

#else
62

bellard's avatar
bellard committed
63
#ifndef TARGET_SPARC64
bellard's avatar
bellard committed
64 65 66
/*
 * Sparc V8 Reference MMU (SRMMU)
 */
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
static const int access_table[8][8] = {
    { 0, 0, 0, 0, 2, 0, 3, 3 },
    { 0, 0, 0, 0, 2, 0, 0, 0 },
    { 2, 2, 0, 0, 0, 2, 3, 3 },
    { 2, 2, 0, 0, 0, 2, 0, 0 },
    { 2, 0, 2, 0, 2, 2, 3, 3 },
    { 2, 0, 2, 0, 2, 0, 2, 0 },
    { 2, 2, 2, 0, 2, 2, 3, 3 },
    { 2, 2, 2, 0, 2, 2, 2, 0 }
};

/* 1 = write OK */
static const int rw_table[2][8] = {
    { 0, 1, 0, 1, 0, 1, 0, 1 },
    { 0, 1, 0, 1, 0, 0, 0, 0 }
};

84 85
int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot,
			  int *access_index, target_ulong address, int rw,
bellard's avatar
bellard committed
86
			  int is_user)
87
{
bellard's avatar
bellard committed
88 89
    int access_perms = 0;
    target_phys_addr_t pde_ptr;
90 91
    uint32_t pde;
    target_ulong virt_addr;
bellard's avatar
bellard committed
92 93
    int error_code = 0, is_dirty;
    unsigned long page_offset;
94 95 96

    virt_addr = address & TARGET_PAGE_MASK;
    if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
bellard's avatar
bellard committed
97 98 99
	*physical = address;
        *prot = PAGE_READ | PAGE_WRITE;
        return 0;
100 101
    }

bellard's avatar
bellard committed
102
    *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
bellard's avatar
bellard committed
103
    *physical = 0xfffff000;
bellard's avatar
bellard committed
104

105 106
    /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
    /* Context base + context number */
bellard's avatar
bellard committed
107
    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
bellard's avatar
bellard committed
108
    pde = ldl_phys(pde_ptr);
109 110 111

    /* Ctx pde */
    switch (pde & PTE_ENTRYTYPE_MASK) {
bellard's avatar
bellard committed
112
    default:
113
    case 0: /* Invalid */
bellard's avatar
bellard committed
114
	return 1 << 2;
bellard's avatar
bellard committed
115
    case 2: /* L0 PTE, maybe should not happen? */
116
    case 3: /* Reserved */
bellard's avatar
bellard committed
117
        return 4 << 2;
bellard's avatar
bellard committed
118 119
    case 1: /* L0 PDE */
	pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
bellard's avatar
bellard committed
120
        pde = ldl_phys(pde_ptr);
121 122

	switch (pde & PTE_ENTRYTYPE_MASK) {
bellard's avatar
bellard committed
123
	default:
124
	case 0: /* Invalid */
bellard's avatar
bellard committed
125
	    return (1 << 8) | (1 << 2);
126
	case 3: /* Reserved */
bellard's avatar
bellard committed
127
	    return (1 << 8) | (4 << 2);
bellard's avatar
bellard committed
128 129
	case 1: /* L1 PDE */
	    pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
bellard's avatar
bellard committed
130
            pde = ldl_phys(pde_ptr);
131 132

	    switch (pde & PTE_ENTRYTYPE_MASK) {
bellard's avatar
bellard committed
133
	    default:
134
	    case 0: /* Invalid */
bellard's avatar
bellard committed
135
		return (2 << 8) | (1 << 2);
136
	    case 3: /* Reserved */
bellard's avatar
bellard committed
137
		return (2 << 8) | (4 << 2);
bellard's avatar
bellard committed
138 139
	    case 1: /* L2 PDE */
		pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
bellard's avatar
bellard committed
140
                pde = ldl_phys(pde_ptr);
141 142

		switch (pde & PTE_ENTRYTYPE_MASK) {
bellard's avatar
bellard committed
143
		default:
144
		case 0: /* Invalid */
bellard's avatar
bellard committed
145
		    return (3 << 8) | (1 << 2);
146 147
		case 1: /* PDE, should not happen */
		case 3: /* Reserved */
bellard's avatar
bellard committed
148
		    return (3 << 8) | (4 << 2);
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
		case 2: /* L3 PTE */
		    virt_addr = address & TARGET_PAGE_MASK;
		    page_offset = (address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1);
		}
		break;
	    case 2: /* L2 PTE */
		virt_addr = address & ~0x3ffff;
		page_offset = address & 0x3ffff;
	    }
	    break;
	case 2: /* L1 PTE */
	    virt_addr = address & ~0xffffff;
	    page_offset = address & 0xffffff;
	}
    }

    /* update page modified and dirty bits */
bellard's avatar
bellard committed
166
    is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
167 168 169 170
    if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
	pde |= PG_ACCESSED_MASK;
	if (is_dirty)
	    pde |= PG_MODIFIED_MASK;
bellard's avatar
bellard committed
171
        stl_phys_notdirty(pde_ptr, pde);
172 173 174
    }
    /* check access */
    access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
bellard's avatar
bellard committed
175
    error_code = access_table[*access_index][access_perms];
bellard's avatar
bellard committed
176
    if (error_code && !(env->mmuregs[0] & MMU_NF))
bellard's avatar
bellard committed
177
	return error_code;
178 179

    /* the page can be put in the TLB */
bellard's avatar
bellard committed
180
    *prot = PAGE_READ;
181 182 183 184
    if (pde & PG_MODIFIED_MASK) {
        /* only set write access if already dirty... otherwise wait
           for dirty access */
	if (rw_table[is_user][access_perms])
bellard's avatar
bellard committed
185
	        *prot |= PAGE_WRITE;
186 187 188 189
    }

    /* Even if large ptes, we map only one 4KB page in the cache to
       avoid filling it too fast */
bellard's avatar
bellard committed
190
    *physical = ((pde & PTE_ADDR_MASK) << 4) + page_offset;
bellard's avatar
bellard committed
191
    return error_code;
bellard's avatar
bellard committed
192 193 194
}

/* Perform address translation */
195
int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
bellard's avatar
bellard committed
196 197
                              int is_user, int is_softmmu)
{
198
    target_phys_addr_t paddr;
bellard's avatar
bellard committed
199 200
    unsigned long vaddr;
    int error_code = 0, prot, ret = 0, access_index;
201

bellard's avatar
bellard committed
202 203
    error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user);
    if (error_code == 0) {
bellard's avatar
bellard committed
204 205 206 207 208
	vaddr = address & TARGET_PAGE_MASK;
	paddr &= TARGET_PAGE_MASK;
#ifdef DEBUG_MMU
	printf("Translate at 0x%lx -> 0x%lx, vaddr 0x%lx\n", (long)address, (long)paddr, (long)vaddr);
#endif
bellard's avatar
bellard committed
209 210 211
	ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
	return ret;
    }
212 213 214

    if (env->mmuregs[3]) /* Fault status register */
	env->mmuregs[3] = 1; /* overflow (not read before another fault) */
bellard's avatar
bellard committed
215
    env->mmuregs[3] |= (access_index << 5) | error_code | 2;
216 217
    env->mmuregs[4] = address; /* Fault address register */

bellard's avatar
bellard committed
218
    if ((env->mmuregs[0] & MMU_NF) || env->psret == 0)  {
bellard's avatar
bellard committed
219 220 221 222
        // No fault mode: if a mapping is available, just override
        // permissions. If no mapping is available, redirect accesses to
        // neverland. Fake/overridden mappings will be flushed when
        // switching to normal mode.
bellard's avatar
bellard committed
223 224 225 226 227 228 229 230 231 232
	vaddr = address & TARGET_PAGE_MASK;
        prot = PAGE_READ | PAGE_WRITE;
        ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
	return ret;
    } else {
        if (rw & 2)
            env->exception_index = TT_TFAULT;
        else
            env->exception_index = TT_DFAULT;
        return 1;
bellard's avatar
bellard committed
233
    }
234
}
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335

target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
{
    target_phys_addr_t pde_ptr;
    uint32_t pde;

    /* Context base + context number */
    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
    pde = ldl_phys(pde_ptr);

    switch (pde & PTE_ENTRYTYPE_MASK) {
    default:
    case 0: /* Invalid */
    case 2: /* PTE, maybe should not happen? */
    case 3: /* Reserved */
	return 0;
    case 1: /* L1 PDE */
	if (mmulev == 3)
	    return pde;
	pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
        pde = ldl_phys(pde_ptr);

	switch (pde & PTE_ENTRYTYPE_MASK) {
	default:
	case 0: /* Invalid */
	case 3: /* Reserved */
	    return 0;
	case 2: /* L1 PTE */
	    return pde;
	case 1: /* L2 PDE */
	    if (mmulev == 2)
		return pde;
	    pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
            pde = ldl_phys(pde_ptr);

	    switch (pde & PTE_ENTRYTYPE_MASK) {
	    default:
	    case 0: /* Invalid */
	    case 3: /* Reserved */
		return 0;
	    case 2: /* L2 PTE */
		return pde;
	    case 1: /* L3 PDE */
		if (mmulev == 1)
		    return pde;
		pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
                pde = ldl_phys(pde_ptr);

		switch (pde & PTE_ENTRYTYPE_MASK) {
		default:
		case 0: /* Invalid */
		case 1: /* PDE, should not happen */
		case 3: /* Reserved */
		    return 0;
		case 2: /* L3 PTE */
		    return pde;
		}
	    }
	}
    }
    return 0;
}

#ifdef DEBUG_MMU
void dump_mmu(CPUState *env)
{
     target_ulong va, va1, va2;
     unsigned int n, m, o;
     target_phys_addr_t pde_ptr, pa;
    uint32_t pde;

    printf("MMU dump:\n");
    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
    pde = ldl_phys(pde_ptr);
    printf("Root ptr: " TARGET_FMT_lx ", ctx: %d\n", env->mmuregs[1] << 4, env->mmuregs[2]);
    for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
	pde_ptr = mmu_probe(env, va, 2);
	if (pde_ptr) {
	    pa = cpu_get_phys_page_debug(env, va);
 	    printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PDE: " TARGET_FMT_lx "\n", va, pa, pde_ptr);
	    for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
		pde_ptr = mmu_probe(env, va1, 1);
		if (pde_ptr) {
		    pa = cpu_get_phys_page_debug(env, va1);
 		    printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PDE: " TARGET_FMT_lx "\n", va1, pa, pde_ptr);
		    for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
			pde_ptr = mmu_probe(env, va2, 0);
			if (pde_ptr) {
			    pa = cpu_get_phys_page_debug(env, va2);
 			    printf("  VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PTE: " TARGET_FMT_lx "\n", va2, pa, pde_ptr);
			}
		    }
		}
	    }
	}
    }
    printf("MMU dump ends\n");
}
#endif /* DEBUG_MMU */

#else /* !TARGET_SPARC64 */
bellard's avatar
bellard committed
336 337 338
/*
 * UltraSparc IIi I/DMMUs
 */
bellard's avatar
bellard committed
339 340 341 342 343 344 345 346
static int get_physical_address_data(CPUState *env, target_phys_addr_t *physical, int *prot,
			  int *access_index, target_ulong address, int rw,
			  int is_user)
{
    target_ulong mask;
    unsigned int i;

    if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
bellard's avatar
bellard committed
347
	*physical = address;
bellard's avatar
bellard committed
348 349 350 351 352
	*prot = PAGE_READ | PAGE_WRITE;
        return 0;
    }

    for (i = 0; i < 64; i++) {
bellard's avatar
bellard committed
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
	switch ((env->dtlb_tte[i] >> 61) & 3) {
	default:
	case 0x0: // 8k
	    mask = 0xffffffffffffe000ULL;
	    break;
	case 0x1: // 64k
	    mask = 0xffffffffffff0000ULL;
	    break;
	case 0x2: // 512k
	    mask = 0xfffffffffff80000ULL;
	    break;
	case 0x3: // 4M
	    mask = 0xffffffffffc00000ULL;
	    break;
	}
	// ctx match, vaddr match?
	if (env->dmmuregs[1] == (env->dtlb_tag[i] & 0x1fff) &&
	    (address & mask) == (env->dtlb_tag[i] & ~0x1fffULL)) {
	    // valid, access ok?
	    if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0 ||
		((env->dtlb_tte[i] & 0x4) && is_user) ||
		(!(env->dtlb_tte[i] & 0x2) && (rw == 1))) {
		if (env->dmmuregs[3]) /* Fault status register */
		    env->dmmuregs[3] = 2; /* overflow (not read before another fault) */
		env->dmmuregs[3] |= (is_user << 3) | ((rw == 1) << 2) | 1;
		env->dmmuregs[4] = address; /* Fault address register */
		env->exception_index = TT_DFAULT;
#ifdef DEBUG_MMU
		printf("DFAULT at 0x%llx\n", address);
#endif
		return 1;
bellard's avatar
bellard committed
384
	    }
bellard's avatar
bellard committed
385 386 387 388 389
	    *physical = (env->dtlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL);
	    *prot = PAGE_READ;
	    if (env->dtlb_tte[i] & 0x2)
		*prot |= PAGE_WRITE;
	    return 0;
bellard's avatar
bellard committed
390 391
	}
    }
bellard's avatar
bellard committed
392 393 394 395
#ifdef DEBUG_MMU
    printf("DMISS at 0x%llx\n", address);
#endif
    env->exception_index = TT_DMISS;
bellard's avatar
bellard committed
396 397 398 399 400 401 402 403 404 405 406
    return 1;
}

static int get_physical_address_code(CPUState *env, target_phys_addr_t *physical, int *prot,
			  int *access_index, target_ulong address, int rw,
			  int is_user)
{
    target_ulong mask;
    unsigned int i;

    if ((env->lsu & IMMU_E) == 0) { /* IMMU disabled */
bellard's avatar
bellard committed
407
	*physical = address;
bellard's avatar
bellard committed
408 409 410
	*prot = PAGE_READ;
        return 0;
    }
bellard's avatar
bellard committed
411

bellard's avatar
bellard committed
412
    for (i = 0; i < 64; i++) {
bellard's avatar
bellard committed
413 414 415 416 417 418 419 420 421 422 423 424 425
	switch ((env->itlb_tte[i] >> 61) & 3) {
	default:
	case 0x0: // 8k
	    mask = 0xffffffffffffe000ULL;
	    break;
	case 0x1: // 64k
	    mask = 0xffffffffffff0000ULL;
	    break;
	case 0x2: // 512k
	    mask = 0xfffffffffff80000ULL;
	    break;
	case 0x3: // 4M
	    mask = 0xffffffffffc00000ULL;
bellard's avatar
bellard committed
426
		break;
bellard's avatar
bellard committed
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
	}
	// ctx match, vaddr match?
	if (env->dmmuregs[1] == (env->itlb_tag[i] & 0x1fff) &&
	    (address & mask) == (env->itlb_tag[i] & ~0x1fffULL)) {
	    // valid, access ok?
	    if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0 ||
		((env->itlb_tte[i] & 0x4) && is_user)) {
		if (env->immuregs[3]) /* Fault status register */
		    env->immuregs[3] = 2; /* overflow (not read before another fault) */
		env->immuregs[3] |= (is_user << 3) | 1;
		env->exception_index = TT_TFAULT;
#ifdef DEBUG_MMU
		printf("TFAULT at 0x%llx\n", address);
#endif
		return 1;
bellard's avatar
bellard committed
442
	    }
bellard's avatar
bellard committed
443 444 445
	    *physical = (env->itlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL);
	    *prot = PAGE_READ;
	    return 0;
bellard's avatar
bellard committed
446 447
	}
    }
bellard's avatar
bellard committed
448 449 450 451
#ifdef DEBUG_MMU
    printf("TMISS at 0x%llx\n", address);
#endif
    env->exception_index = TT_TMISS;
bellard's avatar
bellard committed
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
    return 1;
}

int get_physical_address(CPUState *env, target_phys_addr_t *physical, int *prot,
			  int *access_index, target_ulong address, int rw,
			  int is_user)
{
    if (rw == 2)
	return get_physical_address_code(env, physical, prot, access_index, address, rw, is_user);
    else
	return get_physical_address_data(env, physical, prot, access_index, address, rw, is_user);
}

/* Perform address translation */
int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                              int is_user, int is_softmmu)
{
bellard's avatar
bellard committed
469
    target_ulong virt_addr, vaddr;
bellard's avatar
bellard committed
470 471 472 473 474 475 476
    target_phys_addr_t paddr;
    int error_code = 0, prot, ret = 0, access_index;

    error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user);
    if (error_code == 0) {
	virt_addr = address & TARGET_PAGE_MASK;
	vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1));
bellard's avatar
bellard committed
477 478 479
#ifdef DEBUG_MMU
	printf("Translate at 0x%llx -> 0x%llx, vaddr 0x%llx\n", address, paddr, vaddr);
#endif
bellard's avatar
bellard committed
480 481 482 483 484 485 486
	ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
	return ret;
    }
    // XXX
    return 1;
}

bellard's avatar
bellard committed
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
#ifdef DEBUG_MMU
void dump_mmu(CPUState *env)
{
    unsigned int i;
    const char *mask;

    printf("MMU contexts: Primary: %lld, Secondary: %lld\n", env->dmmuregs[1], env->dmmuregs[2]);
    if ((env->lsu & DMMU_E) == 0) {
	printf("DMMU disabled\n");
    } else {
	printf("DMMU dump:\n");
	for (i = 0; i < 64; i++) {
	    switch ((env->dtlb_tte[i] >> 61) & 3) {
	    default:
	    case 0x0:
		mask = "  8k";
		break;
	    case 0x1:
		mask = " 64k";
		break;
	    case 0x2:
		mask = "512k";
		break;
	    case 0x3:
		mask = "  4M";
		break;
	    }
	    if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) {
		printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, %s, ctx %lld\n",
		       env->dtlb_tag[i] & ~0x1fffULL,
		       env->dtlb_tte[i] & 0x1ffffffe000ULL,
		       mask,
		       env->dtlb_tte[i] & 0x4? "priv": "user",
		       env->dtlb_tte[i] & 0x2? "RW": "RO",
		       env->dtlb_tte[i] & 0x40? "locked": "unlocked",
		       env->dtlb_tag[i] & 0x1fffULL);
	    }
	}
    }
    if ((env->lsu & IMMU_E) == 0) {
	printf("IMMU disabled\n");
    } else {
	printf("IMMU dump:\n");
	for (i = 0; i < 64; i++) {
	    switch ((env->itlb_tte[i] >> 61) & 3) {
	    default:
	    case 0x0:
		mask = "  8k";
		break;
	    case 0x1:
		mask = " 64k";
		break;
	    case 0x2:
		mask = "512k";
		break;
	    case 0x3:
		mask = "  4M";
		break;
	    }
	    if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) {
		printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, ctx %lld\n",
		       env->itlb_tag[i] & ~0x1fffULL,
		       env->itlb_tte[i] & 0x1ffffffe000ULL,
		       mask,
		       env->itlb_tte[i] & 0x4? "priv": "user",
		       env->itlb_tte[i] & 0x40? "locked": "unlocked",
		       env->itlb_tag[i] & 0x1fffULL);
	    }
	}
    }
}
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573
#endif /* DEBUG_MMU */

#endif /* TARGET_SPARC64 */
#endif /* !CONFIG_USER_ONLY */

void memcpy32(target_ulong *dst, const target_ulong *src)
{
    dst[0] = src[0];
    dst[1] = src[1];
    dst[2] = src[2];
    dst[3] = src[3];
    dst[4] = src[4];
    dst[5] = src[5];
    dst[6] = src[6];
    dst[7] = src[7];
}