root / target-cris / mmu.c @ 6ebbf390
History | View | Annotate | Download (3.3 kB)
1 |
/*
|
---|---|
2 |
* CRIS mmu emulation.
|
3 |
*
|
4 |
* Copyright (c) 2007 AXIS Communications AB
|
5 |
* Written by Edgar E. Iglesias.
|
6 |
*
|
7 |
* This library is free software; you can redistribute it and/or
|
8 |
* modify it under the terms of the GNU Lesser General Public
|
9 |
* License as published by the Free Software Foundation; either
|
10 |
* version 2 of the License, or (at your option) any later version.
|
11 |
*
|
12 |
* This library is distributed in the hope that it will be useful,
|
13 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
15 |
* Lesser General Public License for more details.
|
16 |
*
|
17 |
* You should have received a copy of the GNU Lesser General Public
|
18 |
* License along with this library; if not, write to the Free Software
|
19 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
20 |
*/
|
21 |
|
22 |
#ifndef CONFIG_USER_ONLY
|
23 |
|
24 |
#include <stdio.h> |
25 |
#include <string.h> |
26 |
#include <stdlib.h> |
27 |
|
28 |
#include "config.h" |
29 |
#include "cpu.h" |
30 |
#include "mmu.h" |
31 |
#include "exec-all.h" |
32 |
|
33 |
|
34 |
static int cris_mmu_enabled(uint32_t rw_gc_cfg) |
35 |
{ |
36 |
return (rw_gc_cfg & 12) != 0; |
37 |
} |
38 |
|
39 |
static int cris_mmu_segmented_addr(int seg, uint32_t rw_mm_cfg) |
40 |
{ |
41 |
return (1 << seg) & rw_mm_cfg; |
42 |
} |
43 |
|
44 |
static uint32_t cris_mmu_translate_seg(CPUState *env, int seg) |
45 |
{ |
46 |
uint32_t base; |
47 |
int i;
|
48 |
|
49 |
if (seg < 8) |
50 |
base = env->sregs[SFR_RW_MM_KBASE_LO]; |
51 |
else
|
52 |
base = env->sregs[SFR_RW_MM_KBASE_HI]; |
53 |
|
54 |
i = seg & 7;
|
55 |
base >>= i * 4;
|
56 |
base &= 15;
|
57 |
|
58 |
base <<= 28;
|
59 |
return base;
|
60 |
} |
61 |
/* Used by the tlb decoder. */
|
62 |
#define EXTRACT_FIELD(src, start, end) \
|
63 |
(((src) >> start) & ((1 << (end - start + 1)) - 1)) |
64 |
|
65 |
static int cris_mmu_translate_page(struct cris_mmu_result_t *res, |
66 |
CPUState *env, uint32_t vaddr, |
67 |
int rw, int usermode) |
68 |
{ |
69 |
unsigned int vpage; |
70 |
unsigned int idx; |
71 |
uint32_t lo, hi; |
72 |
uint32_t vpn, pfn = 0, pid, fg, fv, fk, fw, fx;
|
73 |
int i, match = 0; |
74 |
|
75 |
vpage = vaddr >> 13;
|
76 |
idx = vpage & 31;
|
77 |
vpage >>= 4;
|
78 |
|
79 |
/* We know the index which to check on each set.
|
80 |
Scan both I and D. */
|
81 |
for (i = 0; i < 4; i++) |
82 |
{ |
83 |
lo = env->tlbsets[0][i][idx].lo;
|
84 |
hi = env->tlbsets[0][i][idx].hi;
|
85 |
|
86 |
vpn = EXTRACT_FIELD(hi, 13, 31); |
87 |
pid = EXTRACT_FIELD(hi, 0, 7); |
88 |
|
89 |
if (vpn == vpage
|
90 |
&& pid == env->pregs[SR_PID]) { |
91 |
match = 1;
|
92 |
break;
|
93 |
} |
94 |
} |
95 |
|
96 |
if (match) {
|
97 |
pfn = EXTRACT_FIELD(lo, 13, 31); |
98 |
fg = EXTRACT_FIELD(lo, 4, 4); |
99 |
fv = EXTRACT_FIELD(lo, 3, 3); |
100 |
fk = EXTRACT_FIELD(lo, 2, 2); |
101 |
fw = EXTRACT_FIELD(lo, 1, 1); |
102 |
fx = EXTRACT_FIELD(lo, 0, 0); |
103 |
} |
104 |
printf ("%s match=%d vaddr=%x vpage=%x vpn=%x pfn=%x pid=%x %x\n",
|
105 |
__func__, match, |
106 |
vaddr, vpage, |
107 |
vpn, pfn, pid, env->pregs[SR_PID]); |
108 |
res->pfn = pfn; |
109 |
return !match;
|
110 |
} |
111 |
|
112 |
int cris_mmu_translate(struct cris_mmu_result_t *res, |
113 |
CPUState *env, uint32_t vaddr, |
114 |
int rw, int mmu_idx) |
115 |
{ |
116 |
uint32_t phy = vaddr; |
117 |
int seg;
|
118 |
int miss = 0; |
119 |
int is_user = mmu_idx == MMU_USER_IDX;
|
120 |
|
121 |
if (!cris_mmu_enabled(env->sregs[SFR_RW_GC_CFG])) {
|
122 |
res->phy = vaddr; |
123 |
return 0; |
124 |
} |
125 |
|
126 |
seg = vaddr >> 28;
|
127 |
if (cris_mmu_segmented_addr(seg, env->sregs[SFR_RW_MM_CFG]))
|
128 |
{ |
129 |
uint32_t base; |
130 |
|
131 |
miss = 0;
|
132 |
base = cris_mmu_translate_seg(env, seg); |
133 |
phy = base | (0x0fffffff & vaddr);
|
134 |
res->phy = phy; |
135 |
} |
136 |
else
|
137 |
{ |
138 |
miss = cris_mmu_translate_page(res, env, vaddr, rw, is_user); |
139 |
if (!miss) {
|
140 |
phy &= 8191;
|
141 |
phy |= (res->pfn << 13);
|
142 |
res->phy = phy; |
143 |
} |
144 |
} |
145 |
// printf ("miss=%d v=%x -> p=%x\n", miss, vaddr, phy);
|
146 |
return miss;
|
147 |
} |
148 |
#endif
|