Search
lxdream.org :: lxdream/src/sh4/mmux86.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/mmux86.c
changeset 972:fb948057cf08
prev953:f4a156508ad1
next975:007bf7eb944f
author nkeynes
date Mon Jan 26 03:05:54 2009 +0000 (15 years ago)
permissions -rw-r--r--
last change Fix TLB access to SH4 peripheral control regions
file annotate diff log raw
nkeynes@953
     1
/**
nkeynes@953
     2
 * $Id$
nkeynes@953
     3
 * 
nkeynes@953
     4
 * x86-specific MMU code - this emits simple TLB stubs for TLB indirection.
nkeynes@953
     5
  *
nkeynes@953
     6
 * Copyright (c) 2008 Nathan Keynes.
nkeynes@953
     7
 *
nkeynes@953
     8
 * This program is free software; you can redistribute it and/or modify
nkeynes@953
     9
 * it under the terms of the GNU General Public License as published by
nkeynes@953
    10
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@953
    11
 * (at your option) any later version.
nkeynes@953
    12
 *
nkeynes@953
    13
 * This program is distributed in the hope that it will be useful,
nkeynes@953
    14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@953
    15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@953
    16
 * GNU General Public License for more details.
nkeynes@953
    17
 */
nkeynes@953
    18
nkeynes@953
    19
#include "lxdream.h"
nkeynes@953
    20
#include "mem.h"
nkeynes@953
    21
#include "sh4/sh4core.h"
nkeynes@953
    22
#include "sh4/sh4mmio.h"
nkeynes@953
    23
#include "sh4/sh4trans.h"
nkeynes@953
    24
#include "sh4/mmu.h"
nkeynes@953
    25
#include "sh4/x86op.h"
nkeynes@953
    26
nkeynes@953
    27
#if SIZEOF_VOID_P == 8
nkeynes@953
    28
#define ARG1 R_EDI
nkeynes@953
    29
#define ARG2 R_ESI
nkeynes@953
    30
#define DECODE() \
nkeynes@972
    31
    MOV_imm64_r32((uintptr_t)addr_space, R_EAX);     /* movq ptr, %rax */ \
nkeynes@953
    32
    REXW(); OP(0x8B); OP(0x0C); OP(0xC8)                    /* movq [%rax + %rcx*8], %rcx */
nkeynes@953
    33
#else
nkeynes@953
    34
#define ARG1 R_EAX
nkeynes@953
    35
#define ARG2 R_EDX
nkeynes@953
    36
#define DECODE() \
nkeynes@972
    37
    MOV_r32disp32x4_r32( R_ECX, (uintptr_t)addr_space, R_ECX );
nkeynes@953
    38
#endif
nkeynes@953
    39
nkeynes@953
    40
void mmu_utlb_init_vtable( struct utlb_entry *ent, struct utlb_page_entry *page, gboolean writable )
nkeynes@953
    41
{
nkeynes@953
    42
    uint32_t mask = ent->mask;
nkeynes@953
    43
    uint32_t vpn = ent->vpn & mask;
nkeynes@953
    44
    uint32_t ppn = ent->ppn & mask;
nkeynes@972
    45
    struct mem_region_fn **addr_space;
nkeynes@972
    46
    uint8_t **out = (uint8_t **)&page->fn;
nkeynes@972
    47
    uint8_t **fn;
nkeynes@953
    48
    int inc = writable ? 1 : 2; 
nkeynes@953
    49
    int i;
nkeynes@953
    50
    
nkeynes@953
    51
    xlat_output = page->code;
nkeynes@972
    52
    if( (ppn & 0x1FFFFFFF) >= 0x1C000000 ) {
nkeynes@972
    53
        /* SH4 control region */
nkeynes@972
    54
        ppn |= 0xE0000000;
nkeynes@972
    55
        addr_space = sh4_address_space;
nkeynes@972
    56
    } else {
nkeynes@972
    57
        addr_space = ext_address_space;
nkeynes@972
    58
    }
nkeynes@972
    59
    fn = (uint8_t **)addr_space[ppn>>12];
nkeynes@953
    60
    
nkeynes@953
    61
    for( i=0; i<9; i+= inc, fn += inc, out += inc ) {
nkeynes@953
    62
        *out = xlat_output;
nkeynes@953
    63
#if SIZEOF_VOID_P == 8
nkeynes@953
    64
        MOV_imm64_r32((uintptr_t)&mmu_urc, R_EAX );
nkeynes@953
    65
        OP(0x83); OP(0x00); OP(0x01); // ADD #1, [RAX]
nkeynes@953
    66
#else 
nkeynes@953
    67
        OP(0x83); MODRM_r32_disp32(0, (uintptr_t)&mmu_urc); OP(0x01); // ADD #1, mmu_urc
nkeynes@953
    68
#endif
nkeynes@953
    69
        ADD_imm32_r32( ppn-vpn, ARG1 ); // 6
nkeynes@953
    70
        if( ent->mask >= 0xFFFFF000 ) {
nkeynes@953
    71
            // Maps to a single page, so jump directly there
nkeynes@953
    72
            int rel = (*fn - xlat_output);
nkeynes@953
    73
            JMP_rel( rel ); // 5
nkeynes@953
    74
        } else {
nkeynes@953
    75
            MOV_r32_r32( ARG1, R_ECX ); // 2
nkeynes@953
    76
            SHR_imm8_r32( 12, R_ECX );  // 3
nkeynes@953
    77
            DECODE();                   // 14
nkeynes@953
    78
            JMP_r32disp8(R_ECX, (((uintptr_t)out) - ((uintptr_t)&page->fn)) );    // 3
nkeynes@953
    79
        }
nkeynes@953
    80
    }
nkeynes@953
    81
    
nkeynes@953
    82
    page->fn.prefetch = unmapped_prefetch; // FIXME
nkeynes@953
    83
}
nkeynes@953
    84
nkeynes@953
    85
void mmu_utlb_init_storequeue_vtable( struct utlb_entry *ent, struct utlb_page_entry *page )
nkeynes@953
    86
{
nkeynes@953
    87
    uint32_t mask = ent->mask;
nkeynes@953
    88
    uint32_t vpn = ent->vpn & mask;
nkeynes@953
    89
    uint32_t ppn = ent->ppn & mask;
nkeynes@953
    90
nkeynes@953
    91
    xlat_output = page->code;
nkeynes@953
    92
nkeynes@953
    93
    memcpy( page, &p4_region_storequeue, sizeof(struct mem_region_fn) );
nkeynes@953
    94
nkeynes@953
    95
    /* TESTME: Does a PREF increment the URC counter? */
nkeynes@953
    96
    page->fn.prefetch = (mem_prefetch_fn_t)xlat_output;
nkeynes@953
    97
    ADD_imm32_r32( ppn-vpn, ARG1 );
nkeynes@953
    98
    int rel = ((uint8_t *)ccn_storequeue_prefetch_tlb) - xlat_output;
nkeynes@953
    99
    JMP_rel( rel );
nkeynes@953
   100
}
nkeynes@953
   101
nkeynes@953
   102
void mmu_utlb_1k_init_vtable( struct utlb_1k_entry *entry )
nkeynes@953
   103
{
nkeynes@953
   104
    xlat_output = entry->code;
nkeynes@953
   105
    int i;
nkeynes@953
   106
    uint8_t **out = (uint8_t **)&entry->fn;
nkeynes@953
   107
    
nkeynes@953
   108
    for( i=0; i<9; i++, out++ ) {
nkeynes@953
   109
        *out = xlat_output;
nkeynes@953
   110
        MOV_r32_r32( ARG1, R_ECX );
nkeynes@953
   111
        SHR_imm8_r32( 10, R_ECX );
nkeynes@953
   112
        AND_imm8s_r32( 0x3, R_ECX );
nkeynes@953
   113
#if SIZEOF_VOID_P == 8
nkeynes@953
   114
        MOV_imm64_r32( (uintptr_t)&entry->subpages[0], R_EAX );
nkeynes@953
   115
        REXW(); OP(0x8B); OP(0x0C); OP(0xC8);                   /* movq [%rax + %rcx*8], %rcx */
nkeynes@953
   116
#else
nkeynes@953
   117
        MOV_r32disp32x4_r32( R_ECX, ((uintptr_t)&entry->subpages[0]), R_ECX );
nkeynes@953
   118
#endif                
nkeynes@953
   119
        JMP_r32disp8(R_ECX, (((uintptr_t)out) - ((uintptr_t)&entry->fn)) );    // 3
nkeynes@953
   120
    }
nkeynes@953
   121
nkeynes@953
   122
    out = (uint8_t **)&entry->user_fn;
nkeynes@953
   123
    for( i=0; i<9; i++, out++ ) {
nkeynes@953
   124
        *out = xlat_output;
nkeynes@953
   125
        MOV_r32_r32( ARG1, R_ECX );
nkeynes@953
   126
        SHR_imm8_r32( 10, R_ECX );
nkeynes@953
   127
        AND_imm8s_r32( 0x3, R_ECX );
nkeynes@953
   128
#if SIZEOF_VOID_P == 8
nkeynes@953
   129
        MOV_imm64_r32( (uintptr_t)&entry->user_subpages[0], R_EAX );
nkeynes@953
   130
        REXW(); OP(0x8B); OP(0x0C); OP(0xC8);                   /* movq [%rax + %rcx*8], %rcx */
nkeynes@953
   131
#else
nkeynes@953
   132
        MOV_r32disp32x4_r32( R_ECX, ((uintptr_t)&entry->user_subpages[0]), R_ECX );
nkeynes@953
   133
#endif                
nkeynes@953
   134
        JMP_r32disp8(R_ECX, (((uintptr_t)out) - ((uintptr_t)&entry->user_fn)) );    // 3
nkeynes@953
   135
    }
nkeynes@953
   136
nkeynes@953
   137
}
.