1 | /* $Id: tstOhciRegisterAccess.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
|
---|
2 | /** @file
|
---|
3 | * tstOhciRegisterAccess - OHCI Register Access Tests / Experiments.
|
---|
4 | */
|
---|
5 |
|
---|
6 | /*
|
---|
7 | * Copyright (C) 2011-2020 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 fMask;
|
---|
79 | uint32_t uVal1;
|
---|
80 | uint32_t uVal2;
|
---|
81 | } const s_aRegs[] =
|
---|
82 | {
|
---|
83 | #if 0 /* deadly when missing bytes are taken as zero. */
|
---|
84 | { 13 /* HcFmInterval */, 0xffffffff, 0x58871120, 0x01010101 },
|
---|
85 | #endif
|
---|
86 | { 16 /* HcPeriodicStart */, 0x00003fff, 0x01020304, 0x02010403 },
|
---|
87 | { 17 /* HcLSThreshold */, 0x00000fff, 0xffffffff, 0x66666666 },
|
---|
88 | { 10 /* HcBulkHeadED */, 0xfffffff0, 0xffffffff, 0xfefefef8 }, /* a bit risky... */
|
---|
89 | { 11 /* HcBulkCurrentED */, 0xfffffff0, 0xffffffff, 0xfefefef8 }, /* a bit risky... */
|
---|
90 | };
|
---|
91 |
|
---|
92 | bool fSuccess = true;
|
---|
93 | for (unsigned i = 0; i < RT_ELEMENTS(s_aRegs); i++)
|
---|
94 | {
|
---|
95 | uint32_t const iReg = s_aRegs[i].iReg;
|
---|
96 | RTVPTRUNION uPtrReg;
|
---|
97 | uPtrReg.pu32 = &uPtr.pu32[iReg];
|
---|
98 |
|
---|
99 | uint32_t uInitialValue = *uPtrReg.pu32;
|
---|
100 | LogRel(("TestOhciWrites: %p iReg=%2d %20s = %08RX32\n", uPtrReg.pv, iReg, g_apszRegNms[iReg], uInitialValue));
|
---|
101 |
|
---|
102 | bool fTryAgain = true;
|
---|
103 | const char *pszError = NULL;
|
---|
104 | uint32_t u32A = 0;
|
---|
105 | uint32_t uChangedValue = 0;
|
---|
106 | uint32_t uExpectedValue = 0;
|
---|
107 |
|
---|
108 | for (uint32_t iTry = 0; fTryAgain && iTry < 1024; iTry++)
|
---|
109 | {
|
---|
110 | pszError = NULL;
|
---|
111 | fTryAgain = false;
|
---|
112 | u32A = 0;
|
---|
113 | uChangedValue = 0;
|
---|
114 | uExpectedValue = 0;
|
---|
115 |
|
---|
116 | RTCCUINTREG const fFlags = ASMIntDisableFlags();
|
---|
117 | uInitialValue = *uPtrReg.pu32;
|
---|
118 |
|
---|
119 | /*
|
---|
120 | * DWORD writes.
|
---|
121 | */
|
---|
122 | if ((fTryAgain = (*uPtrReg.pu32 != uInitialValue)))
|
---|
123 | break;
|
---|
124 | *uPtrReg.pu32 = uInitialValue;
|
---|
125 | u32A = *uPtrReg.pu32;
|
---|
126 | uChangedValue = s_aRegs[i].uVal1 != uInitialValue ? s_aRegs[i].uVal1 : s_aRegs[i].uVal2;
|
---|
127 | if (u32A == uInitialValue)
|
---|
128 | {
|
---|
129 | /* Change the value. */
|
---|
130 | *uPtrReg.pu32 = uChangedValue;
|
---|
131 | u32A = *uPtrReg.pu32;
|
---|
132 | *uPtrReg.pu32 = uInitialValue;
|
---|
133 | uExpectedValue = uChangedValue & s_aRegs[i].fMask;
|
---|
134 | if (u32A != uExpectedValue)
|
---|
135 | pszError = "Writing changed value failed";
|
---|
136 | else
|
---|
137 | {
|
---|
138 | u32A = *uPtrReg.pu32;
|
---|
139 | if (u32A != uInitialValue)
|
---|
140 | pszError = "Restore error 1";
|
---|
141 | }
|
---|
142 | }
|
---|
143 | else
|
---|
144 | pszError = "Writing back initial value failed";
|
---|
145 |
|
---|
146 | /*
|
---|
147 | * Write aligned word changes.
|
---|
148 | */
|
---|
149 | for (unsigned iWord = 0; iWord < 2 && !pszError && !fTryAgain; iWord++)
|
---|
150 | {
|
---|
151 | if ((fTryAgain = (*uPtrReg.pu32 != uInitialValue)))
|
---|
152 | break;
|
---|
153 |
|
---|
154 | /* Change the value. */
|
---|
155 | uPtrReg.pu16[iWord] = (uint16_t)(uChangedValue >> iWord * 16);
|
---|
156 | u32A = *uPtrReg.pu32;
|
---|
157 | *uPtrReg.pu32 = uInitialValue;
|
---|
158 | uExpectedValue = (uChangedValue & UINT32_C(0xffff) << iWord * 16) & s_aRegs[i].fMask;
|
---|
159 | if (u32A != uExpectedValue)
|
---|
160 | {
|
---|
161 | static const char * const s_apsz[] = { "word 0", "word 1" };
|
---|
162 | pszError = s_apsz[iWord];
|
---|
163 | }
|
---|
164 | else
|
---|
165 | {
|
---|
166 | u32A = *uPtrReg.pu32;
|
---|
167 | if (u32A != uInitialValue)
|
---|
168 | pszError = "Restore error 2";
|
---|
169 | }
|
---|
170 | }
|
---|
171 |
|
---|
172 | /*
|
---|
173 | * Write aligned word change. We have to keep within the register,
|
---|
174 | * unfortunately.
|
---|
175 | */
|
---|
176 | if (!pszError && !fTryAgain)
|
---|
177 | {
|
---|
178 | fTryAgain = *uPtrReg.pu32 != uInitialValue;
|
---|
179 | if (!fTryAgain)
|
---|
180 | {
|
---|
181 | /* Change the value. */
|
---|
182 | *(uint16_t volatile *)&uPtrReg.pu8[1] = (uint16_t)(uChangedValue >> 8);
|
---|
183 | u32A = *uPtrReg.pu32;
|
---|
184 | *uPtrReg.pu32 = uInitialValue;
|
---|
185 | uExpectedValue = (uChangedValue & UINT32_C(0x00ffff00)) & s_aRegs[i].fMask;
|
---|
186 | if (u32A != uExpectedValue)
|
---|
187 | pszError = "Unaligned word access";
|
---|
188 | else
|
---|
189 | {
|
---|
190 | u32A = *uPtrReg.pu32;
|
---|
191 | if (u32A != uInitialValue)
|
---|
192 | pszError = "Restore error 3";
|
---|
193 | }
|
---|
194 | }
|
---|
195 | }
|
---|
196 |
|
---|
197 | /*
|
---|
198 | * Write byte changes.
|
---|
199 | */
|
---|
200 | for (unsigned iByte = 0; iByte < 4 && !pszError && !fTryAgain; iByte++)
|
---|
201 | {
|
---|
202 | if ((fTryAgain = (*uPtrReg.pu32 != uInitialValue)))
|
---|
203 | break;
|
---|
204 |
|
---|
205 | /* Change the value. */
|
---|
206 | uPtrReg.pu8[iByte] = (uint8_t)(uChangedValue >> iByte * 8);
|
---|
207 | u32A = *uPtrReg.pu32;
|
---|
208 | *uPtrReg.pu32 = uInitialValue;
|
---|
209 | uExpectedValue = (uChangedValue & UINT32_C(0xff) << iByte * 8) & s_aRegs[i].fMask;
|
---|
210 | if (u32A != uExpectedValue)
|
---|
211 | {
|
---|
212 | static const char * const s_apsz[] = { "byte 0", "byte 1", "byte 2", "byte 3" };
|
---|
213 | pszError = s_apsz[iByte];
|
---|
214 | }
|
---|
215 | else
|
---|
216 | {
|
---|
217 | u32A = *uPtrReg.pu32;
|
---|
218 | if (u32A != uInitialValue)
|
---|
219 | pszError = "Restore error 4";
|
---|
220 | }
|
---|
221 | }
|
---|
222 |
|
---|
223 | ASMSetFlags(fFlags);
|
---|
224 | ASMNopPause();
|
---|
225 | }
|
---|
226 |
|
---|
227 | /*
|
---|
228 | * Complain on failure.
|
---|
229 | */
|
---|
230 | if (fTryAgain)
|
---|
231 | LogRel(("TestOhciWrites: Warning! Register %s was never stable enough for testing! %08RX32 %08RX32 %08RX32\n",
|
---|
232 | g_apszRegNms[iReg], uInitialValue, u32A, uChangedValue, uInitialValue));
|
---|
233 | else if (pszError)
|
---|
234 | {
|
---|
235 | LogRel(("TestOhciWrites: Error! Register %s failed: %s; Initial=%08RX32 Changed=%08RX32 Expected=%08RX32 u32A=%08RX32\n",
|
---|
236 | g_apszRegNms[iReg], pszError, uInitialValue, uChangedValue, uExpectedValue, u32A));
|
---|
237 | fSuccess = false;
|
---|
238 | }
|
---|
239 | }
|
---|
240 |
|
---|
241 | return fSuccess;
|
---|
242 | }
|
---|
243 |
|
---|
244 |
|
---|
245 | static bool TestOhciReadOnly(RTVPTRUNION uPtr)
|
---|
246 | {
|
---|
247 | static struct
|
---|
248 | {
|
---|
249 | unsigned iReg;
|
---|
250 | uint32_t cValues;
|
---|
251 | uint32_t auValues[8];
|
---|
252 | } const s_aRegs[] =
|
---|
253 | {
|
---|
254 | { 0 /* HcRevision */, 8, { 0, UINT32_MAX, 0x10100110, 0x200, 0x111, 0x11f, 0xf110, 0x0f10 } },
|
---|
255 | { 12 /* HcDoneHead */, 3, { 0, UINT32_MAX, 0x55555555, 0, 0, 0, 0, 0 } },
|
---|
256 | { 14 /* HcFmRemaining */, 3, { 0, UINT32_MAX, 0x55555555, 0, 0, 0, 0, 0 } },
|
---|
257 | { 15 /* HcFmNumber */, 5, { 0, UINT32_MAX, 0x55555555, 0x7899, 0x00012222, 0, 0, 0 } },
|
---|
258 | #if 0 /* HCD can write this */
|
---|
259 | { 17 /* HcLSThreshold */, 5, { 0x627, 0x628, 0x629, 0x666, 0x599, 0, 0, 0 } } /* ??? */
|
---|
260 | #endif
|
---|
261 | };
|
---|
262 |
|
---|
263 | bool fSuccess = true;
|
---|
264 | for (unsigned i = 0; i < RT_ELEMENTS(s_aRegs); i++)
|
---|
265 | {
|
---|
266 | uint32_t const iReg = s_aRegs[i].iReg;
|
---|
267 | RTVPTRUNION uPtrReg;
|
---|
268 | uPtrReg.pu32 = &uPtr.pu32[iReg];
|
---|
269 |
|
---|
270 | uint32_t uInitialValue = *uPtrReg.pu32;
|
---|
271 | LogRel(("TestOhciReadOnly: %p iReg=%2d %20s = %08RX32\n", uPtrReg.pv, iReg, g_apszRegNms[iReg], uInitialValue));
|
---|
272 |
|
---|
273 | bool fTryAgain = true;
|
---|
274 | const char *pszError = NULL;
|
---|
275 | uint32_t uChangedValue = 0;
|
---|
276 | uint32_t u32A = 0;
|
---|
277 |
|
---|
278 | for (uint32_t iTry = 0; fTryAgain && iTry < 1024; iTry++)
|
---|
279 | {
|
---|
280 | pszError = NULL;
|
---|
281 | fTryAgain = false;
|
---|
282 | u32A = 0;
|
---|
283 | uChangedValue = 0;
|
---|
284 |
|
---|
285 | RTCCUINTREG const fFlags = ASMIntDisableFlags();
|
---|
286 | uInitialValue = *uPtrReg.pu32;
|
---|
287 |
|
---|
288 | /*
|
---|
289 | * Try aligned dword, word and byte writes for now.
|
---|
290 | */
|
---|
291 | for (unsigned iValue = 0; iValue < s_aRegs[i].cValues && !pszError && !fTryAgain; iValue++)
|
---|
292 | {
|
---|
293 | uChangedValue = s_aRegs[i].auValues[iValue];
|
---|
294 | if (uInitialValue == uChangedValue)
|
---|
295 | continue;
|
---|
296 |
|
---|
297 | /* dword */
|
---|
298 | if ((fTryAgain = (*uPtrReg.pu32 != uInitialValue)))
|
---|
299 | break;
|
---|
300 |
|
---|
301 | *uPtrReg.pu32 = uChangedValue;
|
---|
302 | u32A = *uPtrReg.pu32;
|
---|
303 | *uPtrReg.pu32 = uInitialValue;
|
---|
304 | if (u32A != uInitialValue)
|
---|
305 | pszError = "dword access";
|
---|
306 | else
|
---|
307 | {
|
---|
308 | u32A = *uPtrReg.pu32;
|
---|
309 | if (u32A != uInitialValue)
|
---|
310 | pszError = "Restore error 1";
|
---|
311 | }
|
---|
312 |
|
---|
313 | /* word */
|
---|
314 | for (unsigned iWord = 0; iWord < 2 && !pszError && !fTryAgain; iWord++)
|
---|
315 | {
|
---|
316 | if ((fTryAgain = (*uPtrReg.pu32 != uInitialValue)))
|
---|
317 | break;
|
---|
318 | uPtrReg.pu16[iWord] = (uint16_t)(uChangedValue >> iWord * 16);
|
---|
319 | u32A = *uPtrReg.pu32;
|
---|
320 | *uPtrReg.pu32 = uInitialValue;
|
---|
321 | if (u32A != uInitialValue)
|
---|
322 | pszError = iWord == 0 ? "aligned word 0 access" : "aligned word 1 access";
|
---|
323 | else
|
---|
324 | {
|
---|
325 | u32A = *uPtrReg.pu32;
|
---|
326 | if (u32A != uInitialValue)
|
---|
327 | pszError = "Restore error 2";
|
---|
328 | }
|
---|
329 | }
|
---|
330 |
|
---|
331 | /* byte */
|
---|
332 | for (unsigned iByte = 0; iByte < 4 && !pszError && !fTryAgain; iByte++)
|
---|
333 | {
|
---|
334 | if ((fTryAgain = (*uPtrReg.pu32 != uInitialValue)))
|
---|
335 | break;
|
---|
336 | uPtrReg.pu8[iByte] = (uint8_t)(uChangedValue >> iByte * 8);
|
---|
337 | u32A = *uPtrReg.pu32;
|
---|
338 | *uPtrReg.pu32 = uInitialValue;
|
---|
339 | if (u32A != uInitialValue)
|
---|
340 | {
|
---|
341 | static const char * const s_apsz[] = { "byte 0", "byte 1", "byte 2", "byte 3" };
|
---|
342 | pszError = s_apsz[iByte];
|
---|
343 | }
|
---|
344 | else
|
---|
345 | {
|
---|
346 | u32A = *uPtrReg.pu32;
|
---|
347 | if (u32A != uInitialValue)
|
---|
348 | pszError = "Restore error 3";
|
---|
349 | }
|
---|
350 | }
|
---|
351 | }
|
---|
352 |
|
---|
353 | ASMSetFlags(fFlags);
|
---|
354 | ASMNopPause();
|
---|
355 | }
|
---|
356 |
|
---|
357 | /*
|
---|
358 | * Complain on failure.
|
---|
359 | */
|
---|
360 | if (fTryAgain)
|
---|
361 | LogRel(("TestOhciReadOnly: Warning! Register %s was never stable enough for testing! %08RX32 %08RX32 %08RX32\n",
|
---|
362 | g_apszRegNms[iReg], uInitialValue, u32A, uChangedValue, uInitialValue));
|
---|
363 | else if (pszError)
|
---|
364 | {
|
---|
365 | LogRel(("TestOhciReadOnly: Error! Register %s failed: %s; uInitialValue=%08RX32 uChangedValue=%08RX32 u32A=%08RX32\n",
|
---|
366 | g_apszRegNms[iReg], pszError, uInitialValue, uChangedValue, u32A));
|
---|
367 | fSuccess = false;
|
---|
368 | }
|
---|
369 | }
|
---|
370 |
|
---|
371 | return fSuccess;
|
---|
372 | }
|
---|
373 |
|
---|
374 |
|
---|
375 | static bool TestOhciReads(RTVPTRUNION uPtr)
|
---|
376 | {
|
---|
377 | /*
|
---|
378 | * We can read just about any register we like since read shouldn't have
|
---|
379 | * any side effects. However, some registers are volatile and makes for
|
---|
380 | * difficult targets, thus the ugly code.
|
---|
381 | */
|
---|
382 | bool fSuccess = true;
|
---|
383 | uint32_t cMaxReg = RT_ELEMENTS(g_apszRegNms);
|
---|
384 | for (uint32_t iReg = 0; iReg < cMaxReg; iReg++, uPtr.pu32++)
|
---|
385 | {
|
---|
386 | const char *pszError = NULL;
|
---|
387 | bool fDone = false;
|
---|
388 | uint32_t uInitialValue = *uPtr.pu32;
|
---|
389 | uint32_t u32A = 0;
|
---|
390 | uint32_t u32B = 0;
|
---|
391 | uint32_t u32C = 0;
|
---|
392 | LogRel(("TestOhciReads: %p iReg=%2d %20s = %08RX32\n", uPtr.pv, iReg, g_apszRegNms[iReg], uInitialValue));
|
---|
393 |
|
---|
394 | for (uint32_t iTry = 0; !fDone && iTry < 1024; iTry++)
|
---|
395 | {
|
---|
396 | pszError = NULL;
|
---|
397 | fDone = true;
|
---|
398 | u32A = u32B = u32C = 0;
|
---|
399 |
|
---|
400 | RTCCUINTREG const fFlags = ASMIntDisableFlags();
|
---|
401 | uInitialValue = *uPtr.pu32;
|
---|
402 |
|
---|
403 | /* Test byte access. */
|
---|
404 | for (unsigned iByte = 0; iByte < 4; iByte++)
|
---|
405 | {
|
---|
406 | u32A = *uPtr.pu32;
|
---|
407 | u32B = uPtr.pu8[iByte];
|
---|
408 | u32C = *uPtr.pu32;
|
---|
409 | if (u32A != uInitialValue || u32C != uInitialValue)
|
---|
410 | {
|
---|
411 | fDone = false;
|
---|
412 | break;
|
---|
413 | }
|
---|
414 |
|
---|
415 | static uint32_t const a_au32Masks[] =
|
---|
416 | {
|
---|
417 | UINT32_C(0xffffff00), UINT32_C(0xffff00ff), UINT32_C(0xff00ffff), UINT32_C(0x00ffffff)
|
---|
418 | };
|
---|
419 | u32B <<= iByte * 8;
|
---|
420 | u32B |= uInitialValue & a_au32Masks[iByte];
|
---|
421 | if (u32B != uInitialValue)
|
---|
422 | {
|
---|
423 | static const char * const s_apsz[] = { "byte 0", "byte 1", "byte 2", "byte 3" };
|
---|
424 | pszError = s_apsz[iByte];
|
---|
425 | break;
|
---|
426 | }
|
---|
427 | }
|
---|
428 |
|
---|
429 | /* Test aligned word access. */
|
---|
430 | if (fDone)
|
---|
431 | {
|
---|
432 | for (unsigned iWord = 0; iWord < 2; iWord++)
|
---|
433 | {
|
---|
434 | u32A = *uPtr.pu32;
|
---|
435 | u32B = uPtr.pu16[iWord];
|
---|
436 | u32C = *uPtr.pu32;
|
---|
437 | if (u32A != uInitialValue || u32C != uInitialValue)
|
---|
438 | {
|
---|
439 | fDone = false;
|
---|
440 | break;
|
---|
441 | }
|
---|
442 |
|
---|
443 | u32B <<= iWord * 16;
|
---|
444 | u32B |= uInitialValue & (iWord == 0 ? UINT32_C(0xffff0000) : UINT32_C(0x0000ffff));
|
---|
445 | if (u32B != uInitialValue)
|
---|
446 | {
|
---|
447 | pszError = iWord == 0 ? "aligned word 0 access" : "aligned word 1 access";
|
---|
448 | break;
|
---|
449 | }
|
---|
450 | }
|
---|
451 | }
|
---|
452 |
|
---|
453 | /* Test unaligned word access. */
|
---|
454 | if (fDone)
|
---|
455 | {
|
---|
456 | for (int iWord = ((uintptr_t)uPtr.pv & PAGE_OFFSET_MASK) == 0; iWord < 3; iWord++)
|
---|
457 | {
|
---|
458 | u32A = *uPtr.pu32;
|
---|
459 | u32B = *(volatile uint16_t *)&uPtr.pu8[iWord * 2 - 1];
|
---|
460 | u32C = *uPtr.pu32;
|
---|
461 | if (u32A != uInitialValue || u32C != uInitialValue)
|
---|
462 | {
|
---|
463 | fDone = false;
|
---|
464 | break;
|
---|
465 | }
|
---|
466 |
|
---|
467 | switch (iWord)
|
---|
468 | {
|
---|
469 | case 0: u32B = (u32B >> 8) | (u32A & UINT32_C(0xffffff00)); break;
|
---|
470 | case 1: u32B = (u32B << 8) | (u32A & UINT32_C(0xff0000ff)); break;
|
---|
471 | case 2: u32B = (u32B << 24) | (u32A & UINT32_C(0x00ffffff)); break;
|
---|
472 | }
|
---|
473 | if (u32B != u32A)
|
---|
474 | {
|
---|
475 | static const char * const s_apsz[] = { "unaligned word 0", "unaligned word 1", "unaligned word 2" };
|
---|
476 | pszError = s_apsz[iWord];
|
---|
477 | break;
|
---|
478 | }
|
---|
479 | }
|
---|
480 | }
|
---|
481 |
|
---|
482 | /* Test unaligned dword access. */
|
---|
483 | if (fDone)
|
---|
484 | {
|
---|
485 | for (int iByte = ((uintptr_t)uPtr.pv & PAGE_OFFSET_MASK) == 0 ? 0 : -3; iByte < 4; iByte++)
|
---|
486 | {
|
---|
487 | u32A = *uPtr.pu32;
|
---|
488 | u32B = *(volatile uint32_t *)&uPtr.pu8[iByte];
|
---|
489 | u32C = *uPtr.pu32;
|
---|
490 | if (u32A != uInitialValue || u32C != uInitialValue)
|
---|
491 | {
|
---|
492 | fDone = false;
|
---|
493 | break;
|
---|
494 | }
|
---|
495 |
|
---|
496 | switch (iByte)
|
---|
497 | {
|
---|
498 | case -3: u32B = (u32B >> 24) | (uInitialValue & UINT32_C(0xffffff00)); break;
|
---|
499 | case -2: u32B = (u32B >> 16) | (uInitialValue & UINT32_C(0xffff0000)); break;
|
---|
500 | case -1: u32B = (u32B >> 8) | (uInitialValue & UINT32_C(0xff000000)); break;
|
---|
501 | case 0: break;
|
---|
502 | case 1: u32B = (u32B << 8) | (uInitialValue & UINT32_C(0x000000ff)); break;
|
---|
503 | case 2: u32B = (u32B << 16) | (uInitialValue & UINT32_C(0x0000ffff)); break;
|
---|
504 | case 3: u32B = (u32B << 24) | (uInitialValue & UINT32_C(0x00ffffff)); break;
|
---|
505 |
|
---|
506 | }
|
---|
507 | if (u32B != u32A)
|
---|
508 | {
|
---|
509 | static const char * const s_apsz[] =
|
---|
510 | {
|
---|
511 | "unaligned dword -3", "unaligned dword -2", "unaligned dword -1",
|
---|
512 | "unaligned dword 0", "unaligned dword 1", "unaligned dword 2", "unaligned dword 3"
|
---|
513 | };
|
---|
514 | pszError = s_apsz[iByte + 3];
|
---|
515 | break;
|
---|
516 | }
|
---|
517 |
|
---|
518 | }
|
---|
519 | }
|
---|
520 |
|
---|
521 | ASMSetFlags(fFlags);
|
---|
522 | ASMNopPause();
|
---|
523 | } /* try loop */
|
---|
524 |
|
---|
525 | /*
|
---|
526 | * Complain on failure.
|
---|
527 | */
|
---|
528 | if (!fDone)
|
---|
529 | LogRel(("TestOhciReads: Warning! Register %s was never stable enough for testing! %08RX32 %08RX32 %08RX32\n",
|
---|
530 | g_apszRegNms[iReg], uInitialValue, u32A, u32C));
|
---|
531 | else if (pszError)
|
---|
532 | {
|
---|
533 | LogRel(("TestOhciReads: Error! Register %s failed: %s; uInitialValue=%08RX32 u32B=%08RX32\n",
|
---|
534 | g_apszRegNms[iReg], pszError, uInitialValue, u32B));
|
---|
535 | fSuccess = false;
|
---|
536 | }
|
---|
537 | }
|
---|
538 |
|
---|
539 | return fSuccess;
|
---|
540 | }
|
---|
541 |
|
---|
542 |
|
---|
543 | int tstOhciRegisterAccess(RTHCPHYS HCPhysOHCI)
|
---|
544 | {
|
---|
545 | LogRel(("tstOhciRegisterAccess: HCPhysOHCI=%RHp\n", HCPhysOHCI));
|
---|
546 |
|
---|
547 | /*
|
---|
548 | * Map the OHCI registers so we can access them.
|
---|
549 | */
|
---|
550 | RTR0MEMOBJ hMemObj;
|
---|
551 | int rc = RTR0MemObjEnterPhys(&hMemObj, HCPhysOHCI, PAGE_SIZE, RTMEM_CACHE_POLICY_MMIO);
|
---|
552 | if (RT_FAILURE(rc))
|
---|
553 | {
|
---|
554 | LogRel(("tstOhciRegisterAccess: Failed to enter OHCI memory at %RHp: %Rrc\n", HCPhysOHCI, rc));
|
---|
555 | return rc;
|
---|
556 | }
|
---|
557 | RTR0MEMOBJ hMapObj;
|
---|
558 | rc = RTR0MemObjMapKernel(&hMapObj, hMemObj, (void *)-1, 0 /*uAlignment*/, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
|
---|
559 | if (RT_SUCCESS(rc))
|
---|
560 | {
|
---|
561 | RTVPTRUNION uPtr;
|
---|
562 | uPtr.pv = (void volatile *)RTR0MemObjAddress(hMapObj);
|
---|
563 | LogRel(("tstOhciRegisterAccess: mapping address %p\n", uPtr.pv));
|
---|
564 | if (RT_VALID_PTR(uPtr.pv))
|
---|
565 | {
|
---|
566 | LogRel(("tstOhciRegisterAccess: HcRevision=%#x\n", *uPtr.pu32));
|
---|
567 |
|
---|
568 | /*
|
---|
569 | * Do the access tests.
|
---|
570 | */
|
---|
571 | bool fSuccess = TestOhciReads(uPtr);
|
---|
572 | if (fSuccess)
|
---|
573 | fSuccess = TestOhciReadOnly(uPtr);
|
---|
574 | if (fSuccess)
|
---|
575 | fSuccess = TestOhciWrites(uPtr);
|
---|
576 | if (fSuccess)
|
---|
577 | LogRel(("tstOhciRegisterAccess: Success!\n"));
|
---|
578 | else
|
---|
579 | LogRel(("tstOhciRegisterAccess: Failed!\n"));
|
---|
580 | }
|
---|
581 | else
|
---|
582 | rc = VERR_INTERNAL_ERROR_2;
|
---|
583 |
|
---|
584 | /*
|
---|
585 | * Clean up.
|
---|
586 | */
|
---|
587 | RTR0MemObjFree(hMapObj, false);
|
---|
588 | }
|
---|
589 | else
|
---|
590 | LogRel(("tstOhciRegisterAccess: Failed to map OHCI memory at %RHp: %Rrc\n", HCPhysOHCI, rc));
|
---|
591 | RTR0MemObjFree(hMemObj, false);
|
---|
592 | LogRel(("tstOhciRegisterAccess: returns %Rrc\n", rc));
|
---|
593 | return rc;
|
---|
594 | }
|
---|