tests: port static_idt test to unified kernel

Change-Id: Ida4333b91ad322ff676cfbaa2ccaab0bdd38cd48
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
This commit is contained in:
Anas Nashif 2017-04-04 11:45:31 -04:00
commit 7a90ab448b
19 changed files with 107 additions and 467 deletions

View file

@ -1,4 +1,3 @@
MDEF_FILE = prj.mdef
BOARD ?= qemu_x86
CONF_FILE = prj.conf

View file

@ -0,0 +1,34 @@
Title: Static IDT Support
Description:
This test verifies that the static IDT feature operates as expected.
--------------------------------------------------------------------------------
Building and Running Project:
This project outputs to the console. It can be built and executed
on QEMU as follows:
make run
Sample Output:
tc_start() - Starting static IDT tests
Testing to see if IDT has address of test stubs()
Testing to see interrupt handler executes properly
Testing to see exception handler executes properly
Testing to see spurious handler executes properly
- Expect to see unhandled interrupt/exception message
***** Unhandled interrupt vector *****
Current thread ID = 0x001028e0
Faulting segment:address = 0x8:0x1001c9
eax: 0xa, ebx: 0x0, ecx: 0x1018e0, edx: 0xa
esi: 0x0, edi: 0x0, ebp: 01030b4, esp: 0x1030b4
eflags: 0x202
Fatal fault in thread 0x001028e0! Aborting.
PASS - main.
===================================================================
PROJECT EXECUTION SUCCESSFUL

View file

@ -1,2 +1,3 @@
CONFIG_EXCEPTION_DEBUG=n
CONFIG_LEGACY_KERNEL=y
CONFIG_MAIN_THREAD_PRIORITY=6

View file

@ -1,4 +1,3 @@
/* static_idt.c - test static IDT APIs */
/*
* Copyright (c) 2012-2014 Wind River Systems, Inc.
@ -6,9 +5,10 @@
* SPDX-License-Identifier: Apache-2.0
*/
/*
DESCRIPTION
Ensures interrupt and exception stubs are installed correctly.
/**
* @file
* test static IDT APIs
* Ensures interrupt and exception stubs are installed correctly.
*/
#include <zephyr.h>
@ -26,43 +26,48 @@ Ensures interrupt and exception stubs are installed correctly.
#define TEST_SOFT_INT 62
#define TEST_SPUR_INT 63
#define MY_STACK_SIZE 2048
#define MY_PRIORITY 5
char __noinit __stack my_stack_area[MY_STACK_SIZE];
/* externs */
/* the _idt_base_address symbol is generated via a linker script */
/* The _idt_base_address symbol is generated via a linker script */
extern unsigned char _idt_base_address[];
extern void *nanoIntStub;
NANO_CPU_INT_REGISTER(nanoIntStub, -1, -1, TEST_SOFT_INT, 0);
extern void *int_stub;
NANO_CPU_INT_REGISTER(int_stub, -1, -1, TEST_SOFT_INT, 0);
static volatile int excHandlerExecuted;
static volatile int intHandlerExecuted;
static volatile int exc_handler_executed;
static volatile int int_handler_executed;
/* Assume the spurious interrupt handler will execute and abort the task */
static volatile int spurHandlerAbortedThread = 1;
static volatile int spur_handler_aborted_thread = 1;
/**
* Handler to perform various actions from within an ISR context
*
* isr_handler - handler to perform various actions from within an ISR context
*
* This routine is the ISR handler for _trigger_isrHandler().
* This routine is the ISR handler for _trigger_isr_handler().
*
* @return N/A
*/
void isr_handler(void)
{
intHandlerExecuted++;
int_handler_executed++;
}
/**
*
* exc_divide_error_handler -
* This is the handler for the divde by zero exception.
*
* This is the handler for the divde by zero exception. The source of this
* divide-by-zero error comes from the following line in main() ...
* error = error / excHandlerExecuted;
* Where excHandlerExecuted is zero.
* The source of this divide-by-zero error comes from the following line in
* main() ...
* error = error / exc_handler_executed;
* Where exc_handler_executed is zero.
* The disassembled code for it looks something like ....
* f7 fb idiv %ecx
* This handler is part of a test that is only interested in detecting the
@ -75,16 +80,16 @@ void isr_handler(void)
* @return N/A
*/
void exc_divide_error_handler(NANO_ESF *pEsf)
void exc_divide_error_handler(NANO_ESF *p_esf)
{
pEsf->eip += 2;
excHandlerExecuted = 1; /* provide evidence that the handler executed */
p_esf->eip += 2;
/* provide evidence that the handler executed */
exc_handler_executed = 1;
}
_EXCEPTION_CONNECT_NOCODE(exc_divide_error_handler, IV_DIVIDE_ERROR);
extern void *_EXCEPTION_STUB_NAME(exc_divide_error_handler, IV_DIVIDE_ERROR);
/**
*
* @brief Check the IDT.
*
* This test examines the IDT and verifies that the static interrupt and
@ -93,26 +98,26 @@ extern void *_EXCEPTION_STUB_NAME(exc_divide_error_handler, IV_DIVIDE_ERROR);
* @return TC_PASS on success, TC_FAIL on failure
*/
int nanoIdtStubTest(void)
int idt_stub_test(void)
{
struct segment_descriptor *pIdtEntry;
struct segment_descriptor *p_idt_entry;
uint32_t offset;
/* Check for the interrupt stub */
pIdtEntry = (struct segment_descriptor *)
(_idt_base_address + (TEST_SOFT_INT << 3));
offset = (uint32_t)(&nanoIntStub);
if (DTE_OFFSET(pIdtEntry) != offset) {
TC_ERROR("Failed to find offset of nanoIntStub (0x%x) at vector %d\n",
p_idt_entry = (struct segment_descriptor *)
(_idt_base_address + (TEST_SOFT_INT << 3));
offset = (uint32_t)(&int_stub);
if (DTE_OFFSET(p_idt_entry) != offset) {
TC_ERROR("Failed to find offset of int_stub (0x%x) at vector %d\n",
offset, TEST_SOFT_INT);
return TC_FAIL;
}
/* Check for the exception stub */
pIdtEntry = (struct segment_descriptor *)
(_idt_base_address + (IV_DIVIDE_ERROR << 3));
p_idt_entry = (struct segment_descriptor *)
(_idt_base_address + (IV_DIVIDE_ERROR << 3));
offset = (uint32_t)(&_EXCEPTION_STUB_NAME(exc_divide_error_handler, 0));
if (DTE_OFFSET(pIdtEntry) != offset) {
if (DTE_OFFSET(p_idt_entry) != offset) {
TC_ERROR("Failed to find offset of exc stub (0x%x) at vector %d\n",
offset, IV_DIVIDE_ERROR);
return TC_FAIL;
@ -126,25 +131,23 @@ int nanoIdtStubTest(void)
}
/**
*
* @brief Task to test spurious handlers
*
* @return 0
*/
void idtSpurTask(void)
void idt_spur_task(void *arg1, void *arg2, void *arg3)
{
TC_PRINT("- Expect to see unhandled interrupt/exception message\n");
_trigger_spurHandler();
_trigger_spur_handler();
/* Shouldn't get here */
spurHandlerAbortedThread = 0;
spur_handler_aborted_thread = 0;
}
/**
*
* @brief Entry point to static IDT tests
*
* This is the entry point to the static IDT tests.
@ -152,69 +155,72 @@ void idtSpurTask(void)
* @return N/A
*/
void idtTestTask(void)
void main(void)
{
int rv; /* return value from tests */
volatile int error; /* used to create a divide by zero error */
int rv; /* return value from tests */
volatile int error; /* used to create a divide by zero error */
TC_START("Starting static IDT tests");
TC_PRINT("Testing to see if IDT has address of test stubs()\n");
rv = nanoIdtStubTest();
rv = idt_stub_test();
if (rv != TC_PASS) {
goto doneTests;
goto done_tests;
}
TC_PRINT("Testing to see interrupt handler executes properly\n");
_trigger_isrHandler();
_trigger_isr_handler();
if (intHandlerExecuted == 0) {
if (int_handler_executed == 0) {
TC_ERROR("Interrupt handler did not execute\n");
rv = TC_FAIL;
goto doneTests;
} else if (intHandlerExecuted != 1) {
goto done_tests;
} else if (int_handler_executed != 1) {
TC_ERROR("Interrupt handler executed more than once! (%d)\n",
intHandlerExecuted);
int_handler_executed);
rv = TC_FAIL;
goto doneTests;
goto done_tests;
}
TC_PRINT("Testing to see exception handler executes properly\n");
/*
* Use excHandlerExecuted instead of 0 to prevent the compiler issuing a
* Use exc_handler_executed instead of 0 to prevent the compiler issuing a
* 'divide by zero' warning.
*/
error = 32; /* avoid static checker uninitialized warnings */
error = error / excHandlerExecuted;
error = 32; /* avoid static checker uninitialized warnings */
error = error / exc_handler_executed;
if (excHandlerExecuted == 0) {
if (exc_handler_executed == 0) {
TC_ERROR("Exception handler did not execute\n");
rv = TC_FAIL;
goto doneTests;
} else if (excHandlerExecuted != 1) {
goto done_tests;
} else if (exc_handler_executed != 1) {
TC_ERROR("Exception handler executed more than once! (%d)\n",
excHandlerExecuted);
exc_handler_executed);
rv = TC_FAIL;
goto doneTests;
goto done_tests;
}
/*
* Start task to trigger the spurious interrupt handler
*/
TC_PRINT("Testing to see spurious handler executes properly\n");
task_start(tSpurTask);
k_thread_spawn(my_stack_area, MY_STACK_SIZE,
idt_spur_task, NULL, NULL, NULL,
MY_PRIORITY, 0, K_NO_WAIT);
/*
* The fiber/task should not run past where the spurious interrupt is
* generated. Therefore spurHandlerAbortedThread should remain at 1.
* generated. Therefore spur_handler_aborted_thread should remain at 1.
*/
if (spurHandlerAbortedThread == 0) {
if (spur_handler_aborted_thread == 0) {
TC_ERROR("Spurious handler did not execute as expected\n");
rv = TC_FAIL;
goto doneTests;
goto done_tests;
}
doneTests:
done_tests:
TC_END(rv, "%s - %s.\n", rv == TC_PASS ? PASS : FAIL, __func__);
TC_END_REPORT(rv);
}

View file

@ -13,7 +13,7 @@
#error test_asm_inline_gcc.h goes only with x86 GCC
#endif
#define _trigger_isrHandler() __asm__ volatile("int %0" : : "i" (TEST_SOFT_INT) : "memory")
#define _trigger_spurHandler() __asm__ volatile("int %0" : : "i" (TEST_SPUR_INT) : "memory")
#define _trigger_isr_handler() __asm__ volatile("int %0" : : "i" (TEST_SOFT_INT) : "memory")
#define _trigger_spur_handler() __asm__ volatile("int %0" : : "i" (TEST_SPUR_INT) : "memory")
#endif /* _TEST_ASM_INLINE_GCC_H */

View file

@ -27,8 +27,8 @@ testing.
/* Static interrupt handler stubs */
GTEXT(nanoIntStub)
SECTION_FUNC(TEXT, nanoIntStub)
GTEXT(int_stub)
SECTION_FUNC(TEXT, int_stub)
pushl $0
pushl $isr_handler
jmp _interrupt_enter

View file

@ -1,6 +0,0 @@
#
# This TC will force a fatal fault, as it is testing it. Don't error
# if we find it (cancel out the default setting in root's defaults.tc
# that will consider a testcase toast if a fatal fault is found
#
# ^eval console-rx %(console)s::pass [Ff]atal fault in

View file

@ -1,45 +0,0 @@
Title: Static IDT Support
Description:
This test verifies that the static IDT feature operates as expected.
--------------------------------------------------------------------------------
Building and Running Project:
This microkernel project outputs to the console. It can be built and executed
on QEMU as follows:
make qemu
--------------------------------------------------------------------------------
Troubleshooting:
Problems caused by out-dated project information can be addressed by
issuing one of the following commands then rebuilding the project:
make clean # discard results of previous builds
# but keep existing configuration info
or
make pristine # discard results of previous builds
# and restore pre-defined configuration info
--------------------------------------------------------------------------------
Sample Output:
tc_start() - Test Nanokernel static IDT tests
Testing to see if IDT has address of test stubs()
Testing to see interrupt handler executes properly
Testing to see exception handler executes properly
Testing to see spurious handler executes properly
- Expect to see unhandled interrupt/exception message
***** Unhandled exception/interrupt occurred! *****
Current context ID = 0x00102c44
Faulting instruction address = 0x0010342c
Fatal task error! Aborting task.
PASS - idtTestTask.
===================================================================
PROJECT EXECUTION SUCCESSFUL

View file

@ -1,2 +0,0 @@
CONFIG_EXCEPTION_DEBUG=n
CONFIG_LEGACY_KERNEL=y

View file

@ -1,6 +0,0 @@
% Application : test static interrutps
% TASK NAME PRIO ENTRY STACK GROUPS
% ==================================================
TASK tStartTask 6 idtTestTask 2048 [EXE]
TASK tSpurTask 5 idtSpurTask 2048 []

View file

@ -1,4 +0,0 @@
BOARD ?= qemu_x86
CONF_FILE = prj.conf
include $(ZEPHYR_BASE)/Makefile.test

View file

@ -1,46 +0,0 @@
Title: Static IDT Support
Description:
This test verifies that the static IDT feature operates as expected in a
nanokernel environment.
---------------------------------------------------------------------------
Building and Running Project:
This nanokernel project outputs to the console. It can be built and executed
on QEMU as follows:
make qemu
---------------------------------------------------------------------------
Troubleshooting:
Problems caused by out-dated project information can be addressed by
issuing one of the following commands then rebuilding the project:
make clean # discard results of previous builds
# but keep existing configuration info
or
make pristine # discard results of previous builds
# and restore pre-defined configuration info
---------------------------------------------------------------------------
Sample Output:
tc_start() - Test Nanokernel static IDT tests
Testing to see if IDT has address of test stubs()
Testing to see interrupt handler executes properly
Testing to see exception handler executes properly
Testing to see spurious handler executes properly
- Expect to see unhandled interrupt/exception message
***** Unhandled exception/interrupt occurred! *****
Current context ID = 0x00102a68
Faulting instruction address = 0x00102c50
Fatal fiber error! Aborting fiber.
PASS - main.
===================================================================
PROJECT EXECUTION SUCCESSFUL

View file

@ -1,3 +0,0 @@
ccflags-y += -I${ZEPHYR_BASE}/tests/include
obj-y = static_idt.o test_stubs.o

View file

@ -1,226 +0,0 @@
/* static_idt.c - test static IDT APIs */
/*
* Copyright (c) 2012-2014 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
DESCRIPTION
Ensures interrupt and exception stubs are installed correctly.
*/
#include <zephyr.h>
#include <tc_util.h>
#include <arch/x86/segmentation.h>
#include <kernel_structs.h>
#if defined(__GNUC__)
#include <test_asm_inline_gcc.h>
#else
#include <test_asm_inline_other.h>
#endif
/* These vectors are somewhat arbitrary. We try and use unused vectors */
#define TEST_SOFT_INT 62
#define TEST_SPUR_INT 63
/* externs */
/* the _idt_base_address symbol is generated via a linker script */
extern unsigned char _idt_base_address[];
extern void *nanoIntStub;
NANO_CPU_INT_REGISTER(nanoIntStub, -1, -1, TEST_SOFT_INT, 0);
static volatile int excHandlerExecuted;
static volatile int intHandlerExecuted;
/* Assume the spurious interrupt handler will execute and abort the fiber */
static volatile int spurHandlerAbortedThread = 1;
#define STACK_SIZE 1024
static char __stack fiberStack[STACK_SIZE];
/**
*
* isr_handler - handler to perform various actions from within an ISR context
*
* This routine is the ISR handler for _trigger_isrHandler().
*
* @return N/A
*/
void isr_handler(void)
{
intHandlerExecuted++;
}
/**
*
* exc_divide_error_handler -
*
* This is the handler for the divde by zero exception. The source of this
* divide-by-zero error comes from the following line in main() ...
* error = error / excHandlerExecuted;
* Where excHandlerExecuted is zero.
* The disassembled code for it looks something like ....
* f7 fb idiv %ecx
* This handler is part of a test that is only interested in detecting the
* error so that we know the exception connect code is working. Therefore,
* a very quick and dirty approach is taken for dealing with the exception;
* we skip the offending instruction by adding 2 to the EIP. (If nothing is
* done, then control goes back to the offending instruction and an infinite
* loop of divide-by-zero errors would be created.)
*
* @return N/A
*/
void exc_divide_error_handler(NANO_ESF *pEsf)
{
pEsf->eip += 2;
excHandlerExecuted = 1; /* provide evidence that the handler executed */
}
_EXCEPTION_CONNECT_NOCODE(exc_divide_error_handler, IV_DIVIDE_ERROR);
extern void *_EXCEPTION_STUB_NAME(exc_divide_error_handler, IV_DIVIDE_ERROR);
/**
*
* @brief Check the IDT.
*
* This test examines the IDT and verifies that the static interrupt and
* exception stubs are installed at the correct place.
*
* @return TC_PASS on success, TC_FAIL on failure
*/
int nanoIdtStubTest(void)
{
struct segment_descriptor *pIdtEntry;
uint32_t offset;
/* Check for the interrupt stub */
pIdtEntry = (struct segment_descriptor *)
(_idt_base_address + (TEST_SOFT_INT << 3));
offset = (uint32_t)(&nanoIntStub);
if (DTE_OFFSET(pIdtEntry) != offset) {
TC_ERROR("Failed to find offset of nanoIntStub (0x%x) at vector %d\n",
offset, TEST_SOFT_INT);
return TC_FAIL;
}
/* Check for the exception stub */
pIdtEntry = (struct segment_descriptor *)
(_idt_base_address + (IV_DIVIDE_ERROR << 3));
offset = (uint32_t)(&_EXCEPTION_STUB_NAME(exc_divide_error_handler, 0));
if (DTE_OFFSET(pIdtEntry) != offset) {
TC_ERROR("Failed to find offset of exc stub (0x%x) at vector %d\n",
offset, IV_DIVIDE_ERROR);
return TC_FAIL;
}
/*
* If the other fields are wrong, the system will crash when the exception
* and software interrupt are triggered so we don't check them.
*/
return TC_PASS;
}
/**
*
* @brief Fiber to test spurious handlers
*
* @return 0
*/
static void idtSpurFiber(int a1, int a2)
{
ARG_UNUSED(a1);
ARG_UNUSED(a2);
TC_PRINT("- Expect to see unhandled interrupt/exception message\n");
_trigger_spurHandler();
/* Shouldn't get here */
spurHandlerAbortedThread = 0;
}
/**
*
* @brief Entry point to static IDT tests
*
* This is the entry point to the static IDT tests.
*
* @return N/A
*/
void main(void)
{
int rv; /* return value from tests */
volatile int error; /* used to create a divide by zero error */
TC_START("Starting static IDT tests");
TC_PRINT("Testing to see if IDT has address of test stubs()\n");
rv = nanoIdtStubTest();
if (rv != TC_PASS) {
goto doneTests;
}
TC_PRINT("Testing to see interrupt handler executes properly\n");
_trigger_isrHandler();
if (intHandlerExecuted == 0) {
TC_ERROR("Interrupt handler did not execute\n");
rv = TC_FAIL;
goto doneTests;
} else if (intHandlerExecuted != 1) {
TC_ERROR("Interrupt handler executed more than once! (%d)\n",
intHandlerExecuted);
rv = TC_FAIL;
goto doneTests;
}
TC_PRINT("Testing to see exception handler executes properly\n");
/*
* Use excHandlerExecuted instead of 0 to prevent the compiler issuing a
* 'divide by zero' warning.
*/
error = 32;
error = error / excHandlerExecuted;
if (excHandlerExecuted == 0) {
TC_ERROR("Exception handler did not execute\n");
rv = TC_FAIL;
goto doneTests;
} else if (excHandlerExecuted != 1) {
TC_ERROR("Exception handler executed more than once! (%d)\n",
excHandlerExecuted);
rv = TC_FAIL;
goto doneTests;
}
/*
* Start fiber to trigger the spurious interrupt handler
*/
TC_PRINT("Testing to see spurious handler executes properly\n");
task_fiber_start(fiberStack, sizeof(fiberStack), idtSpurFiber, 0, 0, 5, 0);
/*
* The fiber/task should not run past where the spurious interrupt is
* generated. Therefore spurHandlerAbortedThread should remain at 1.
*/
if (spurHandlerAbortedThread == 0) {
TC_ERROR("Spurious handler did not execute as expected\n");
rv = TC_FAIL;
goto doneTests;
}
doneTests:
TC_END(rv, "%s - %s.\n", rv == TC_PASS ? PASS : FAIL, __func__);
TC_END_REPORT(rv);
}

View file

@ -1,19 +0,0 @@
/* Intel x86 GCC specific test inline assembler functions and macros */
/*
* Copyright (c) 2015, Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _TEST_ASM_INLINE_GCC_H
#define _TEST_ASM_INLINE_GCC_H
#if !defined(__GNUC__) || !defined(CONFIG_X86)
#error test_asm_inline_gcc.h goes only with x86 GCC
#endif
#define _trigger_isrHandler() __asm__ volatile("int %0" : : "i" (TEST_SOFT_INT) : "memory")
#define _trigger_spurHandler() __asm__ volatile("int %0" : : "i" (TEST_SPUR_INT) : "memory")
#endif /* _TEST_ASM_INLINE_GCC_H */

View file

@ -1,39 +0,0 @@
/* test_stubs.S - Exception and interrupt stubs */
/*
* Copyright (c) 2012-2014 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
DESCRIPTION
This module implements assembler exception and interrupt stubs for regression
testing.
*/
#ifdef CONFIG_ISA_IA32
/* IA-32 specific */
#include <arch/cpu.h>
#include <kernel_structs.h>
#include <arch/x86/asm.h>
#include <asm_inline.h>
/* imports (internal APIs) */
GTEXT(_interrupt_enter)
/* Static interrupt handler stubs */
GTEXT(nanoIntStub)
SECTION_FUNC(TEXT, nanoIntStub)
pushl $0
pushl $isr_handler
jmp _interrupt_enter
#else
#error Arch not supported
#endif /* CONFIG_ISA_IA32 */

View file

@ -1,4 +0,0 @@
[test]
tags = legacy core bat_commit ignore_faults
arch_whitelist = x86