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