diff --git a/arch/x86/core/intconnect.c b/arch/x86/core/intconnect.c index 9840a099e17..4f0886d5580 100644 --- a/arch/x86/core/intconnect.c +++ b/arch/x86/core/intconnect.c @@ -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 * - * 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 . 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); } diff --git a/arch/x86/include/nano_private.h b/arch/x86/include/nano_private.h index 0294f6a12da..b5d8a8853b4 100644 --- a/arch/x86/include/nano_private.h +++ b/arch/x86/include/nano_private.h @@ -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 */ /** diff --git a/include/arch/x86/linker-common-sections.h b/include/arch/x86/linker-common-sections.h index 49ea0d972ad..f3333bfd9ac 100644 --- a/include/arch/x86/linker-common-sections.h +++ b/include/arch/x86/linker-common-sections.h @@ -144,6 +144,7 @@ SECTIONS *(.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 4ea2d09cde9..1c33432098a 100644 --- a/include/arch/x86/linker-defs-arch.h +++ b/include/arch/x86/linker-defs-arch.h @@ -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 */ diff --git a/scripts/gen_idt/gen_idt.c b/scripts/gen_idt/gen_idt.c index 0df6f85c2a0..8421443649c 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 -o -n + * gen_idt -i -o -n <# of interrupt vectors> + * -b * All parameters are required. * * The 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 \n\n" + " [Mandatory] The interrupt vector bitmap output file.\n\n" " -i \n\n" " [Mandatory] The input file in binary format.\n\n" - " -o \n\n" - " [Mandatory] The output file.\n\n" + " -o \n\n" + " [Mandatory] The IDT output file.\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 f44006ae11f..603ba2d7a03 100755 --- a/scripts/link-zephyr.sh +++ b/scripts/link-zephyr.sh @@ -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