x86: Properly initialize _interrupt_vectors_allocated[] bitmap

Updates the 'gen_idt' tool to generate a bitmap of (statically) allocated
interrupt vectors that is linked into the final image in a manner similar to
the static IDT. The kernel then uses this bitmap when dynamically connecting
an interrupt vector, thereby preventing the dynamic irq connections
from clobbering the static irq connections.

Change-Id: I0a8f488408dad4912736865179f32f63ff1ca98f
Signed-off-by: Peter Mitsis <peter.mitsis@windriver.com>
This commit is contained in:
Peter Mitsis 2015-10-02 13:26:20 -04:00 committed by Anas Nashif
commit 5705d06874
6 changed files with 117 additions and 49 deletions

View file

@ -122,22 +122,6 @@ void *__attribute__((section(".spurNoErrIsr")))
MK_ISR_NAME(_SpuriousIntNoErrCodeHandler) =
&_SpuriousIntNoErrCodeHandler;
/*
* Bitfield used to track which interrupt vectors are available for allocation.
* The array is initialized to indicate all vectors are currently available.
*
* NOTE: For portability reasons, the ROUND_UP() macro can NOT be used to
* perform the rounding up calculation below. Unlike GCC, the Diab compiler
* generates an error when a macro that takes a parameter is used to define
* the size of an array.
*/
#define VEC_ALLOC_NUM_INTS ((CONFIG_IDT_NUM_VECTORS + 31) & ~31) / 32
static unsigned int interrupt_vectors_allocated[VEC_ALLOC_NUM_INTS] = {
[0 ...(VEC_ALLOC_NUM_INTS - 1)] = 0xffffffff
};
/*
* Array of interrupt stubs for dynamic interrupt connection.
*/
@ -328,8 +312,7 @@ int irq_connect(
*
* The _SysIntVecAlloc() routine will use the "utility" routine
* _IntVecAlloc() provided in this module to scan the
*interrupt_vectors_allocated[]
* array for a suitable vector.
* _interrupt_vectors_allocated[] array for a suitable vector.
*/
vector = _SysIntVecAlloc(irq,
@ -467,7 +450,7 @@ int irq_connect(
*
* @brief Allocate a free interrupt vector given <priority>
*
* This routine scans the interrupt_vectors_allocated[] array for a free vector
* This routine scans the _interrupt_vectors_allocated[] array for a free vector
* that satisfies the specified <priority>. It is a utility function for use
* only by the interrupt controller's _SysIntVecAlloc() routine.
*
@ -515,15 +498,15 @@ int _IntVecAlloc(unsigned int priority)
#endif /* DEBUG */
/*
* Atomically allocate a vector from the interrupt_vectors_allocated[] array
* to prevent race conditions with other tasks/fibers attempting to
* allocate an interrupt vector.
* Atomically allocate a vector from the _interrupt_vectors_allocated[]
* array to prevent race conditions with other tasks/fibers attempting
* to allocate an interrupt vector.
*/
entryToScan = priority >> 1; /* interrupt_vectors_allocated[] entry to scan */
entryToScan = priority >> 1;
/*
* The interrupt_vectors_allocated[] entry specified by 'entryToScan' is a
* The _interrupt_vectors_allocated[] entry indexed by 'entryToScan' is a
* 32-bit quantity and thus represents the vectors for a pair of priority
* levels. Mask out the unwanted priority level and then use find_lsb_set()
* to scan for an available vector of the requested priority.
@ -534,7 +517,7 @@ int _IntVecAlloc(unsigned int priority)
key = irq_lock();
search_set = mask[priority & 1] & interrupt_vectors_allocated[entryToScan];
search_set = mask[priority & 1] & _interrupt_vectors_allocated[entryToScan];
fsb = find_lsb_set(search_set);
#if defined(DEBUG)
@ -552,7 +535,7 @@ int _IntVecAlloc(unsigned int priority)
*/
--fsb;
interrupt_vectors_allocated[entryToScan] &= ~(1 << fsb);
_interrupt_vectors_allocated[entryToScan] &= ~(1 << fsb);
irq_unlock(key);
@ -583,7 +566,7 @@ void _IntVecMarkAllocated(unsigned int vector)
unsigned int imask;
imask = irq_lock();
interrupt_vectors_allocated[entryToSet] &= ~(1 << bitToSet);
_interrupt_vectors_allocated[entryToSet] &= ~(1 << bitToSet);
irq_unlock(imask);
}
@ -604,7 +587,7 @@ void _IntVecMarkFree(unsigned int vector)
unsigned int imask;
imask = irq_lock();
interrupt_vectors_allocated[entryToSet] |= (1 << bitToSet);
_interrupt_vectors_allocated[entryToSet] |= (1 << bitToSet);
irq_unlock(imask);
}

View file

@ -758,6 +758,15 @@ typedef struct s_NANO {
extern tNANO _nanokernel;
/*
* _interrupt_vectors_allocated[] is generated by the 'gen_idt' tool. It is
* initialized to identify which interrupts have been statically connected
* and which interrupts are available to be dynamically connected at run time.
* The variable itself is defined in the linker file.
*/
extern unsigned int _interrupt_vectors_allocated[];
/* inline function definitions */
/**

View file

@ -144,6 +144,7 @@ SECTIONS
*(.data)
*(".data.*")
IDT_MEMORY
INTERRUPT_VECTORS_ALLOCATED_MEMORY
. = ALIGN(4);
} GROUP_LINK_IN(RAM)

View file

@ -42,14 +42,23 @@ Commonly used macros and defines for linker script.
#define INT_STUB_NOINIT KEEP(*(.intStubSect))
#ifdef FINAL_LINK
/* Use the real IDT */
#define STATIC_IDT KEEP(*(staticIdt))
/* Use the real IDT */
#define STATIC_IDT KEEP(*(staticIdt))
/* Use the real _interrupt_vectors_allocated[] array */
#define INTERRUPT_VECTORS_ALLOCATED KEEP(*(int_vector_alloc))
#else
/*
* Save space for the real IDT to prevent symbols from shifting. Note that
* an IDT entry is 8 bytes in size.
*/
#define STATIC_IDT . += (8 * CONFIG_IDT_NUM_VECTORS);
/*
* Save space for the real IDT to prevent symbols from shifting. Note that
* an IDT entry is 8 bytes in size.
*/
#define STATIC_IDT . += (8 * CONFIG_IDT_NUM_VECTORS);
/*
* Save space for the real _interrupt_vectors_allocated[] array to prevent
* symbols from shifting.
*/
#define INTERRUPT_VECTORS_ALLOCATED . += ((CONFIG_IDT_NUM_VECTORS + 31) / 32);
#endif
/*
@ -58,8 +67,13 @@ Commonly used macros and defines for linker script.
* interrupt management code relies on.
*/
#define IDT_MEMORY \
. = ALIGN(8);\
_idt_base_address = .;\
STATIC_IDT
. = ALIGN(8);\
_idt_base_address = .;\
STATIC_IDT
#define INTERRUPT_VECTORS_ALLOCATED_MEMORY \
. = ALIGN(4); \
_interrupt_vectors_allocated = .; \
INTERRUPT_VECTORS_ALLOCATED
#endif /* _LINKERDEFSARCH_H */

View file

@ -30,11 +30,12 @@
/**
* @file
* @brief Create static IDT
* @brief Generate static IDT and a bitmap of allocated interrupt vectors.
* Creates a static IA-32 Interrupt Descriptor Table (IDT).
*
* This program expects to be invoked as follows:
* gen_idt -i <input file> -o <output file> -n <number of interrupt vectors>
* gen_idt -i <input file> -o <IDT output file> -n <# of interrupt vectors>
* -b <allocated vectors bitmap file>
* All parameters are required.
*
* The <input file> is assumed to be a binary file containing the intList
@ -89,6 +90,7 @@ static void read_input_file(void);
static void close_files(void);
static void validate_input_file(void);
static void generate_idt(void);
static void generate_interrupt_vector_bitmap(void);
static void clean_exit(int exit_code);
struct genidt_header_s {
@ -112,6 +114,7 @@ static struct genidt_entry_s generated_entry[MAX_NUM_VECTORS];
enum {
IFILE = 0, /* input file */
OFILE, /* output file */
BFILE, /* allocated interrupt vector bitmap file */
NUSERFILES, /* number of user-provided file names */
EXECFILE = NUSERFILES, /* for name of executable */
NFILES /* total number of file names */
@ -121,7 +124,7 @@ enum { SHORT_USAGE, LONG_USAGE };
static int fds[NUSERFILES] = {-1, -1};
static char *filenames[NFILES];
static unsigned int num_vectors = (unsigned int)-1;
static struct version version = {KERNEL_VERSION, 1, 1, 3};
static struct version version = {KERNEL_VERSION, 1, 1, 4};
int main(int argc, char *argv[])
{
@ -131,6 +134,7 @@ int main(int argc, char *argv[])
read_input_file(); /* may exit */
validate_input_file(); /* may exit */
generate_idt(); /* may exit */
generate_interrupt_vector_bitmap();
close_files();
return 0;
}
@ -140,8 +144,11 @@ static void get_options(int argc, char *argv[])
char *endptr;
int ii, opt;
while ((opt = getopt(argc, argv, "hi:o:n:v")) != -1) {
while ((opt = getopt(argc, argv, "hb:i:o:n:v")) != -1) {
switch (opt) {
case 'b':
filenames[BFILE] = optarg;
break;
case 'i':
filenames[IFILE] = optarg;
break;
@ -211,6 +218,9 @@ static void open_files(void)
fds[OFILE] = open(filenames[OFILE], O_WRONLY | O_BINARY |
O_TRUNC | O_CREAT,
S_IWUSR | S_IRUSR);
fds[BFILE] = open(filenames[BFILE], O_WRONLY | O_BINARY | O_CREAT |
O_TRUNC | O_BINARY,
S_IWUSR | S_IRUSR);
for (ii = 0; ii < NUSERFILES; ii++) {
int invalid = fds[ii] == -1;
@ -472,6 +482,47 @@ static void generate_idt(void)
return;
}
static void generate_interrupt_vector_bitmap(void)
{
int i;
unsigned int num_elements = (num_vectors + 31) / 32;
unsigned int interrupt_vector_bitmap[num_elements];
unsigned int index;
unsigned int bit;
size_t bytes_to_write;
ssize_t bytes_written;
/* Initially mark each interrupt vector as available */
for (i = 0; i < num_elements; i++) {
interrupt_vector_bitmap[i] = 0xffffffff;
}
/* Loop through each supplied entry and mark its vector as allocated. */
for (i = 0; i < genidt_header.num_entries; i++) {
index = supplied_entry[i].vector_id / 32;
bit = supplied_entry[i].vector_id & 31;
interrupt_vector_bitmap[index] &= ~(1 << bit);
}
/* Ensure that any leftover entries are marked as allocated too. */
for (i = num_vectors; i < num_elements * 32; i++) {
index = i / 32;
bit = i & 0x1f;
interrupt_vector_bitmap[index] &= ~(1 << bit);
}
bytes_to_write = num_elements * sizeof(unsigned int);
bytes_written = write(fds[BFILE], interrupt_vector_bitmap,
bytes_to_write);
if (bytes_written != bytes_to_write) {
fprintf(stderr, "Failed to write all data to '%s'.\n",
filenames[BFILE]);
clean_exit(-1);
}
}
static void close_files(void)
{
int ii;
@ -499,10 +550,12 @@ static void usage(int len)
"\n"
" options\n"
"\n"
" -b <allocated interrupt vector bitmap output file>\n\n"
" [Mandatory] The interrupt vector bitmap output file.\n\n"
" -i <binary file>\n\n"
" [Mandatory] The input file in binary format.\n\n"
" -o <output file>\n\n"
" [Mandatory] The output file.\n\n"
" -o <IDT output file>\n\n"
" [Mandatory] The IDT output file.\n\n"
" -n <n>\n\n"
" [Mandatory] Number of vectors\n\n"
" -v Display version.\n\n"

View file

@ -77,14 +77,20 @@ initial_link()
#Generates IDT and merge them into final binary
# ${1} input file (${KERNEL_NAME}.elf)
# ${2} output file (staticIdt.o)
# ${3} output file (int_vector_alloc)
gen_idt()
{
test -z $OUTPUT_FORMAT && OUTPUT_FORMAT=elf32-i386
test -z $OUTPUT_ARCH && OUTPUT_ARCH=i386
${OBJCOPY} -I $OUTPUT_FORMAT -O binary -j intList ${1} isrList.bin
${GENIDT} -i isrList.bin -n ${CONFIG_IDT_NUM_VECTORS:-256} -o staticIdt.bin
${OBJCOPY} -I binary -B $OUTPUT_ARCH -O $OUTPUT_FORMAT --rename-section .data=staticIdt staticIdt.bin ${2}
${GENIDT} -i isrList.bin -n ${CONFIG_IDT_NUM_VECTORS:-256} \
-o staticIdt.bin -b ${3}.bin
${OBJCOPY} -I binary -B $OUTPUT_ARCH -O $OUTPUT_FORMAT \
--rename-section .data=staticIdt staticIdt.bin ${2}
${OBJCOPY} -I binary -B $OUTPUT_ARCH -O $OUTPUT_FORMAT \
--rename-section .data=${3} ${3}.bin ${3}.o
rm -f staticIdt.bin
rm -f ${3}.bin
rm -f isrList.bin
}
@ -93,9 +99,10 @@ gen_idt()
# ${2} - linker command file (final-linker.cmd)
# ${3} - input file (staticIdt.o)
# ${4} - output file
# ${5} - additional input file if applicable
zephyr_link()
{
${LD} -T ${2} @${1} ${3} -o ${4}
${LD} -T ${2} @${1} ${3} ${5} -o ${4}
${OBJCOPY} --set-section-flags intList=noload ${4} elf.tmp
${OBJCOPY} -R intList elf.tmp ${4}
rm elf.tmp
@ -259,9 +266,10 @@ fi
if [ "${SRCARCH}" = "x86" ]; then
info SIDT ${KERNEL_NAME}.elf
gen_idt ${KERNEL_NAME}.elf staticIdt.o
gen_idt ${KERNEL_NAME}.elf staticIdt.o int_vector_alloc
linker_command final-linker.cmd -DFINAL_LINK
zephyr_link ${KERNEL_NAME}.lnk final-linker.cmd staticIdt.o ${KERNEL_NAME}.elf
zephyr_link ${KERNEL_NAME}.lnk final-linker.cmd staticIdt.o \
${KERNEL_NAME}.elf int_vector_alloc.o
fi
info BIN ${KERNEL_NAME}.bin