1 |
/* |
2 |
* Copyright (C) 2004-2005 Anders Gavare. All rights reserved. |
3 |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
6 |
* |
7 |
* 1. Redistributions of source code must retain the above copyright |
8 |
* notice, this list of conditions and the following disclaimer. |
9 |
* 2. Redistributions in binary form must reproduce the above copyright |
10 |
* notice, this list of conditions and the following disclaimer in the |
11 |
* documentation and/or other materials provided with the distribution. |
12 |
* 3. The name of the author may not be used to endorse or promote products |
13 |
* derived from this software without specific prior written permission. |
14 |
* |
15 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
16 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
19 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
20 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
21 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
22 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
23 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
24 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
25 |
* SUCH DAMAGE. |
26 |
* |
27 |
* |
28 |
* $Id: memory_fast_v2h.c,v 1.2 2005/11/13 00:14:07 debug Exp $ |
29 |
* |
30 |
* Fast virtual memory to host address, used by binary translated code. |
31 |
*/ |
32 |
|
33 |
#include <stdio.h> |
34 |
#include <stdlib.h> |
35 |
|
36 |
#include "bintrans.h" |
37 |
#include "cpu.h" |
38 |
#include "memory.h" |
39 |
#include "cpu_mips.h" |
40 |
#include "misc.h" |
41 |
|
42 |
|
43 |
#ifdef BINTRANS |
44 |
|
45 |
/* |
46 |
* fast_vaddr_to_hostaddr(): |
47 |
* |
48 |
* Used by dynamically translated code. The caller should have made sure |
49 |
* that the access is aligned correctly. |
50 |
* |
51 |
* Return value is a pointer to a host page + offset, if the page was |
52 |
* writable (or writeflag was zero), if the virtual address was translatable |
53 |
* to a paddr, and if the paddr was translatable to a host address. |
54 |
* |
55 |
* On error, NULL is returned. The caller (usually the dynamically |
56 |
* generated machine code) must check for this. |
57 |
*/ |
58 |
unsigned char *fast_vaddr_to_hostaddr(struct cpu *cpu, |
59 |
uint64_t vaddr, int writeflag) |
60 |
{ |
61 |
int ok, i, n, start_and_stop; |
62 |
uint64_t paddr, vaddr_page; |
63 |
unsigned char *memblock; |
64 |
size_t offset; |
65 |
const int MAX = N_BINTRANS_VADDR_TO_HOST; |
66 |
|
67 |
/* printf("fast_vaddr_to_hostaddr(): cpu=%p, vaddr=%016llx, wf=%i\n", |
68 |
cpu, (long long)vaddr, writeflag); */ |
69 |
|
70 |
#if 0 |
71 |
/* Hm. This seems to work now, so this #if X can be removed. (?) */ |
72 |
|
73 |
/* |
74 |
* TODO: |
75 |
* |
76 |
* Why doesn't this work yet? |
77 |
*/ |
78 |
if ((vaddr & 0xc0000000ULL) >= 0xc0000000ULL && writeflag) { |
79 |
return NULL; |
80 |
} |
81 |
#endif |
82 |
|
83 |
|
84 |
vaddr_page = vaddr & ~0xfff; |
85 |
i = start_and_stop = cpu->cd.mips.bintrans_next_index; |
86 |
n = 0; |
87 |
for (;;) { |
88 |
if (cpu->cd.mips.bintrans_data_vaddr[i] == vaddr_page && |
89 |
cpu->cd.mips.bintrans_data_hostpage[i] != NULL && |
90 |
cpu->cd.mips.bintrans_data_writable[i] >= writeflag) { |
91 |
uint64_t tmpaddr; |
92 |
unsigned char *tmpptr; |
93 |
int tmpwf; |
94 |
|
95 |
if (n < 3) |
96 |
return cpu->cd.mips.bintrans_data_hostpage[i] |
97 |
+ (vaddr & 0xfff); |
98 |
|
99 |
cpu->cd.mips.bintrans_next_index = start_and_stop - 1; |
100 |
if (cpu->cd.mips.bintrans_next_index < 0) |
101 |
cpu->cd.mips.bintrans_next_index = MAX - 1; |
102 |
|
103 |
tmpptr = cpu->cd.mips.bintrans_data_hostpage[ |
104 |
cpu->cd.mips.bintrans_next_index]; |
105 |
tmpaddr = cpu->cd.mips.bintrans_data_vaddr[ |
106 |
cpu->cd.mips.bintrans_next_index]; |
107 |
tmpwf = cpu->cd.mips.bintrans_data_writable[ |
108 |
cpu->cd.mips.bintrans_next_index]; |
109 |
|
110 |
cpu->cd.mips.bintrans_data_hostpage[ |
111 |
cpu->cd.mips.bintrans_next_index] = |
112 |
cpu->cd.mips.bintrans_data_hostpage[i]; |
113 |
cpu->cd.mips.bintrans_data_vaddr[ |
114 |
cpu->cd.mips.bintrans_next_index] = |
115 |
cpu->cd.mips.bintrans_data_vaddr[i]; |
116 |
cpu->cd.mips.bintrans_data_writable[ |
117 |
cpu->cd.mips.bintrans_next_index] = |
118 |
cpu->cd.mips.bintrans_data_writable[i]; |
119 |
|
120 |
cpu->cd.mips.bintrans_data_hostpage[i] = tmpptr; |
121 |
cpu->cd.mips.bintrans_data_vaddr[i] = tmpaddr; |
122 |
cpu->cd.mips.bintrans_data_writable[i] = tmpwf; |
123 |
|
124 |
return cpu->cd.mips.bintrans_data_hostpage[ |
125 |
cpu->cd.mips.bintrans_next_index] + (vaddr & 0xfff); |
126 |
} |
127 |
|
128 |
n ++; |
129 |
i ++; |
130 |
if (i == MAX) |
131 |
i = 0; |
132 |
if (i == start_and_stop) |
133 |
break; |
134 |
} |
135 |
|
136 |
ok = cpu->translate_address(cpu, vaddr, &paddr, |
137 |
(writeflag? FLAG_WRITEFLAG : 0) + FLAG_NOEXCEPTIONS); |
138 |
/* printf("ok=%i\n", ok); */ |
139 |
if (!ok) |
140 |
return NULL; |
141 |
|
142 |
for (i=0; i<cpu->mem->n_mmapped_devices; i++) |
143 |
if (paddr >= (cpu->mem->dev_baseaddr[i] & ~0xfff) && |
144 |
paddr <= ((cpu->mem->dev_baseaddr[i] + |
145 |
cpu->mem->dev_length[i] - 1) | 0xfff)) { |
146 |
if (cpu->mem->dev_flags[i] & DM_DYNTRANS_OK) { |
147 |
paddr -= cpu->mem->dev_baseaddr[i]; |
148 |
|
149 |
/* Within a device _page_ but not within the |
150 |
actual device? Then abort: */ |
151 |
if ((int64_t)paddr < 0 || |
152 |
paddr >= cpu->mem->dev_length[i]) |
153 |
return NULL; |
154 |
|
155 |
if (writeflag) { |
156 |
uint64_t low_paddr = paddr & ~0xfff; |
157 |
uint64_t high_paddr = paddr | 0xfff; |
158 |
if (!(cpu->mem->dev_flags[i] & |
159 |
DM_DYNTRANS_WRITE_OK)) |
160 |
return NULL; |
161 |
|
162 |
if (low_paddr < cpu->mem-> |
163 |
dev_dyntrans_write_low[i]) |
164 |
cpu->mem-> |
165 |
dev_dyntrans_write_low[i] = |
166 |
low_paddr; |
167 |
if (high_paddr > cpu->mem-> |
168 |
dev_dyntrans_write_high[i]) |
169 |
cpu->mem-> |
170 |
dev_dyntrans_write_high[i] |
171 |
= high_paddr; |
172 |
} |
173 |
|
174 |
cpu->cd.mips.bintrans_next_index --; |
175 |
if (cpu->cd.mips.bintrans_next_index < 0) |
176 |
cpu->cd.mips.bintrans_next_index = |
177 |
MAX - 1; |
178 |
cpu->cd.mips.bintrans_data_hostpage[cpu-> |
179 |
cd.mips.bintrans_next_index] = cpu->mem-> |
180 |
dev_dyntrans_data[i] + (paddr & ~0xfff); |
181 |
cpu->cd.mips.bintrans_data_vaddr[cpu-> |
182 |
cd.mips.bintrans_next_index] = vaddr_page; |
183 |
cpu->cd.mips.bintrans_data_writable[cpu-> |
184 |
cd.mips.bintrans_next_index] = writeflag; |
185 |
return cpu->mem->dev_dyntrans_data[i] + paddr; |
186 |
} else |
187 |
return NULL; |
188 |
} |
189 |
|
190 |
memblock = memory_paddr_to_hostaddr(cpu->mem, paddr, |
191 |
writeflag? MEM_WRITE : MEM_READ); |
192 |
if (memblock == NULL) |
193 |
return NULL; |
194 |
|
195 |
offset = paddr & ((1 << BITS_PER_MEMBLOCK) - 1); |
196 |
|
197 |
if (writeflag) |
198 |
bintrans_invalidate(cpu, paddr); |
199 |
|
200 |
cpu->cd.mips.bintrans_next_index --; |
201 |
if (cpu->cd.mips.bintrans_next_index < 0) |
202 |
cpu->cd.mips.bintrans_next_index = MAX - 1; |
203 |
cpu->cd.mips.bintrans_data_hostpage[cpu->cd.mips.bintrans_next_index] = |
204 |
memblock + (offset & ~0xfff); |
205 |
cpu->cd.mips.bintrans_data_vaddr[cpu->cd.mips.bintrans_next_index] = |
206 |
vaddr_page; |
207 |
cpu->cd.mips.bintrans_data_writable[cpu->cd.mips.bintrans_next_index] = |
208 |
writeflag; /* ok - 1; */ |
209 |
|
210 |
return memblock + offset; |
211 |
} |
212 |
|
213 |
#endif /* BINTRANS */ |