OAL Kernel Mode Interrupt Tests (Compact 7)
3/12/2014
The OAL Interrupt Tests assess the behavior of interrupt-related I/O controls (IOCTLs) in the OEM Adaptation Layer (OAL). The tests verify that the IOCTLs process parameters correctly and that the return values are correct.
The OAL Interrupt Tests exercise the following IOCTLs:
IOCTL_HAL_REQUEST_SYSINTR
IOCTL_HAL_RELEASE_SYSINTR
IOCTL_HAL_REQUEST_IRQ
You can achieve good test coverage of interrupts using the following OAL tests:
* OAL Interrupt Tests
* OAL Timer Tests
* OAL KITL Tests
Note the following points regarding this test:
* Interrupt testing cannot be isolated from the device drivers that use these interrupts or from the timer routines that use the system tick.
* The allocation and release tests can run on any image. These tests must be signed so that they have low level access to the interrupt IOCTL routines.
* IRQ ranges are used throughout the code. The default ranges are currently set from 0 to 1024. For some of the tests, the IRQ range can be set by the command line arguments. All IRQ ranges are inclusive, unless specified otherwise.
* The IOCTLs should only be called in Kernel mode. In user mode the kernel should prevent the OAL code from even being called. The test is run in user mode to confirm that none of the calls complete successfully.
* The IOCTL test code has numerous internal checks that confirm that the correct data is returned. Two important ones:
* Valid SYSINTRs: Valid SYSINTRs must be between [0, 71]. Anything else is an error.
* Number of free SYSINTRs before and after the test: The tests are designed to leave the system in the state that they found it in. This can be confirmed by comparing the number of free SYSINTRs before and after the test. This helps catch errors both on the tests and errors in the routines themselves.
* "Extended flag structure" allows the OAL_INTR_* flags to specify more actions to the IOCTLs.
* Since the interrupt routines control essential system behavior, trashed tables that map the IRQs to SYSINTRs generally lead to system instability and crashes. This means that the pedantic user would run each test case individually to eliminate risk of adjacent test cases impacting test results. As part of the CTK, these tests are run in two passes: kernel mode and user mode (these require different command lines). A failure in the test will normally break all of the others. This needs be noted by anyone looking at CTK results.
Test Prerequisites
Your device must meet the following requirements before you run this test.
* The OAL must implement IOCTL_HAL_REQUEST_SYSINTR IOCTL.
The following table shows the software requirements for the test:
Requirements | Description |
---|---|
Tux.exe |
Tux test harness, required for executing the test |
ktux.dll |
Required for running tests in kernel mode |
kato.dll |
Kato logging engine, required for logging test data |
oaltestinterrupts.dll |
Library containing OAL interrupt tests |
Subtests
The table below lists the subtests included in this test.
SubTest ID | Description |
---|---|
500 |
IOCTL_HAL_REQUEST_SYSINTR: Bad Input (Extended flag structure) - Incomplete Args IRQ Range: Command line or default Checks the following: * Null on both the in buf and out buffer * Inbound size of two DWORDs (in this case no IRQs were provided) |
510 |
IOCTL_HAL_REQUEST_SYSINTR: Bad Input (Extended flag structure) - Bad Input Sizes IRQ Range: Command or default Inbound structure must be DWORDs, so length much always be a multiple of four. Furthemore, it must always be > 2 DWORDs, or 8 bytes. Confirm this up to an arbitrary 32 bytes. |
520 |
IOCTL_HAL_REQUEST_SYSINTR: Bad Input Size IRQ Range: Command line or default Confirm that anything except for 4 bytes causes a failure. |
530 |
IOCTL_HAL_REQUEST_SYSINTR: Bad Flags IRQ Range: Command line or default Test works from 0 to 256, skipping the valid flags (OAL_INTR_TRANSLATE, OAL_INTR_STATIC, OAL_INTR_DYNAMIC, OAL_INTR_FORCE_STATIC). |
540 |
IOCTL_HAL_REQUEST_SYSINTR: Bad Out Size (Extended flag structure) IRQ Range: Command line or default Any size less than 4 bytes causes failure. Note that only 4 bytes is needed for output. If given more, the IOCTL just ignores it. |
550 |
IOCTL_HAL_REQUEST_SYSINTR: Bad Out Size IRQ Range: Command line or default Any size less than 4 bytes causes failure. Note that only 4 bytes is needed for output. If given more, the IOCTL just ignores it. |
600 |
IOCTL_HAL_RELEASE_SYSINTR: Bad Input Size IRQ Range: Command line or default Confirm that anything other than 4 bytes causes an error. This IOCTL passes no output. In this case the code is supposed to completely ignore the output values, include lpBytesReturned. |
1000 |
Free SYSINTRs that should not be freed Any SYSINTR less than 8 or greater than 71 is not valid. Freeing these should result in FALSE from the IOCTL and no change in the system. This test tries to release these SYSINTRs. Since releasing ~ 2^32 interrupts takes a long time, we hit the most likely values: * [0, 7] * [72, 256] * Boundaries of powers of two (plus/minus 1) * (-256, -1] (include SYSINTR_UNDEFINED = -1) * 10,000 random SYSINTR values between [72, 0xffff_ffff] |
1110 |
Parameter Checks: Good Out-Size (Extended flag structure) IRQ Range: Command line or default Any size greater than 4 bytes will work as output. This confirms that these values cause success to the IOCTL. |
1120 |
Parameter Checks: Good Out-Size IRQ Range: Command line or default Any size greater than 4 bytes will work as output. This confirms that these values cause success to the IOCTL. |
1130 |
Parameter Check: lpBytesReturned (Extended flag structure) IRQ Range: Command line or default Makes sure that lpBytesReturned is always 4 bytes. Calls the IOCTL with a successful call and confirm that lpBytesReturned is working correctly. Same at output size test cases 1110 and 1120, except that they pass lpBytesReturned to the IOCTL instead of NULL. |
1140 |
Parameter Check: lpBytesReturned IRQ Range: Command line or default Makes sure that lpBytesReturned is always 4 bytes. Calls the IOCTL with a successful call and confirm that lpBytesReturned is working correctly. Same at output size test cases 1110 and 1120, except that they pass lpBytesReturned to the IOCTL instead of NULL. |
1200 |
SYSINTR focused testing: Stress Unallocated SYSINTRs IRQ Range: Command line or default Exercises allocating and freeing SYSINTRs. Throughout all of these tests we must be careful not to free the wrong thing. Doing this incorrectly will lock up the system. We assume that anything that we allocate can be freed. Furthermore, if the system is quiescent and drivers are not loading and unloading, this SYSINTR should be free until we reallocate it. In other words, we can extrapolate the state of the system by targeted allocation and free scenarios. We assume that system will not reuse SYSINTRs; once a SYSINTR is allocated it won’t be reallocated until released. The test first establishes a list of SYSINTRs that are not currently allocated. These can then be allocated, freed, and double freed at will, without crashing the system. To gather this list the test allocates everything and tracks the SYSINTRs returned. After this process is completed, all of the SYSINTRs on the system have been fully allocated. For each SYSINTR in this list, the test then: 1. Releases it - this should be successful, since we just allocated it. 2. Releases it - this should fail since the routines won’t return a SYSINTR twice and we were the only person who allocated it. It should be free and releasing a free SYSINTR should fail. 3. Reallocates that IRQ - we store which IRQ was mapped to this SYSINTR. We then use the same IOCTL call to reallocate this IRQ. Since only one SYSINTR is available we should get the same SYSINTR back. 4. Reallocates it again - no SYSINTRs are available, so this call should fail. At this point, all of the SYSINTRs are still allocated. If the above was successful, the test next releases all of the SYSINTRs that it allocated. Each of these calls should be successful. The test then tries to release these SYSINTRs again. These should all fail, since these were unallocated SYSINTRs and should have no IRQs associated with them. Again, the above assumes that we don’t have two IRQs mapped to the same SYSINTR. This can’t be possible, since the underlying interrupt framework has no knowledge of which driver asked for a given mapping from an IRQ to a SYSINTR. The above process is repeated multiple times (probably five or so). After each run we compare the SYSINTR list that the test was working with. These should always be the same. If they aren’t, the interrupt routines are incorrect. This test can only be run in kernel mode. In user mode no allocations can be performed, so the critical initialization step of the test won’t work. The IRQ range does not matter much for this test. If the given IRQ can’t be allocated, the test moves onto the next one. As long as enough IRQs are available to consume all of the SYSINTRs the test will succeed. For this reason there is no In Range version of this test. |
1300 |
SYSINTR focused testing: Find Number of Free SYSINTRS IRQ Range: Command line or default Using the same general method used in case 1200, the number of free SYSINTRs can be found. The test starts working through the given IRQs, allocating as it goes along. Once all of the IRQs have been tried it counts how many were successfully allocated. Each allocation takes a separate SYSINTR, and this gives the number of SYSINTRs free before the tests started. The allocated SYSINTRs are freed before the test exits. This test can only be run in kernel mode. In user mode no allocations can be performed, so the critical initialization step of the test won’t work. The IRQ range does not matter much for this test. If the given IRQ can’t be allocated, the test moves onto the next one. As long as enough IRQs are available to consume all of the SYSINTRs the test will succeed. For this reason there is no In Range version of this test. |
1400 |
SYSINTR focused testing: Find Max IRQ per SYSINTR IRQ Range: Command line or default This test guesses at the largest number of IRQs per SYSINTR that the test supports. The algorithm works from 1 IRQ up to 10 IRQs. It randomly selects IRQs and tries to dynamically allocate them. If it can’t get a dynamic allocation with 100 tries, it decides that this number of IRQs can’t be supported. Therefore, one less than this is the number of IRQs supported on the system. The IRQ range can be specified by the user. This test requires the best available information concerning which IRQs are valid. This test is kernel mode only, because SYSINTRs must be allocated for it to determine the largest number of supported IRQs, and no SYSINTRs can be allocated in user mode. |
2000 |
Test case 2000: Single IRQ Allocations: Single IRQ Standard Alloc Test case 2100: Single IRQ Allocations: Single IRQ static Alloc Test case 2200: Single IRQ Allocations: Single IRQ dynamic Alloc Test case 3000: Single IRQ Allocations: Single IRQ Standard Alloc - In Range Test case 3100: Single IRQ Allocations: Single IRQ Static Alloc - In Range Test case 3200: Single IRQ Allocations: Single IRQ Dynamic Alloc - In Range IRQ Range: Command line or default Test cases 2000, 2100, 2200, 3100, and 3200 allocate every IRQ in the given IRQ list. The IRQ list is determined by the command line arguments and the version of the test. If the "In Range" version is used, the test uses either the command line args (-irqBeing and/or -irqEnd) or it uses the range from 0 to the largest possible IRQ that can be allocated. The test then confirms that in the dynamic case we can allocate a SYSINTR for a given IRQ. In the static case we can’t guarantee this. The standard (old) case is the legacy version of the call. This behaves just like dynamic. If the "In Range" version is not used, this tells the test to ignore the command line arguments and use the default IRQ range. This test provides coverage for the negative cases to the IOCTL. If the test relied only upon the command line args, it would exercise only those values that should work. The non-"In Range" version exercises IRQ values that should fail. |
2300 |
Single IRQ Allocations: Find Max Successfully Allocated IRQ IRQ Range: Command line or default, In Range Along with test case 3300, computes the maximum allocated IRQ on the system. This search is bounded by the default IRQ range (In Range), or by the IRQ range given by the command line arguments. The algorithm starts the maximum allowed IRQ in the given range and works down, trying to allocate each IRQ as dynamic. The first IRQ that can be allocated is designated the first and returned as such. Included is an "In Range" version so that the user, for debugging, can set the command line args for this test. |
3300 |
Single IRQ Allocations: Find Max Successfully Allocated IRQ - In Range IRQ Range: Command line or default, In Range Along with test case 3300, computes the maximum allocated IRQ on the system. This search is bounded by the default IRQ range (In Range), or by the IRQ range given by the command line arguments. The algorithm starts the maximum allowed IRQ in the given range and works down, trying to allocate each IRQ as dynamic. The first IRQ that can be allocated is designated the first and returned as such. Included is an "In Range" version so that the user, for debugging, can set the command line args for this test. |
4000 |
Test case 4000: Multiple IRQ Allocations: Mult IRQ Static Alloc Test case 4100: Multiple IRQ Allocations: Mult IRQ Dynamic Alloc Test case 4200: Multiple IRQ Allocations: Mult IRQ Force-Static Alloc Test case 5000: Multiple IRQ Allocations: Mult IRQ Static Alloc - In Range Test case 5100: Multiple IRQ Allocations: Mult IRQ Dynamic Alloc - In Range Test case 5200: Multiple IRQ Allocations: Mult IRQ Force-Static Alloc - In Range IRQ Range: Command line or default Test cases 4000, 4100, 4200, 5000, 5100, and 5200 randomly generate a set of IRQs for a given call. The IRQs come from the IRQ range (see discussion below). The number of IRQs passed to the IOCTL varies from 1 to the maximum number allowed on the system, as determined by the test. The test tries 100 different allocations for each number of IRQs. The IRQ list is determined by the command line arguments and the version of the test. If the "In Range" version is used, the test uses either the command line args (-irqBegin and/or -irqEnd) or it uses the range from 0 to the largest possible IRQ that can be allocated. If the non-"In Range" version is used, the test uses the default IRQ range. The IRQ range is important for this test. Since the IRQs sent to the IOCTL are generated randomly, it is quite possible that one is out of the supported IRQ range. In this case we would only be testing negative cases. No positive cases would be hit. Using the "In Range" model uses a range of IRQs that are much more likely to be valid. This forces positive cases into the mix, giving better coverage. The dynamic and static tests allocate the given set of IRQs, confirm that the SYSINTR returned is valid, and then release it. The also duplicate this IRQ list and confirm that the routines handle duplicate IRQs correctly. Duplicates are assumed to denote the one IRQ that is duplicated, and this isn’t an error to the IOCTL. If there are two IRQs passed to the IOCTL, the code duplicates the first IRQ (we preserve the number of IRQs for a given call). If there are more than two, the code alternates between the first two being used for the given test case. If you do get an error on these tests, the code will print the exact call made, so you can reconstruct it. The Force-Static allocation can change the operation of the IRQ to SYSINTR mappings already on the system. These changes could conceivably crash the system. The force-static tests work through the IRQs differently. After a potential IRQ list has been initialized, the test: 1. Allocates as static. If this does not succeed the IRQ list (or one of the IRQs) is not free and the test should not mark it as force-static. 2. Force-static on this IRQ list. This should succeed and furthermore should kick off the previous mapping, which now becomes dynamic. 3. Confirm that we did indeed allocate a new SYSINTR. 4. Cleanup; Release both SYSINTRs |
20010 |
IOCTL_HAL_REQUEST_IRQ: Incorrect Parameter Checks: Bad Input Size IRQ Range: Command line or default Confirm that any size not = sizeof (DEVICE_LOCATION) causes a failure. |
20020 |
IOCTL_HAL_REQUEST_IRQ: Incorrect Parameter Checks: Bad Output Size IRQ Range: Command line or default This IOCTL supports multiple IRQs on output. Bad inputs consist of outputBufSize < 4 bytes. The test code uses random values for the inbound structures, which unfortunately does not provide ideal coverage, since these random values would fail anyway. |
20100 |
IOCTL_HAL_REQUEST_IRQ: Random Request IRQ Range: Command line or default IOCTL_HAL_REQUEST_IRQ is used to hardcode certain DEVICE_LOCATION values to certain IRQs in the platform. This appears to be used only in PCI and serial kitl. The input is a DEVICE_LOCATION structure. The fields in this structure are compared against special cased values in the OAL. The return value is an IRQ. The input space is very large. Every platform seems to use different fields and have different values for these fields. Furthermore, the constants range all over the map. The "Random Request" test randomly selects values for the fields of the DEVICE_LOCATION structure. The goal is not to find a set of values that work with the IOCTL; rather, it is to try to cause a crash/memory access violation by sending in bad input. Note that the DEVICE_LOCATION structure also has a PhysicalLoc value. This is a PVOID and is reserved for future use, so is set to zero by our test. |
20200 |
IOCTL_HAL_REQUEST_IRQ: User Specified Params (see sub-test 20100) The "User Specified Params" test allows the user to pass in values to the IOCTL. These values do not necessarily cause the IOCTL to succeed. This test always passes, since the test has no idea what the user expects to happen with these arguments. Call the test with test arguments: -dev IfcType BusNumber LogicalLoc Pin Note that the DEVICE_LOCATION structure also has a PhysicalLoc value. This is a PVOID and is reserved for future use, so is set to zero by our test. |
Setting Up the Test
This test has no additional requirements, beyond the standard test environment setup.
Running the Test
The test performs the following during default execution: tux -o -n -d OalTestInterrupts.dll -x500-9999,20000-29999
The following table shows the command line parameters for the OAL Interrupt Tests.
Command-line parameter | Description |
---|---|
-irqEnd <n> |
Specifies the end of the inclusive IRQs on the device. Default is 1024. |
-irqBegin <n> |
Specifies the beginning of the inclusive range of IRQs on the device. Default is 0. |
-dev <values> |
Specifies the values for the DEVICE_LOCATION structure to be passed to IOCTL_HAL_REQUEST_IRQ. Can be ignored unless specifically needed. For more information, see the test case descriptions. |
Verifying the Test
When the test completes running, verify that "PASS" appears in the test log for all sub-tests.
Troubleshooting the Test
* Verify you are running the test in kernel mode, with the "-n" parameter provided on the command line.
* Verify how SYSINTRs are allocated and if there may be a leak.
* Verify the implementation of the SYSINTR IOCTLs in the OAL.
* On larger images; more IRQs may be reserved or used which could interfere with the test. Although the test has been designed to work with many IRQ configurations, some tests may be affected. Therefore, if the test fails, you may want to re-run it on a smaller run-time image with fewer potential IRQs in use.
* Determine the point of failure and record the exact error message. Check that the setup steps were followed and that all pre-requisites were met. If the source code is available, examine the point of failure in code to see if any additional information can be gathered about the failure domain.
For additional platform specific issues, consult the CTK articles on the TechNet wiki.