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) = MK_ISR_NAME(_SpuriousIntNoErrCodeHandler) =
&_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. * Array of interrupt stubs for dynamic interrupt connection.
*/ */
@ -328,8 +312,7 @@ int irq_connect(
* *
* The _SysIntVecAlloc() routine will use the "utility" routine * The _SysIntVecAlloc() routine will use the "utility" routine
* _IntVecAlloc() provided in this module to scan the * _IntVecAlloc() provided in this module to scan the
*interrupt_vectors_allocated[] * _interrupt_vectors_allocated[] array for a suitable vector.
* array for a suitable vector.
*/ */
vector = _SysIntVecAlloc(irq, vector = _SysIntVecAlloc(irq,
@ -467,7 +450,7 @@ int irq_connect(
* *
* @brief Allocate a free interrupt vector given <priority> * @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 * that satisfies the specified <priority>. It is a utility function for use
* only by the interrupt controller's _SysIntVecAlloc() routine. * only by the interrupt controller's _SysIntVecAlloc() routine.
* *
@ -515,15 +498,15 @@ int _IntVecAlloc(unsigned int priority)
#endif /* DEBUG */ #endif /* DEBUG */
/* /*
* Atomically allocate a vector from the interrupt_vectors_allocated[] array * Atomically allocate a vector from the _interrupt_vectors_allocated[]
* to prevent race conditions with other tasks/fibers attempting to * array to prevent race conditions with other tasks/fibers attempting
* allocate an interrupt vector. * 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 * 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() * levels. Mask out the unwanted priority level and then use find_lsb_set()
* to scan for an available vector of the requested priority. * to scan for an available vector of the requested priority.
@ -534,7 +517,7 @@ int _IntVecAlloc(unsigned int priority)
key = irq_lock(); 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); fsb = find_lsb_set(search_set);
#if defined(DEBUG) #if defined(DEBUG)
@ -552,7 +535,7 @@ int _IntVecAlloc(unsigned int priority)
*/ */
--fsb; --fsb;
interrupt_vectors_allocated[entryToScan] &= ~(1 << fsb); _interrupt_vectors_allocated[entryToScan] &= ~(1 << fsb);
irq_unlock(key); irq_unlock(key);
@ -583,7 +566,7 @@ void _IntVecMarkAllocated(unsigned int vector)
unsigned int imask; unsigned int imask;
imask = irq_lock(); imask = irq_lock();
interrupt_vectors_allocated[entryToSet] &= ~(1 << bitToSet); _interrupt_vectors_allocated[entryToSet] &= ~(1 << bitToSet);
irq_unlock(imask); irq_unlock(imask);
} }
@ -604,7 +587,7 @@ void _IntVecMarkFree(unsigned int vector)
unsigned int imask; unsigned int imask;
imask = irq_lock(); imask = irq_lock();
interrupt_vectors_allocated[entryToSet] |= (1 << bitToSet); _interrupt_vectors_allocated[entryToSet] |= (1 << bitToSet);
irq_unlock(imask); irq_unlock(imask);
} }

View file

@ -758,6 +758,15 @@ typedef struct s_NANO {
extern tNANO _nanokernel; 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 */ /* inline function definitions */
/** /**

View file

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

View file

@ -44,12 +44,21 @@ Commonly used macros and defines for linker script.
#ifdef FINAL_LINK #ifdef FINAL_LINK
/* Use the real IDT */ /* Use the real IDT */
#define STATIC_IDT KEEP(*(staticIdt)) #define STATIC_IDT KEEP(*(staticIdt))
/* Use the real _interrupt_vectors_allocated[] array */
#define INTERRUPT_VECTORS_ALLOCATED KEEP(*(int_vector_alloc))
#else #else
/* /*
* Save space for the real IDT to prevent symbols from shifting. Note that * Save space for the real IDT to prevent symbols from shifting. Note that
* an IDT entry is 8 bytes in size. * an IDT entry is 8 bytes in size.
*/ */
#define STATIC_IDT . += (8 * CONFIG_IDT_NUM_VECTORS); #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 #endif
/* /*
@ -62,4 +71,9 @@ Commonly used macros and defines for linker script.
_idt_base_address = .;\ _idt_base_address = .;\
STATIC_IDT STATIC_IDT
#define INTERRUPT_VECTORS_ALLOCATED_MEMORY \
. = ALIGN(4); \
_interrupt_vectors_allocated = .; \
INTERRUPT_VECTORS_ALLOCATED
#endif /* _LINKERDEFSARCH_H */ #endif /* _LINKERDEFSARCH_H */

View file

@ -30,11 +30,12 @@
/** /**
* @file * @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). * Creates a static IA-32 Interrupt Descriptor Table (IDT).
* *
* This program expects to be invoked as follows: * 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. * All parameters are required.
* *
* The <input file> is assumed to be a binary file containing the intList * 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 close_files(void);
static void validate_input_file(void); static void validate_input_file(void);
static void generate_idt(void); static void generate_idt(void);
static void generate_interrupt_vector_bitmap(void);
static void clean_exit(int exit_code); static void clean_exit(int exit_code);
struct genidt_header_s { struct genidt_header_s {
@ -112,6 +114,7 @@ static struct genidt_entry_s generated_entry[MAX_NUM_VECTORS];
enum { enum {
IFILE = 0, /* input file */ IFILE = 0, /* input file */
OFILE, /* output file */ OFILE, /* output file */
BFILE, /* allocated interrupt vector bitmap file */
NUSERFILES, /* number of user-provided file names */ NUSERFILES, /* number of user-provided file names */
EXECFILE = NUSERFILES, /* for name of executable */ EXECFILE = NUSERFILES, /* for name of executable */
NFILES /* total number of file names */ NFILES /* total number of file names */
@ -121,7 +124,7 @@ enum { SHORT_USAGE, LONG_USAGE };
static int fds[NUSERFILES] = {-1, -1}; static int fds[NUSERFILES] = {-1, -1};
static char *filenames[NFILES]; static char *filenames[NFILES];
static unsigned int num_vectors = (unsigned int)-1; 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[]) int main(int argc, char *argv[])
{ {
@ -131,6 +134,7 @@ int main(int argc, char *argv[])
read_input_file(); /* may exit */ read_input_file(); /* may exit */
validate_input_file(); /* may exit */ validate_input_file(); /* may exit */
generate_idt(); /* may exit */ generate_idt(); /* may exit */
generate_interrupt_vector_bitmap();
close_files(); close_files();
return 0; return 0;
} }
@ -140,8 +144,11 @@ static void get_options(int argc, char *argv[])
char *endptr; char *endptr;
int ii, opt; 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) { switch (opt) {
case 'b':
filenames[BFILE] = optarg;
break;
case 'i': case 'i':
filenames[IFILE] = optarg; filenames[IFILE] = optarg;
break; break;
@ -211,6 +218,9 @@ static void open_files(void)
fds[OFILE] = open(filenames[OFILE], O_WRONLY | O_BINARY | fds[OFILE] = open(filenames[OFILE], O_WRONLY | O_BINARY |
O_TRUNC | O_CREAT, O_TRUNC | O_CREAT,
S_IWUSR | S_IRUSR); 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++) { for (ii = 0; ii < NUSERFILES; ii++) {
int invalid = fds[ii] == -1; int invalid = fds[ii] == -1;
@ -472,6 +482,47 @@ static void generate_idt(void)
return; 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) static void close_files(void)
{ {
int ii; int ii;
@ -499,10 +550,12 @@ static void usage(int len)
"\n" "\n"
" options\n" " options\n"
"\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" " -i <binary file>\n\n"
" [Mandatory] The input file in binary format.\n\n" " [Mandatory] The input file in binary format.\n\n"
" -o <output file>\n\n" " -o <IDT output file>\n\n"
" [Mandatory] The output file.\n\n" " [Mandatory] The IDT output file.\n\n"
" -n <n>\n\n" " -n <n>\n\n"
" [Mandatory] Number of vectors\n\n" " [Mandatory] Number of vectors\n\n"
" -v Display version.\n\n" " -v Display version.\n\n"

View file

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