]>
Commit | Line | Data |
---|---|---|
94cff60a TS |
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, | |
6ebbf390 | 114 | int rw, int mmu_idx) |
94cff60a TS |
115 | { |
116 | uint32_t phy = vaddr; | |
117 | int seg; | |
118 | int miss = 0; | |
6ebbf390 | 119 | int is_user = mmu_idx == MMU_USER_IDX; |
94cff60a TS |
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 |