1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <mach.h>
5 #include "arm.h"
6
7 extern ulong textbase;
8
9 ulong
ifetch(ulong addr)10 ifetch(ulong addr)
11 {
12 uchar *va;
13
14 if(addr&3) {
15 Bprint(bioout, "Address error (I-fetch) vaddr %.8lux\n", addr);
16 longjmp(errjmp, 0);
17 }
18
19 if(icache.on)
20 updateicache(addr);
21 iprof[(addr-textbase)/PROFGRAN]++;
22
23 va = vaddr(addr);
24 va += addr&(BY2PG-1);
25
26 return va[3]<<24 | va[2]<<16 | va[1]<<8 | va[0];
27 }
28
29 ulong
getmem_4(ulong addr)30 getmem_4(ulong addr)
31 {
32 ulong val;
33 int i;
34
35 val = 0;
36 for(i = 0; i < 4; i++)
37 val = (val>>8) | (getmem_b(addr++)<<24);
38 return val;
39 }
40
41 ulong
getmem_2(ulong addr)42 getmem_2(ulong addr)
43 {
44 ulong val;
45 int i;
46
47 val = 0;
48 for(i = 0; i < 2; i++)
49 val = (val>>8) | (getmem_b(addr++)<<16);
50 return val;
51 }
52
53 ulong
getmem_w(ulong addr)54 getmem_w(ulong addr)
55 {
56 uchar *va;
57 ulong w;
58
59 if(addr&3) {
60 w = getmem_w(addr & ~3);
61 while(addr & 3) {
62 w = (w>>8) | (w<<24);
63 addr--;
64 }
65 return w;
66 }
67 if(membpt)
68 brkchk(addr, Read);
69
70 va = vaddr(addr);
71 va += addr&(BY2PG-1);
72
73 return va[3]<<24 | va[2]<<16 | va[1]<<8 | va[0];
74 }
75
76 ushort
getmem_h(ulong addr)77 getmem_h(ulong addr)
78 {
79 uchar *va;
80 ulong w;
81
82 if(addr&1) {
83 w = getmem_h(addr & ~1);
84 while(addr & 1) {
85 w = (w>>8) | (w<<8);
86 addr--;
87 }
88 return w;
89 }
90 if(membpt)
91 brkchk(addr, Read);
92
93 va = vaddr(addr);
94 va += addr&(BY2PG-1);
95
96 return va[1]<<8 | va[0];
97 }
98
99 uchar
getmem_b(ulong addr)100 getmem_b(ulong addr)
101 {
102 uchar *va;
103
104 if(membpt)
105 brkchk(addr, Read);
106
107 va = vaddr(addr);
108 va += addr&(BY2PG-1);
109 return va[0];
110 }
111
112 uvlong
getmem_v(ulong addr)113 getmem_v(ulong addr)
114 {
115 return ((uvlong)getmem_w(addr+4) << 32) | getmem_w(addr);
116 }
117
118 void
putmem_h(ulong addr,ushort data)119 putmem_h(ulong addr, ushort data)
120 {
121 uchar *va;
122
123 if(addr&1) {
124 Bprint(bioout, "Address error (Store) vaddr %.8lux\n", addr);
125 longjmp(errjmp, 0);
126 }
127
128 va = vaddr(addr);
129 va += addr&(BY2PG-1);
130
131 va[1] = data>>8;
132 va[0] = data;
133 if(membpt)
134 brkchk(addr, Write);
135 }
136
137 void
putmem_w(ulong addr,ulong data)138 putmem_w(ulong addr, ulong data)
139 {
140 uchar *va;
141
142 if(addr&3) {
143 Bprint(bioout, "Address error (Store) vaddr %.8lux\n", addr);
144 longjmp(errjmp, 0);
145 }
146
147 va = vaddr(addr);
148 va += addr&(BY2PG-1);
149
150 va[3] = data>>24;
151 va[2] = data>>16;
152 va[1] = data>>8;
153 va[0] = data;
154 if(membpt)
155 brkchk(addr, Write);
156 }
157
158 void
putmem_b(ulong addr,uchar data)159 putmem_b(ulong addr, uchar data)
160 {
161 uchar *va;
162
163 va = vaddr(addr);
164 va += addr&(BY2PG-1);
165 va[0] = data;
166 if(membpt)
167 brkchk(addr, Write);
168 }
169
170 void
putmem_v(ulong addr,uvlong data)171 putmem_v(ulong addr, uvlong data)
172 {
173 putmem_w(addr, data); /* two stages, to catch brkchk */
174 putmem_w(addr+4, data>>32);
175 }
176
177 char *
memio(char * mb,ulong mem,int size,int dir)178 memio(char *mb, ulong mem, int size, int dir)
179 {
180 int i;
181 char *buf, c;
182
183 if(mb == 0)
184 mb = emalloc(size);
185
186 buf = mb;
187 switch(dir) {
188 default:
189 fatal(0, "memio");
190 case MemRead:
191 while(size--)
192 *mb++ = getmem_b(mem++);
193 break;
194 case MemReadstring:
195 for(;;) {
196 if(size-- == 0) {
197 Bprint(bioout, "memio: user/kernel copy too long for arm\n");
198 longjmp(errjmp, 0);
199 }
200 c = getmem_b(mem++);
201 *mb++ = c;
202 if(c == '\0')
203 break;
204 }
205 break;
206 case MemWrite:
207 for(i = 0; i < size; i++)
208 putmem_b(mem++, *mb++);
209 break;
210 }
211 return buf;
212 }
213
214 void
dotlb(ulong vaddr)215 dotlb(ulong vaddr)
216 {
217 ulong *l, *e;
218
219 vaddr &= ~(BY2PG-1);
220
221 e = &tlb.tlbent[tlb.tlbsize];
222 for(l = tlb.tlbent; l < e; l++)
223 if(*l == vaddr) {
224 tlb.hit++;
225 return;
226 }
227
228 tlb.miss++;
229 tlb.tlbent[lnrand(tlb.tlbsize)] = vaddr;
230 }
231
232 void *
vaddr(ulong addr)233 vaddr(ulong addr)
234 {
235 Segment *s, *es;
236 int off, foff, l, n;
237 uchar **p, *a;
238
239 if(tlb.on)
240 dotlb(addr);
241
242 es = &memory.seg[Nseg];
243 for(s = memory.seg; s < es; s++) {
244 if(addr >= s->base && addr < s->end) {
245 s->refs++;
246 off = (addr-s->base)/BY2PG;
247 p = &s->table[off];
248 if(*p)
249 return *p;
250 s->rss++;
251 switch(s->type) {
252 default:
253 fatal(0, "vaddr");
254 case Text:
255 *p = emalloc(BY2PG);
256 if(seek(text, s->fileoff+(off*BY2PG), 0) < 0)
257 fatal(1, "vaddr text seek");
258 if(read(text, *p, BY2PG) < 0)
259 fatal(1, "vaddr text read");
260 return *p;
261 case Data:
262 *p = emalloc(BY2PG);
263 foff = s->fileoff+(off*BY2PG);
264 if(seek(text, foff, 0) < 0)
265 fatal(1, "vaddr text seek");
266 n = read(text, *p, BY2PG);
267 if(n < 0)
268 fatal(1, "vaddr text read");
269 if(foff + n > s->fileend) {
270 l = BY2PG - (s->fileend-foff);
271 a = *p+(s->fileend-foff);
272 memset(a, 0, l);
273 }
274 return *p;
275 case Bss:
276 case Stack:
277 *p = emalloc(BY2PG);
278 return *p;
279 }
280 }
281 }
282 Bprint(bioout, "User TLB miss vaddr 0x%.8lux\n", addr);
283 longjmp(errjmp, 0);
284 return 0; /*to stop compiler whining*/
285 }
286