helper.c 17 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 *  sparc helpers
 * 
 *  Copyright (c) 2003 Fabrice Bellard
 *
 * 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
 */
#include "exec.h"

bellard's avatar
bellard committed
22 23
//#define DEBUG_PCALL
//#define DEBUG_MMU
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40

/* 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
41 42 43 44 45
#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
46 47 48 49
    if (rw & 2)
        env->exception_index = TT_TFAULT;
    else
        env->exception_index = TT_DFAULT;
bellard's avatar
bellard committed
50 51 52 53
    return 1;
}

#else
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74

#define MMUSUFFIX _mmu
#define GETPC() (__builtin_return_address(0))

#define SHIFT 0
#include "softmmu_template.h"

#define SHIFT 1
#include "softmmu_template.h"

#define SHIFT 2
#include "softmmu_template.h"

#define SHIFT 3
#include "softmmu_template.h"


/* try to fill the TLB and return an exception if error. If retaddr is
   NULL, it means that the function was called in C code (i.e. not
   from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
bellard's avatar
bellard committed
75
void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr)
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
{
    TranslationBlock *tb;
    int ret;
    unsigned long pc;
    CPUState *saved_env;

    /* XXX: hack to restore env in all cases, even if not called from
       generated code */
    saved_env = env;
    env = cpu_single_env;

    ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, is_user, 1);
    if (ret) {
        if (retaddr) {
            /* now we have a real cpu fault */
            pc = (unsigned long)retaddr;
            tb = tb_find_pc(pc);
            if (tb) {
                /* the PC is inside the translated code. It means that we have
                   a virtual CPU fault */
96
                cpu_restore_state(tb, env, pc, (void *)T2);
97 98
            }
        }
bellard's avatar
bellard committed
99
        cpu_loop_exit();
100 101 102 103
    }
    env = saved_env;
}

bellard's avatar
bellard committed
104
#ifndef TARGET_SPARC64
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
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 }
};

122 123
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
124
			  int is_user)
125
{
bellard's avatar
bellard committed
126 127
    int access_perms = 0;
    target_phys_addr_t pde_ptr;
128 129
    uint32_t pde;
    target_ulong virt_addr;
bellard's avatar
bellard committed
130 131
    int error_code = 0, is_dirty;
    unsigned long page_offset;
132 133 134

    virt_addr = address & TARGET_PAGE_MASK;
    if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
bellard's avatar
bellard committed
135 136 137
	*physical = address;
        *prot = PAGE_READ | PAGE_WRITE;
        return 0;
138 139
    }

bellard's avatar
bellard committed
140
    *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
bellard's avatar
bellard committed
141
    *physical = 0xfffff000;
bellard's avatar
bellard committed
142

143 144
    /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
    /* Context base + context number */
bellard's avatar
bellard committed
145
    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
bellard's avatar
bellard committed
146
    pde = ldl_phys(pde_ptr);
147 148 149

    /* Ctx pde */
    switch (pde & PTE_ENTRYTYPE_MASK) {
bellard's avatar
bellard committed
150
    default:
151
    case 0: /* Invalid */
bellard's avatar
bellard committed
152
	return 1 << 2;
bellard's avatar
bellard committed
153
    case 2: /* L0 PTE, maybe should not happen? */
154
    case 3: /* Reserved */
bellard's avatar
bellard committed
155
        return 4 << 2;
bellard's avatar
bellard committed
156 157
    case 1: /* L0 PDE */
	pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
bellard's avatar
bellard committed
158
        pde = ldl_phys(pde_ptr);
159 160

	switch (pde & PTE_ENTRYTYPE_MASK) {
bellard's avatar
bellard committed
161
	default:
162
	case 0: /* Invalid */
bellard's avatar
bellard committed
163
	    return (1 << 8) | (1 << 2);
164
	case 3: /* Reserved */
bellard's avatar
bellard committed
165
	    return (1 << 8) | (4 << 2);
bellard's avatar
bellard committed
166 167
	case 1: /* L1 PDE */
	    pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
bellard's avatar
bellard committed
168
            pde = ldl_phys(pde_ptr);
169 170

	    switch (pde & PTE_ENTRYTYPE_MASK) {
bellard's avatar
bellard committed
171
	    default:
172
	    case 0: /* Invalid */
bellard's avatar
bellard committed
173
		return (2 << 8) | (1 << 2);
174
	    case 3: /* Reserved */
bellard's avatar
bellard committed
175
		return (2 << 8) | (4 << 2);
bellard's avatar
bellard committed
176 177
	    case 1: /* L2 PDE */
		pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
bellard's avatar
bellard committed
178
                pde = ldl_phys(pde_ptr);
179 180

		switch (pde & PTE_ENTRYTYPE_MASK) {
bellard's avatar
bellard committed
181
		default:
182
		case 0: /* Invalid */
bellard's avatar
bellard committed
183
		    return (3 << 8) | (1 << 2);
184 185
		case 1: /* PDE, should not happen */
		case 3: /* Reserved */
bellard's avatar
bellard committed
186
		    return (3 << 8) | (4 << 2);
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
		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
204
    is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
205 206 207 208
    if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
	pde |= PG_ACCESSED_MASK;
	if (is_dirty)
	    pde |= PG_MODIFIED_MASK;
bellard's avatar
bellard committed
209
        stl_phys_notdirty(pde_ptr, pde);
210 211 212
    }
    /* check access */
    access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
bellard's avatar
bellard committed
213
    error_code = access_table[*access_index][access_perms];
bellard's avatar
bellard committed
214
    if (error_code && !(env->mmuregs[0] & MMU_NF))
bellard's avatar
bellard committed
215
	return error_code;
216 217

    /* the page can be put in the TLB */
bellard's avatar
bellard committed
218
    *prot = PAGE_READ;
219 220 221 222
    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
223
	        *prot |= PAGE_WRITE;
224 225 226 227
    }

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

/* Perform address translation */
233
int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
bellard's avatar
bellard committed
234 235
                              int is_user, int is_softmmu)
{
236 237
    target_ulong virt_addr;
    target_phys_addr_t paddr;
bellard's avatar
bellard committed
238 239
    unsigned long vaddr;
    int error_code = 0, prot, ret = 0, access_index;
240

bellard's avatar
bellard committed
241 242 243 244 245 246 247
    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;
    }
248 249 250

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

bellard's avatar
bellard committed
254
    if ((env->mmuregs[0] & MMU_NF) || env->psret == 0)  {
bellard's avatar
bellard committed
255 256 257 258
        // 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
259 260 261 262 263 264 265 266 267 268
	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
269
    }
270
}
bellard's avatar
bellard committed
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 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 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 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
#else
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 */
	*physical = address & 0xffffffff;
	*prot = PAGE_READ | PAGE_WRITE;
        return 0;
    }

    for (i = 0; i < 64; i++) {
	if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) {
	    switch (env->dtlb_tte[i] >> 60) {
	    default:
	    case 0x4: // 8k
		mask = 0xffffffffffffe000ULL;
		break;
	    case 0x5: // 64k
		mask = 0xffffffffffff0000ULL;
		break;
	    case 0x6: // 512k
		mask = 0xfffffffffff80000ULL;
		break;
	    case 0x7: // 4M
		mask = 0xffffffffffc00000ULL;
		break;
	    }
	    // ctx match, vaddr match?
	    if (env->dmmuregs[1] == (env->dtlb_tag[i] & 0x1fff) &&
		(address & mask) == (env->dtlb_tag[i] & ~0x1fffULL)) {
		// access ok?
		if (((env->dtlb_tte[i] & 0x4) && !(env->pstate & PS_PRIV)) ||
		    (!(env->dtlb_tte[i] & 0x2) && (rw == 1))) {
		    env->exception_index = TT_DFAULT;
		    return 1;
		}
		*physical = env->dtlb_tte[i] & 0xffffe000;
		*prot = PAGE_READ;
		if (env->dtlb_tte[i] & 0x2)
		    *prot |= PAGE_WRITE;
		return 0;
	    }
	}
    }
    env->exception_index = TT_DFAULT;
    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 */
	*physical = address & 0xffffffff;
	*prot = PAGE_READ;
        return 0;
    }
    for (i = 0; i < 64; i++) {
	if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) {
	    switch (env->itlb_tte[i] >> 60) {
	    default:
	    case 0x4: // 8k
		mask = 0xffffffffffffe000ULL;
		break;
	    case 0x5: // 64k
		mask = 0xffffffffffff0000ULL;
		break;
	    case 0x6: // 512k
		mask = 0xfffffffffff80000ULL;
		break;
	    case 0x7: // 4M
		mask = 0xffffffffffc00000ULL;
		break;
	    }
	    // ctx match, vaddr match?
	    if (env->immuregs[1] == (env->itlb_tag[i] & 0x1fff) &&
		(address & mask) == (env->itlb_tag[i] & ~0x1fffULL)) {
		// access ok?
		if ((env->itlb_tte[i] & 0x4) && !(env->pstate & PS_PRIV)) {
		    env->exception_index = TT_TFAULT;
		    return 1;
		}
		*physical = env->itlb_tte[i] & 0xffffe000;
		*prot = PAGE_READ;
		return 0;
	    }
	}
    }
    env->exception_index = TT_TFAULT;
    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)
{
    target_ulong virt_addr;
    target_phys_addr_t paddr;
    unsigned long vaddr;
    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));
	ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
	return ret;
    }
    // XXX
    return 1;
}

#endif
bellard's avatar
bellard committed
401
#endif
402

403
void memcpy32(target_ulong *dst, const target_ulong *src)
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424
{
    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];
}

void set_cwp(int new_cwp)
{
    /* put the modified wrap registers at their proper location */
    if (env->cwp == (NWINDOWS - 1))
        memcpy32(env->regbase, env->regbase + NWINDOWS * 16);
    env->cwp = new_cwp;
    /* put the wrap registers at their temporary location */
    if (new_cwp == (NWINDOWS - 1))
        memcpy32(env->regbase + NWINDOWS * 16, env->regbase);
    env->regwptr = env->regbase + (new_cwp * 16);
bellard's avatar
bellard committed
425
    REGWPTR = env->regwptr;
426 427
}

bellard's avatar
bellard committed
428 429 430
void cpu_set_cwp(CPUState *env1, int new_cwp)
{
    CPUState *saved_env;
bellard's avatar
bellard committed
431 432 433 434
#ifdef reg_REGWPTR
    target_ulong *saved_regwptr;
#endif

bellard's avatar
bellard committed
435
    saved_env = env;
bellard's avatar
bellard committed
436 437 438
#ifdef reg_REGWPTR
    saved_regwptr = REGWPTR;
#endif
bellard's avatar
bellard committed
439 440 441
    env = env1;
    set_cwp(new_cwp);
    env = saved_env;
bellard's avatar
bellard committed
442 443 444
#ifdef reg_REGWPTR
    REGWPTR = saved_regwptr;
#endif
bellard's avatar
bellard committed
445 446
}

bellard's avatar
bellard committed
447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
#ifdef TARGET_SPARC64
void do_interrupt(int intno)
{
#ifdef DEBUG_PCALL
    if (loglevel & CPU_LOG_INT) {
	static int count;
	fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n",
                count, intno,
                env->pc,
                env->npc, env->regwptr[6]);
	cpu_dump_state(env, logfile, fprintf, 0);
#if 0
	{
	    int i;
	    uint8_t *ptr;

	    fprintf(logfile, "       code=");
	    ptr = (uint8_t *)env->pc;
	    for(i = 0; i < 16; i++) {
		fprintf(logfile, " %02x", ldub(ptr + i));
	    }
	    fprintf(logfile, "\n");
	}
#endif
	count++;
    }
#endif
#if !defined(CONFIG_USER_ONLY) 
    if (env->pstate & PS_IE) {
        cpu_abort(cpu_single_env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index);
	return;
    }
#endif
    env->tstate[env->tl] = ((uint64_t)GET_CCR(env) << 32) | ((env->asi & 0xff) << 24) |
	((env->pstate & 0xfff) << 8) | (env->cwp & 0xff);
    env->tpc[env->tl] = env->pc;
    env->tnpc[env->tl] = env->npc;
    env->tt[env->tl] = intno;
    env->tbr = env->tbr | (env->tl > 1) ? 1 << 14 : 0 | (intno << 4);
    env->tl++;
    env->pc = env->tbr;
    env->npc = env->pc + 4;
    env->exception_index = 0;
}
#else
bellard's avatar
bellard committed
492
void do_interrupt(int intno)
493 494 495 496 497 498
{
    int cwp;

#ifdef DEBUG_PCALL
    if (loglevel & CPU_LOG_INT) {
	static int count;
bellard's avatar
bellard committed
499 500
	fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n",
                count, intno,
bellard's avatar
bellard committed
501 502
                env->pc,
                env->npc, env->regwptr[6]);
bellard's avatar
bellard committed
503
	cpu_dump_state(env, logfile, fprintf, 0);
bellard's avatar
bellard committed
504
#if 0
505 506 507
	{
	    int i;
	    uint8_t *ptr;
bellard's avatar
bellard committed
508

509
	    fprintf(logfile, "       code=");
bellard's avatar
bellard committed
510
	    ptr = (uint8_t *)env->pc;
511 512 513 514 515 516 517 518
	    for(i = 0; i < 16; i++) {
		fprintf(logfile, " %02x", ldub(ptr + i));
	    }
	    fprintf(logfile, "\n");
	}
#endif
	count++;
    }
bellard's avatar
bellard committed
519 520 521
#endif
#if !defined(CONFIG_USER_ONLY) 
    if (env->psret == 0) {
bellard's avatar
bellard committed
522
        cpu_abort(cpu_single_env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index);
bellard's avatar
bellard committed
523 524
	return;
    }
525 526 527 528
#endif
    env->psret = 0;
    cwp = (env->cwp - 1) & (NWINDOWS - 1); 
    set_cwp(cwp);
bellard's avatar
bellard committed
529 530
    env->regwptr[9] = env->pc;
    env->regwptr[10] = env->npc;
531 532 533 534 535 536 537 538
    env->psrps = env->psrs;
    env->psrs = 1;
    env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
    env->pc = env->tbr;
    env->npc = env->pc + 4;
    env->exception_index = 0;
}

539
target_ulong mmu_probe(target_ulong address, int mmulev)
bellard's avatar
bellard committed
540 541 542 543 544
{
    target_phys_addr_t pde_ptr;
    uint32_t pde;

    /* Context base + context number */
bellard's avatar
bellard committed
545
    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
bellard's avatar
bellard committed
546 547
    pde = ldl_phys(pde_ptr);

bellard's avatar
bellard committed
548 549 550 551 552 553 554 555 556 557
    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);
bellard's avatar
bellard committed
558
        pde = ldl_phys(pde_ptr);
bellard's avatar
bellard committed
559 560 561 562 563 564 565 566 567 568 569 570

	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);
bellard's avatar
bellard committed
571
            pde = ldl_phys(pde_ptr);
bellard's avatar
bellard committed
572 573 574 575 576 577 578 579 580 581 582 583

	    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);
bellard's avatar
bellard committed
584
                pde = ldl_phys(pde_ptr);
bellard's avatar
bellard committed
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600

		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;
}

bellard's avatar
bellard committed
601
#ifdef DEBUG_MMU
bellard's avatar
bellard committed
602 603
void dump_mmu(void)
{
604 605 606
     target_ulong va, va1, va2;
     unsigned int n, m, o;
     target_phys_addr_t pde_ptr, pa;
bellard's avatar
bellard committed
607 608 609
    uint32_t pde;

    printf("MMU dump:\n");
bellard's avatar
bellard committed
610
    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
bellard's avatar
bellard committed
611
    pde = ldl_phys(pde_ptr);
612
    printf("Root ptr: " TARGET_FMT_lx ", ctx: %d\n", env->mmuregs[1] << 4, env->mmuregs[2]);
bellard's avatar
bellard committed
613 614 615 616
    for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
	pde_ptr = mmu_probe(va, 2);
	if (pde_ptr) {
	    pa = cpu_get_phys_page_debug(env, va);
617
 	    printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PDE: " TARGET_FMT_lx "\n", va, pa, pde_ptr);
bellard's avatar
bellard committed
618 619 620 621
	    for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
		pde_ptr = mmu_probe(va1, 1);
		if (pde_ptr) {
		    pa = cpu_get_phys_page_debug(env, va1);
622
 		    printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PDE: " TARGET_FMT_lx "\n", va1, pa, pde_ptr);
bellard's avatar
bellard committed
623 624 625 626
		    for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
			pde_ptr = mmu_probe(va2, 0);
			if (pde_ptr) {
			    pa = cpu_get_phys_page_debug(env, va2);
627
 			    printf("  VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PTE: " TARGET_FMT_lx "\n", va2, pa, pde_ptr);
bellard's avatar
bellard committed
628 629 630 631 632 633 634 635
			}
		    }
		}
	    }
	}
    }
    printf("MMU dump ends\n");
}
bellard's avatar
bellard committed
636
#endif
bellard's avatar
bellard committed
637
#endif