1 | /* $Id: tstOhciRegisterAccess.cpp 39149 2011-10-31 13:18:26Z vboxsync $ */
|
---|
2 | /** @file
|
---|
3 | * tstOhciRegisterAccess - OHCI Register Access Tests / Experiments.
|
---|
4 | */
|
---|
5 |
|
---|
6 | /*
|
---|
7 | * Copyright (C) 2011 Oracle Corporation
|
---|
8 | *
|
---|
9 | * This file is part of VirtualBox Open Source Edition (OSE), as
|
---|
10 | * available from http://www.virtualbox.org. This file is free software;
|
---|
11 | * you can redistribute it and/or modify it under the terms of the GNU
|
---|
12 | * General Public License (GPL) as published by the Free Software
|
---|
13 | * Foundation, in version 2 as it comes in the "COPYING" file of the
|
---|
14 | * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
|
---|
15 | * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
|
---|
16 | */
|
---|
17 |
|
---|
18 |
|
---|
19 | /*******************************************************************************
|
---|
20 | * Header Files *
|
---|
21 | *******************************************************************************/
|
---|
22 | #include <VBox/log.h>
|
---|
23 | #include <iprt/mem.h>
|
---|
24 | #include <iprt/memobj.h>
|
---|
25 | #include <iprt/string.h>
|
---|
26 | #include <iprt/asm-amd64-x86.h>
|
---|
27 | #include <iprt/param.h>
|
---|
28 |
|
---|
29 | #include <VBox/sup.h>
|
---|
30 | #undef LogRel
|
---|
31 | #define LogRel(a) SUPR0Printf a
|
---|
32 |
|
---|
33 |
|
---|
34 | /*******************************************************************************
|
---|
35 | * Global Variables *
|
---|
36 | *******************************************************************************/
|
---|
37 | /** Register names. */
|
---|
38 | static const char * const g_apszRegNms[] =
|
---|
39 | {
|
---|
40 | /* 00 */ "HcRevision",
|
---|
41 | /* 01 */ "HcControl",
|
---|
42 | /* 02 */ "HcCommandStatus",
|
---|
43 | /* 03 */ "HcInterruptStatus",
|
---|
44 | /* 04 */ "HcInterruptEnable",
|
---|
45 | /* 05 */ "HcInterruptDisable",
|
---|
46 | /* 06 */ "HcHCCA",
|
---|
47 | /* 07 */ "HcPeriodCurrentED",
|
---|
48 | /* 08 */ "HcControlHeadED",
|
---|
49 | /* 09 */ "HcControlCurrentED",
|
---|
50 | /* 10 */ "HcBulkHeadED",
|
---|
51 | /* 11 */ "HcBulkCurrentED",
|
---|
52 | /* 12 */ "HcDoneHead",
|
---|
53 | /* 13 */ "HcFmInterval",
|
---|
54 | /* 14 */ "HcFmRemaining",
|
---|
55 | /* 15 */ "HcFmNumber",
|
---|
56 | /* 16 */ "HcPeriodicStart",
|
---|
57 | /* 17 */ "HcLSThreshold",
|
---|
58 | /* 18 */ "HcRhDescriptorA",
|
---|
59 | /* 19 */ "HcRhDescriptorB",
|
---|
60 | /* 20 */ "HcRhStatus",
|
---|
61 | /* Variable number of root hub ports: */
|
---|
62 | /* 21 */ "HcRhPortStatus[0]",
|
---|
63 | /* 22 */ "HcRhPortStatus[1]",
|
---|
64 | /* 23 */ "HcRhPortStatus[2]",
|
---|
65 | /* 24 */ "HcRhPortStatus[3]",
|
---|
66 | /* 25 */ "HcRhPortStatus[4]",
|
---|
67 | /* 26 */ "HcRhPortStatus[5]",
|
---|
68 | /* 27 */ "HcRhPortStatus[6]",
|
---|
69 | /* 28 */ "HcRhPortStatus[7]"
|
---|
70 | };
|
---|
71 |
|
---|
72 |
|
---|
73 | static bool TestOhciWrites(RTVPTRUNION uPtr)
|
---|
74 | {
|
---|
75 | static struct
|
---|
76 | {
|
---|
77 | unsigned iReg;
|
---|
78 | uint32_t uVal1;
|
---|
79 | uint32_t uVal2;
|
---|
80 | } const s_aRegs[] =
|
---|
81 | {
|
---|
82 | { 4 /* HcInterruptEnable */, 0x3fffff80, 0x3e555580 },
|
---|
83 | { 5 /* HcInterruptDisable */, 0xffffffff, 0x59575351 },
|
---|
84 | #if 0 /* deadly when missing bytes are taken as zero. */
|
---|
85 | { 13 /* HcFmInterval */, 0x58871120, 0x01010101 },
|
---|
86 | #endif
|
---|
87 | { 16 /* HcPeriodicStart */, 0x01020304, 0x02010403 },
|
---|
88 | };
|
---|
89 |
|
---|
90 | bool fSuccess = true;
|
---|
91 | for (unsigned i = 0; i < RT_ELEMENTS(s_aRegs); i++)
|
---|
92 | {
|
---|
93 | uint32_t const iReg = s_aRegs[i].iReg;
|
---|
94 | RTVPTRUNION uPtrReg;
|
---|
95 | uPtrReg.pu32 = &uPtr.pu32[iReg];
|
---|
96 |
|
---|
97 | uint32_t uInitialValue = *uPtrReg.pu32;
|
---|
98 | LogRel(("TestOhciWrites: %p iReg=%2d %20s = %08RX32\n", uPtrReg.pv, iReg, g_apszRegNms[iReg], uInitialValue));
|
---|
99 |
|
---|
100 | bool fDone = true;
|
---|
101 | const char *pszError = NULL;
|
---|
102 | RTCCUINTREG const fFlags = ASMIntDisableFlags();
|
---|
103 |
|
---|
104 | /*
|
---|
105 | * DWORD writes.
|
---|
106 | */
|
---|
107 | uInitialValue = *uPtrReg.pu32;
|
---|
108 | *uPtrReg.pu32 = uInitialValue;
|
---|
109 | uint32_t u32A = *uPtrReg.pu32;
|
---|
110 | uint32_t const uChangedValue = s_aRegs[i].uVal1 != uInitialValue ? s_aRegs[i].uVal1 : s_aRegs[i].uVal2;
|
---|
111 | if (u32A == uInitialValue)
|
---|
112 | {
|
---|
113 | /* Change the value. */
|
---|
114 | *uPtrReg.pu32 = uChangedValue;
|
---|
115 | u32A = *uPtrReg.pu32;
|
---|
116 | *uPtrReg.pu32 = uInitialValue;
|
---|
117 | if (u32A != uChangedValue)
|
---|
118 | pszError = "Writing changed value failed";
|
---|
119 | else
|
---|
120 | {
|
---|
121 | u32A = *uPtrReg.pu32;
|
---|
122 | if (u32A != uInitialValue)
|
---|
123 | pszError = "Restore error 1";
|
---|
124 | }
|
---|
125 | }
|
---|
126 | else
|
---|
127 | pszError = "Writing back initial value failed";
|
---|
128 |
|
---|
129 |
|
---|
130 | /*
|
---|
131 | * Write byte changes.
|
---|
132 | */
|
---|
133 | for (unsigned iByte = 0; !pszError && iByte < 4; iByte)
|
---|
134 | {
|
---|
135 | /* Change the value. */
|
---|
136 | uPtrReg.pu8[iByte] = (uint8_t)(uChangedValue >> iByte * 8);
|
---|
137 | u32A = *uPtrReg.pu32;
|
---|
138 | *uPtrReg.pu32 = uInitialValue;
|
---|
139 | if (u32A != (uChangedValue & UINT32_C(0xff) << iByte * 8))
|
---|
140 | {
|
---|
141 | static const char * const s_apsz[] = { "byte 0", "byte 1", "byte 2", "byte 3" };
|
---|
142 | pszError = s_apsz[iByte];
|
---|
143 | }
|
---|
144 | else
|
---|
145 | {
|
---|
146 | u32A = *uPtrReg.pu32;
|
---|
147 | if (u32A != uInitialValue)
|
---|
148 | pszError = "Restore error 2";
|
---|
149 | }
|
---|
150 | }
|
---|
151 |
|
---|
152 | *uPtrReg.pu32 = uInitialValue;
|
---|
153 |
|
---|
154 | ASMSetFlags(fFlags);
|
---|
155 | ASMNopPause();
|
---|
156 |
|
---|
157 | /*
|
---|
158 | * Complain on failure.
|
---|
159 | */
|
---|
160 | if (!fDone)
|
---|
161 | LogRel(("TestOhciWrites: Warning! Register %s was never stable enough for testing! %08RX32 %08RX32 %08RX32\n",
|
---|
162 | g_apszRegNms[iReg], uInitialValue, u32A, uChangedValue, uInitialValue));
|
---|
163 | else if (pszError)
|
---|
164 | {
|
---|
165 | LogRel(("TestOhciWrites: Error! Register %s failed: %s; uInitialValue=%08RX32 uChangedValue=%08RX32 u32A=%08RX32\n",
|
---|
166 | g_apszRegNms[iReg], pszError, uInitialValue, uChangedValue, u32A));
|
---|
167 | fSuccess = false;
|
---|
168 | }
|
---|
169 | }
|
---|
170 |
|
---|
171 | return fSuccess;
|
---|
172 | }
|
---|
173 |
|
---|
174 |
|
---|
175 | static bool TestOhciReadOnly(RTVPTRUNION uPtr)
|
---|
176 | {
|
---|
177 | static struct
|
---|
178 | {
|
---|
179 | unsigned iReg;
|
---|
180 | uint32_t cValues;
|
---|
181 | uint32_t auValues[8];
|
---|
182 | } const s_aRegs[] =
|
---|
183 | {
|
---|
184 | { 0 /* HcRevision */, 8, { 0, UINT32_MAX, 0x10100110, 0x200, 0x111, 0x11f, 0xf110, 0x0f10 } },
|
---|
185 | { 12 /* HcDoneHead */, 3, { 0, UINT32_MAX, 0x55555555, 0, 0, 0, 0, 0 } },
|
---|
186 | { 14 /* HcFmRemaining */, 3, { 0, UINT32_MAX, 0x55555555, 0, 0, 0, 0, 0 } },
|
---|
187 | { 15 /* HcFmNumber */, 5, { 0, UINT32_MAX, 0x55555555, 0x7899, 0x00012222, 0, 0, 0 } },
|
---|
188 | #if 0 /* HCD can write this */
|
---|
189 | { 17 /* HcLSThreshold */, 5, { 0x627, 0x628, 0x629, 0x666, 0x599, 0, 0, 0 } } /* ??? */
|
---|
190 | #endif
|
---|
191 | };
|
---|
192 |
|
---|
193 | bool fSuccess = true;
|
---|
194 | for (unsigned i = 0; i < RT_ELEMENTS(s_aRegs); i++)
|
---|
195 | {
|
---|
196 | uint32_t const iReg = s_aRegs[i].iReg;
|
---|
197 | RTVPTRUNION uPtrReg;
|
---|
198 | uPtrReg.pu32 = &uPtr.pu32[iReg];
|
---|
199 |
|
---|
200 | uint32_t uInitialValue = *uPtrReg.pu32;
|
---|
201 | LogRel(("TestOhciReadOnly: %p iReg=%2d %20s = %08RX32\n", uPtrReg.pv, iReg, g_apszRegNms[iReg], uInitialValue));
|
---|
202 |
|
---|
203 | bool fTryAgain = true;
|
---|
204 | const char *pszError = NULL;
|
---|
205 | uint32_t uChangedValue = 0;
|
---|
206 | uint32_t u32A = 0;
|
---|
207 |
|
---|
208 | for (uint32_t iTry = 0; fTryAgain && iTry < 1024; iTry++)
|
---|
209 | {
|
---|
210 | pszError = NULL;
|
---|
211 | fTryAgain = false;
|
---|
212 | u32A = 0;
|
---|
213 | uChangedValue = 0;
|
---|
214 |
|
---|
215 | RTCCUINTREG const fFlags = ASMIntDisableFlags();
|
---|
216 | uInitialValue = *uPtrReg.pu32;
|
---|
217 |
|
---|
218 | /*
|
---|
219 | * Try aligned dword, word and byte writes for now.
|
---|
220 | */
|
---|
221 | for (unsigned iValue = 0; iValue < s_aRegs[i].cValues && !pszError && !fTryAgain; iValue++)
|
---|
222 | {
|
---|
223 | uChangedValue = s_aRegs[i].auValues[iValue];
|
---|
224 | if (uInitialValue == uChangedValue)
|
---|
225 | continue;
|
---|
226 |
|
---|
227 | /* dword */
|
---|
228 | if ((fTryAgain = (*uPtrReg.pu32 != uInitialValue)))
|
---|
229 | break;
|
---|
230 |
|
---|
231 | *uPtrReg.pu32 = uChangedValue;
|
---|
232 | u32A = *uPtrReg.pu32;
|
---|
233 | *uPtrReg.pu32 = uInitialValue;
|
---|
234 | if (u32A != uInitialValue)
|
---|
235 | pszError = "dword access";
|
---|
236 | else
|
---|
237 | {
|
---|
238 | u32A = *uPtrReg.pu32;
|
---|
239 | if (u32A != uInitialValue)
|
---|
240 | pszError = "Restore error 1";
|
---|
241 | }
|
---|
242 |
|
---|
243 | /* word */
|
---|
244 | for (unsigned iWord = 0; iWord < 2 && !pszError && !fTryAgain; iWord++)
|
---|
245 | {
|
---|
246 | if ((fTryAgain = (*uPtrReg.pu32 != uInitialValue)))
|
---|
247 | break;
|
---|
248 | uPtrReg.pu16[iWord] = (uint16_t)(uChangedValue >> iWord * 16);
|
---|
249 | u32A = *uPtrReg.pu32;
|
---|
250 | *uPtrReg.pu32 = uInitialValue;
|
---|
251 | if (u32A != uInitialValue)
|
---|
252 | pszError = iWord == 0 ? "aligned word 0 access" : "aligned word 1 access";
|
---|
253 | else
|
---|
254 | {
|
---|
255 | u32A = *uPtrReg.pu32;
|
---|
256 | if (u32A != uInitialValue)
|
---|
257 | pszError = "Restore error 2";
|
---|
258 | }
|
---|
259 | }
|
---|
260 |
|
---|
261 | /* byte */
|
---|
262 | for (unsigned iByte = 0; iByte < 4 && !pszError && !fTryAgain; iByte++)
|
---|
263 | {
|
---|
264 | if ((fTryAgain = (*uPtrReg.pu32 != uInitialValue)))
|
---|
265 | break;
|
---|
266 | uPtrReg.pu8[iByte] = (uint8_t)(uChangedValue >> iByte * 8);
|
---|
267 | u32A = *uPtrReg.pu32;
|
---|
268 | *uPtrReg.pu32 = uInitialValue;
|
---|
269 | if (u32A != uInitialValue)
|
---|
270 | {
|
---|
271 | static const char * const s_apsz[] = { "byte 0", "byte 1", "byte 2", "byte 3" };
|
---|
272 | pszError = s_apsz[iByte];
|
---|
273 | }
|
---|
274 | else
|
---|
275 | {
|
---|
276 | u32A = *uPtrReg.pu32;
|
---|
277 | if (u32A != uInitialValue)
|
---|
278 | pszError = "Restore error 3";
|
---|
279 | }
|
---|
280 | }
|
---|
281 | }
|
---|
282 |
|
---|
283 | ASMSetFlags(fFlags);
|
---|
284 | ASMNopPause();
|
---|
285 | }
|
---|
286 |
|
---|
287 | /*
|
---|
288 | * Complain on failure.
|
---|
289 | */
|
---|
290 | if (fTryAgain)
|
---|
291 | LogRel(("TestOhciReadOnly: Warning! Register %s was never stable enough for testing! %08RX32 %08RX32 %08RX32\n",
|
---|
292 | g_apszRegNms[iReg], uInitialValue, u32A, uChangedValue, uInitialValue));
|
---|
293 | else if (pszError)
|
---|
294 | {
|
---|
295 | LogRel(("TestOhciReadOnly: Error! Register %s failed: %s; uInitialValue=%08RX32 uChangedValue=%08RX32 u32A=%08RX32\n",
|
---|
296 | g_apszRegNms[iReg], pszError, uInitialValue, uChangedValue, u32A));
|
---|
297 | fSuccess = false;
|
---|
298 | }
|
---|
299 | }
|
---|
300 |
|
---|
301 | return fSuccess;
|
---|
302 | }
|
---|
303 |
|
---|
304 |
|
---|
305 | static bool TestOhciReads(RTVPTRUNION uPtr)
|
---|
306 | {
|
---|
307 | /*
|
---|
308 | * We can read just about any register we like since read shouldn't have
|
---|
309 | * any side effects. However, some registers are volatile and makes for
|
---|
310 | * difficult targets, thus the ugly code.
|
---|
311 | */
|
---|
312 | bool fSuccess = true;
|
---|
313 | uint32_t cMaxReg = RT_ELEMENTS(g_apszRegNms);
|
---|
314 | for (uint32_t iReg = 0; iReg < cMaxReg; iReg++, uPtr.pu32++)
|
---|
315 | {
|
---|
316 | const char *pszError = NULL;
|
---|
317 | bool fDone = false;
|
---|
318 | uint32_t uInitialValue = *uPtr.pu32;
|
---|
319 | uint32_t u32A = 0;
|
---|
320 | uint32_t u32B = 0;
|
---|
321 | uint32_t u32C = 0;
|
---|
322 | LogRel(("TestOhciReads: %p iReg=%2d %20s = %08RX32\n", uPtr.pv, iReg, g_apszRegNms[iReg], uInitialValue));
|
---|
323 |
|
---|
324 | for (uint32_t iTry = 0; !fDone && iTry < 1024; iTry++)
|
---|
325 | {
|
---|
326 | pszError = NULL;
|
---|
327 | fDone = true;
|
---|
328 | u32A = u32B = u32C = 0;
|
---|
329 |
|
---|
330 | RTCCUINTREG const fFlags = ASMIntDisableFlags();
|
---|
331 | uInitialValue = *uPtr.pu32;
|
---|
332 |
|
---|
333 | /* Test byte access. */
|
---|
334 | for (unsigned iByte = 0; iByte < 4; iByte++)
|
---|
335 | {
|
---|
336 | u32A = *uPtr.pu32;
|
---|
337 | u32B = uPtr.pu8[iByte];
|
---|
338 | u32C = *uPtr.pu32;
|
---|
339 | if (u32A != uInitialValue || u32C != uInitialValue)
|
---|
340 | {
|
---|
341 | fDone = false;
|
---|
342 | break;
|
---|
343 | }
|
---|
344 |
|
---|
345 | static uint32_t const a_au32Masks[] =
|
---|
346 | {
|
---|
347 | UINT32_C(0xffffff00), UINT32_C(0xffff00ff), UINT32_C(0xff00ffff), UINT32_C(0x00ffffff)
|
---|
348 | };
|
---|
349 | u32B <<= iByte * 8;
|
---|
350 | u32B |= uInitialValue & a_au32Masks[iByte];
|
---|
351 | if (u32B != uInitialValue)
|
---|
352 | {
|
---|
353 | static const char * const s_apsz[] = { "byte 0", "byte 1", "byte 2", "byte 3" };
|
---|
354 | pszError = s_apsz[iByte];
|
---|
355 | break;
|
---|
356 | }
|
---|
357 | }
|
---|
358 |
|
---|
359 | /* Test aligned word access. */
|
---|
360 | if (fDone)
|
---|
361 | {
|
---|
362 | for (unsigned iWord = 0; iWord < 2; iWord++)
|
---|
363 | {
|
---|
364 | u32A = *uPtr.pu32;
|
---|
365 | u32B = uPtr.pu16[iWord];
|
---|
366 | u32C = *uPtr.pu32;
|
---|
367 | if (u32A != uInitialValue || u32C != uInitialValue)
|
---|
368 | {
|
---|
369 | fDone = false;
|
---|
370 | break;
|
---|
371 | }
|
---|
372 |
|
---|
373 | u32B <<= iWord * 16;
|
---|
374 | u32B |= uInitialValue & (iWord == 0 ? UINT32_C(0xffff0000) : UINT32_C(0x0000ffff));
|
---|
375 | if (u32B != uInitialValue)
|
---|
376 | {
|
---|
377 | pszError = iWord == 0 ? "aligned word 0 access" : "aligned word 1 access";
|
---|
378 | break;
|
---|
379 | }
|
---|
380 | }
|
---|
381 | }
|
---|
382 |
|
---|
383 | /* Test unaligned word access. */
|
---|
384 | if (fDone)
|
---|
385 | {
|
---|
386 | for (int iWord = ((uintptr_t)uPtr.pv & PAGE_OFFSET_MASK) == 0; iWord < 3; iWord++)
|
---|
387 | {
|
---|
388 | u32A = *uPtr.pu32;
|
---|
389 | u32B = *(volatile uint16_t *)&uPtr.pu8[iWord * 2 - 1];
|
---|
390 | u32C = *uPtr.pu32;
|
---|
391 | if (u32A != uInitialValue || u32C != uInitialValue)
|
---|
392 | {
|
---|
393 | fDone = false;
|
---|
394 | break;
|
---|
395 | }
|
---|
396 |
|
---|
397 | switch (iWord)
|
---|
398 | {
|
---|
399 | case 0: u32B = (u32B >> 8) | (u32A & UINT32_C(0xffffff00)); break;
|
---|
400 | case 1: u32B = (u32B << 8) | (u32A & UINT32_C(0xff0000ff)); break;
|
---|
401 | case 2: u32B = (u32B << 24) | (u32A & UINT32_C(0x00ffffff)); break;
|
---|
402 | }
|
---|
403 | if (u32B != u32A)
|
---|
404 | {
|
---|
405 | static const char * const s_apsz[] = { "unaligned word 0", "unaligned word 1", "unaligned word 2" };
|
---|
406 | pszError = s_apsz[iWord];
|
---|
407 | break;
|
---|
408 | }
|
---|
409 | }
|
---|
410 | }
|
---|
411 |
|
---|
412 | /* Test unaligned dword access. */
|
---|
413 | if (fDone)
|
---|
414 | {
|
---|
415 | for (int iByte = ((uintptr_t)uPtr.pv & PAGE_OFFSET_MASK) == 0 ? 0 : -3; iByte < 4; iByte++)
|
---|
416 | {
|
---|
417 | u32A = *uPtr.pu32;
|
---|
418 | u32B = *(volatile uint32_t *)&uPtr.pu8[iByte];
|
---|
419 | u32C = *uPtr.pu32;
|
---|
420 | if (u32A != uInitialValue || u32C != uInitialValue)
|
---|
421 | {
|
---|
422 | fDone = false;
|
---|
423 | break;
|
---|
424 | }
|
---|
425 |
|
---|
426 | switch (iByte)
|
---|
427 | {
|
---|
428 | case -3: u32B = (u32B >> 24) | (uInitialValue & UINT32_C(0xffffff00)); break;
|
---|
429 | case -2: u32B = (u32B >> 16) | (uInitialValue & UINT32_C(0xffff0000)); break;
|
---|
430 | case -1: u32B = (u32B >> 8) | (uInitialValue & UINT32_C(0xff000000)); break;
|
---|
431 | case 0: break;
|
---|
432 | case 1: u32B = (u32B << 8) | (uInitialValue & UINT32_C(0x000000ff)); break;
|
---|
433 | case 2: u32B = (u32B << 16) | (uInitialValue & UINT32_C(0x0000ffff)); break;
|
---|
434 | case 3: u32B = (u32B << 24) | (uInitialValue & UINT32_C(0x00ffffff)); break;
|
---|
435 |
|
---|
436 | }
|
---|
437 | if (u32B != u32A)
|
---|
438 | {
|
---|
439 | static const char * const s_apsz[] =
|
---|
440 | {
|
---|
441 | "unaligned dword -3", "unaligned dword -2", "unaligned dword -1",
|
---|
442 | "unaligned dword 0", "unaligned dword 1", "unaligned dword 2", "unaligned dword 3"
|
---|
443 | };
|
---|
444 | pszError = s_apsz[iByte + 3];
|
---|
445 | break;
|
---|
446 | }
|
---|
447 |
|
---|
448 | }
|
---|
449 | }
|
---|
450 |
|
---|
451 | ASMSetFlags(fFlags);
|
---|
452 | ASMNopPause();
|
---|
453 | } /* try loop */
|
---|
454 |
|
---|
455 | /*
|
---|
456 | * Complain on failure.
|
---|
457 | */
|
---|
458 | if (!fDone)
|
---|
459 | LogRel(("TestOhciReads: Warning! Register %s was never stable enough for testing! %08RX32 %08RX32 %08RX32\n",
|
---|
460 | g_apszRegNms[iReg], uInitialValue, u32A, u32C));
|
---|
461 | else if (pszError)
|
---|
462 | {
|
---|
463 | LogRel(("TestOhciReads: Error! Register %s failed: %s; uInitialValue=%08RX32 u32B=%08RX32\n",
|
---|
464 | g_apszRegNms[iReg], pszError, uInitialValue, u32B));
|
---|
465 | fSuccess = false;
|
---|
466 | }
|
---|
467 | }
|
---|
468 |
|
---|
469 | return fSuccess;
|
---|
470 | }
|
---|
471 |
|
---|
472 |
|
---|
473 | int tstOhciRegisterAccess(RTHCPHYS HCPhysOHCI)
|
---|
474 | {
|
---|
475 | LogRel(("tstOhciRegisterAccess: HCPhysOHCI=%RHp\n", HCPhysOHCI));
|
---|
476 |
|
---|
477 | /*
|
---|
478 | * Map the OHCI registers so we can access them.
|
---|
479 | */
|
---|
480 | RTR0MEMOBJ hMemObj;
|
---|
481 | int rc = RTR0MemObjEnterPhys(&hMemObj, HCPhysOHCI, PAGE_SIZE, RTMEM_CACHE_POLICY_MMIO);
|
---|
482 | if (RT_FAILURE(rc))
|
---|
483 | {
|
---|
484 | LogRel(("tstOhciRegisterAccess: Failed to enter OHCI memory at %RHp: %Rrc\n", HCPhysOHCI, rc));
|
---|
485 | return rc;
|
---|
486 | }
|
---|
487 | RTR0MEMOBJ hMapObj;
|
---|
488 | rc = RTR0MemObjMapKernel(&hMapObj, hMemObj, (void *)-1, 0 /*uAlignment*/, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
|
---|
489 | if (RT_SUCCESS(rc))
|
---|
490 | {
|
---|
491 | RTVPTRUNION uPtr;
|
---|
492 | uPtr.pv = (void volatile *)RTR0MemObjAddress(hMapObj);
|
---|
493 | LogRel(("tstOhciRegisterAccess: mapping address %p\n", uPtr.pv));
|
---|
494 | if (RT_VALID_PTR(uPtr.pv))
|
---|
495 | {
|
---|
496 | LogRel(("tstOhciRegisterAccess: HcRevision=%#x\n", *uPtr.pu32));
|
---|
497 |
|
---|
498 | /*
|
---|
499 | * Do the access tests.
|
---|
500 | */
|
---|
501 | bool fSuccess = TestOhciReads(uPtr);
|
---|
502 | if (fSuccess)
|
---|
503 | fSuccess = TestOhciReadOnly(uPtr);
|
---|
504 | if (fSuccess)
|
---|
505 | fSuccess = TestOhciWrites(uPtr);
|
---|
506 | if (fSuccess)
|
---|
507 | LogRel(("tstOhciRegisterAccess: Success!\n"));
|
---|
508 | else
|
---|
509 | LogRel(("tstOhciRegisterAccess: Failed!\n"));
|
---|
510 | }
|
---|
511 | else
|
---|
512 | rc = VERR_INTERNAL_ERROR_2;
|
---|
513 |
|
---|
514 | /*
|
---|
515 | * Clean up.
|
---|
516 | */
|
---|
517 | RTR0MemObjFree(hMapObj, false);
|
---|
518 | }
|
---|
519 | else
|
---|
520 | LogRel(("tstOhciRegisterAccess: Failed to map OHCI memory at %RHp: %Rrc\n", HCPhysOHCI, rc));
|
---|
521 | RTR0MemObjFree(hMemObj, false);
|
---|
522 | LogRel(("tstOhciRegisterAccess: returns %Rrc\n", rc));
|
---|
523 | return rc;
|
---|
524 | }
|
---|