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>
diff --git a/arch/x86/core/intconnect.c b/arch/x86/core/intconnect.c
index 9840a09..4f0886d 100644
--- a/arch/x86/core/intconnect.c
+++ b/arch/x86/core/intconnect.c
@@ -123,22 +123,6 @@
 		&_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.
  */
 #ifdef CONFIG_MICROKERNEL
@@ -328,8 +312,7 @@
 	 *
 	 * 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 @@
  *
  * @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 @@
 #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 @@
 
 	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 @@
 	 */
 
 	--fsb;
-	interrupt_vectors_allocated[entryToScan] &= ~(1 << fsb);
+	_interrupt_vectors_allocated[entryToScan] &= ~(1 << fsb);
 
 	irq_unlock(key);
 
@@ -583,7 +566,7 @@
 	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 @@
 	unsigned int imask;
 
 	imask = irq_lock();
-	interrupt_vectors_allocated[entryToSet] |= (1 << bitToSet);
+	_interrupt_vectors_allocated[entryToSet] |= (1 << bitToSet);
 	irq_unlock(imask);
 }
 
diff --git a/arch/x86/include/nano_private.h b/arch/x86/include/nano_private.h
index 0294f6a..b5d8a88 100644
--- a/arch/x86/include/nano_private.h
+++ b/arch/x86/include/nano_private.h
@@ -758,6 +758,15 @@
 
 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 */
 
 /**
diff --git a/include/arch/x86/linker-common-sections.h b/include/arch/x86/linker-common-sections.h
index 49ea0d9..f3333bf 100644
--- a/include/arch/x86/linker-common-sections.h
+++ b/include/arch/x86/linker-common-sections.h
@@ -144,6 +144,7 @@
 	*(.data)
 	*(".data.*")
 	IDT_MEMORY
+	INTERRUPT_VECTORS_ALLOCATED_MEMORY
 	. = ALIGN(4);
 	} GROUP_LINK_IN(RAM)
 
diff --git a/include/arch/x86/linker-defs-arch.h b/include/arch/x86/linker-defs-arch.h
index 4ea2d09..1c33432 100644
--- a/include/arch/x86/linker-defs-arch.h
+++ b/include/arch/x86/linker-defs-arch.h
@@ -42,14 +42,23 @@
 #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 @@
  * 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 */
diff --git a/scripts/gen_idt/gen_idt.c b/scripts/gen_idt/gen_idt.c
index 0df6f85..8421443 100644
--- a/scripts/gen_idt/gen_idt.c
+++ b/scripts/gen_idt/gen_idt.c
@@ -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 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 @@
 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 @@
 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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	    "\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"
diff --git a/scripts/link-zephyr.sh b/scripts/link-zephyr.sh
index f44006a..603ba2d 100755
--- a/scripts/link-zephyr.sh
+++ b/scripts/link-zephyr.sh
@@ -77,14 +77,20 @@
 #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 @@
 # ${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 @@
 
 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