Revision 536ba015

b/target-sparc/helper.c
379 379
/*
380 380
 * UltraSparc IIi I/DMMUs
381 381
 */
382

  
383
static inline int compare_masked(uint64_t x, uint64_t y, uint64_t mask)
384
{
385
    return (x & mask) == (y & mask);
386
}
387

  
388
// Returns true if TTE tag is valid and matches virtual address value in context
389
// requires virtual address mask value calculated from TTE entry size
390
static inline int ultrasparc_tag_match(uint64_t tlb_tag, uint64_t tlb_tte,
391
                                       uint64_t address, uint64_t context,
392
                                       target_phys_addr_t *physical)
393
{
394
    uint64_t mask;
395

  
396
    switch ((tlb_tte >> 61) & 3) {
397
    default:
398
    case 0x0: // 8k
399
        mask = 0xffffffffffffe000ULL;
400
        break;
401
    case 0x1: // 64k
402
        mask = 0xffffffffffff0000ULL;
403
        break;
404
    case 0x2: // 512k
405
        mask = 0xfffffffffff80000ULL;
406
        break;
407
    case 0x3: // 4M
408
        mask = 0xffffffffffc00000ULL;
409
        break;
410
    }
411

  
412
    // valid, context match, virtual address match?
413
    if ((tlb_tte & 0x8000000000000000ULL) &&
414
            compare_masked(context, tlb_tag, 0x1fff) &&
415
            compare_masked(address, tlb_tag, mask))
416
    {
417
        // decode physical address
418
        *physical = ((tlb_tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
419
        return 1;
420
    }
421

  
422
    return 0;
423
}
424

  
382 425
static int get_physical_address_data(CPUState *env,
383 426
                                     target_phys_addr_t *physical, int *prot,
384 427
                                     target_ulong address, int rw, int is_user)
385 428
{
386
    target_ulong mask;
387 429
    unsigned int i;
430
    uint64_t context;
388 431

  
389 432
    if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
390 433
        *physical = ultrasparc_truncate_physical(address);
......
392 435
        return 0;
393 436
    }
394 437

  
438
    context = env->dmmuregs[1] & 0x1fff;
439

  
395 440
    for (i = 0; i < 64; i++) {
396
        switch ((env->dtlb_tte[i] >> 61) & 3) {
397
        default:
398
        case 0x0: // 8k
399
            mask = 0xffffffffffffe000ULL;
400
            break;
401
        case 0x1: // 64k
402
            mask = 0xffffffffffff0000ULL;
403
            break;
404
        case 0x2: // 512k
405
            mask = 0xfffffffffff80000ULL;
406
            break;
407
        case 0x3: // 4M
408
            mask = 0xffffffffffc00000ULL;
409
            break;
410
        }
411 441
        // ctx match, vaddr match, valid?
412
        if (env->dmmuregs[1] == (env->dtlb_tag[i] & 0x1fff) &&
413
            (address & mask) == (env->dtlb_tag[i] & mask) &&
414
            (env->dtlb_tte[i] & 0x8000000000000000ULL)) {
442
        if (ultrasparc_tag_match(env->dtlb_tag[i], env->dtlb_tte[i],
443
                                 address, context, physical)
444
        ) {
415 445
            // access ok?
416 446
            if (((env->dtlb_tte[i] & 0x4) && is_user) ||
417 447
                (!(env->dtlb_tte[i] & 0x2) && (rw == 1))) {
......
426 456
#endif
427 457
                return 1;
428 458
            }
429
            *physical = ((env->dtlb_tte[i] & mask) | (address & ~mask)) &
430
                        0x1ffffffe000ULL;
431 459
            *prot = PAGE_READ;
432 460
            if (env->dtlb_tte[i] & 0x2)
433 461
                *prot |= PAGE_WRITE;
......
437 465
#ifdef DEBUG_MMU
438 466
    printf("DMISS at 0x%" PRIx64 "\n", address);
439 467
#endif
440
    env->dmmuregs[6] = (address & ~0x1fffULL) | (env->dmmuregs[1] & 0x1fff);
468
    env->dmmuregs[6] = (address & ~0x1fffULL) | context;
441 469
    env->exception_index = TT_DMISS;
442 470
    return 1;
443 471
}
......
446 474
                                     target_phys_addr_t *physical, int *prot,
447 475
                                     target_ulong address, int is_user)
448 476
{
449
    target_ulong mask;
450 477
    unsigned int i;
478
    uint64_t context;
451 479

  
452 480
    if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
453 481
        /* IMMU disabled */
......
456 484
        return 0;
457 485
    }
458 486

  
487
    context = env->dmmuregs[1] & 0x1fff;
488

  
459 489
    for (i = 0; i < 64; i++) {
460
        switch ((env->itlb_tte[i] >> 61) & 3) {
461
        default:
462
        case 0x0: // 8k
463
            mask = 0xffffffffffffe000ULL;
464
            break;
465
        case 0x1: // 64k
466
            mask = 0xffffffffffff0000ULL;
467
            break;
468
        case 0x2: // 512k
469
            mask = 0xfffffffffff80000ULL;
470
            break;
471
        case 0x3: // 4M
472
            mask = 0xffffffffffc00000ULL;
473
                break;
474
        }
475 490
        // ctx match, vaddr match, valid?
476
        if (env->dmmuregs[1] == (env->itlb_tag[i] & 0x1fff) &&
477
            (address & mask) == (env->itlb_tag[i] & mask) &&
478
            (env->itlb_tte[i] & 0x8000000000000000ULL)) {
491
        if (ultrasparc_tag_match(env->itlb_tag[i], env->itlb_tte[i],
492
                                 address, context, physical)
493
        ) {
479 494
            // access ok?
480 495
            if ((env->itlb_tte[i] & 0x4) && is_user) {
481 496
                if (env->immuregs[3]) /* Fault status register */
......
488 503
#endif
489 504
                return 1;
490 505
            }
491
            *physical = ((env->itlb_tte[i] & mask) | (address & ~mask)) &
492
                        0x1ffffffe000ULL;
493 506
            *prot = PAGE_EXEC;
494 507
            return 0;
495 508
        }
......
498 511
    printf("TMISS at 0x%" PRIx64 "\n", address);
499 512
#endif
500 513
    /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
501
    env->immuregs[6] = (address & ~0x1fffULL) | (env->dmmuregs[1] & 0x1fff);
514
    env->immuregs[6] = (address & ~0x1fffULL) | context;
502 515
    env->exception_index = TT_TMISS;
503 516
    return 1;
504 517
}

Also available in: Unified diff