helper.c 15.6 KB
Newer Older
1 2 3
/*
 *  sparc helpers
 * 
B
bellard 已提交
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

B
bellard 已提交
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);
}

B
bellard 已提交
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)
{
B
bellard 已提交
54 55 56 57
    if (rw & 2)
        env->exception_index = TT_TFAULT;
    else
        env->exception_index = TT_DFAULT;
B
bellard 已提交
58 59 60 61
    return 1;
}

#else
62

B
bellard 已提交
63
#ifndef TARGET_SPARC64
B
bellard 已提交
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,
B
bellard 已提交
86
			  int is_user)
87
{
B
bellard 已提交
88 89
    int access_perms = 0;
    target_phys_addr_t pde_ptr;
90 91
    uint32_t pde;
    target_ulong virt_addr;
B
bellard 已提交
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 */
B
bellard 已提交
97 98 99
	*physical = address;
        *prot = PAGE_READ | PAGE_WRITE;
        return 0;
100 101
    }

B
bellard 已提交
102
    *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
B
bellard 已提交
103
    *physical = 0xfffff000;
B
bellard 已提交
104

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

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

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

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

		switch (pde & PTE_ENTRYTYPE_MASK) {
B
bellard 已提交
143
		default:
144
		case 0: /* Invalid */
B
bellard 已提交
145
		    return (3 << 8) | (1 << 2);
146 147
		case 1: /* PDE, should not happen */
		case 3: /* Reserved */
B
bellard 已提交
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 */
B
bellard 已提交
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;
B
bellard 已提交
171
        stl_phys_notdirty(pde_ptr, pde);
172 173 174
    }
    /* check access */
    access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
B
bellard 已提交
175
    error_code = access_table[*access_index][access_perms];
B
bellard 已提交
176
    if (error_code && !(env->mmuregs[0] & MMU_NF))
B
bellard 已提交
177
	return error_code;
178 179

    /* the page can be put in the TLB */
B
bellard 已提交
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])
B
bellard 已提交
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 */
B
bellard 已提交
190
    *physical = ((pde & PTE_ADDR_MASK) << 4) + page_offset;
B
bellard 已提交
191
    return error_code;
B
bellard 已提交
192 193 194
}

/* Perform address translation */
195
int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
B
bellard 已提交
196 197
                              int is_user, int is_softmmu)
{
198 199
    target_ulong virt_addr;
    target_phys_addr_t paddr;
B
bellard 已提交
200 201
    unsigned long vaddr;
    int error_code = 0, prot, ret = 0, access_index;
202

B
bellard 已提交
203 204 205 206 207 208 209
    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));
	ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
	return ret;
    }
210 211 212

    if (env->mmuregs[3]) /* Fault status register */
	env->mmuregs[3] = 1; /* overflow (not read before another fault) */
B
bellard 已提交
213
    env->mmuregs[3] |= (access_index << 5) | error_code | 2;
214 215
    env->mmuregs[4] = address; /* Fault address register */

B
bellard 已提交
216
    if ((env->mmuregs[0] & MMU_NF) || env->psret == 0)  {
B
bellard 已提交
217 218 219 220
        // 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.
B
bellard 已提交
221 222 223 224 225 226 227 228 229 230
	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;
B
bellard 已提交
231
    }
232
}
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

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 */
B
bellard 已提交
334 335 336
/*
 * UltraSparc IIi I/DMMUs
 */
B
bellard 已提交
337 338 339 340 341 342 343 344
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 */
B
bellard 已提交
345
	*physical = address;
B
bellard 已提交
346 347 348 349 350
	*prot = PAGE_READ | PAGE_WRITE;
        return 0;
    }

    for (i = 0; i < 64; i++) {
B
bellard 已提交
351 352 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
	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;
B
bellard 已提交
382
	    }
B
bellard 已提交
383 384 385 386 387
	    *physical = (env->dtlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL);
	    *prot = PAGE_READ;
	    if (env->dtlb_tte[i] & 0x2)
		*prot |= PAGE_WRITE;
	    return 0;
B
bellard 已提交
388 389
	}
    }
B
bellard 已提交
390 391 392 393
#ifdef DEBUG_MMU
    printf("DMISS at 0x%llx\n", address);
#endif
    env->exception_index = TT_DMISS;
B
bellard 已提交
394 395 396 397 398 399 400 401 402 403 404
    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 */
B
bellard 已提交
405
	*physical = address;
B
bellard 已提交
406 407 408
	*prot = PAGE_READ;
        return 0;
    }
B
bellard 已提交
409

B
bellard 已提交
410
    for (i = 0; i < 64; i++) {
B
bellard 已提交
411 412 413 414 415 416 417 418 419 420 421 422 423
	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;
B
bellard 已提交
424
		break;
B
bellard 已提交
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
	}
	// 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;
B
bellard 已提交
440
	    }
B
bellard 已提交
441 442 443
	    *physical = (env->itlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL);
	    *prot = PAGE_READ;
	    return 0;
B
bellard 已提交
444 445
	}
    }
B
bellard 已提交
446 447 448 449
#ifdef DEBUG_MMU
    printf("TMISS at 0x%llx\n", address);
#endif
    env->exception_index = TT_TMISS;
B
bellard 已提交
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
    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)
{
B
bellard 已提交
467
    target_ulong virt_addr, vaddr;
B
bellard 已提交
468 469 470 471 472 473 474
    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));
B
bellard 已提交
475 476 477
#ifdef DEBUG_MMU
	printf("Translate at 0x%llx -> 0x%llx, vaddr 0x%llx\n", address, paddr, vaddr);
#endif
B
bellard 已提交
478 479 480 481 482 483 484
	ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
	return ret;
    }
    // XXX
    return 1;
}

B
bellard 已提交
485 486 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
#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);
	    }
	}
    }
}
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
#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];
}