x86: convert gen_idt to Python
This is one less host tool we have to compile for every build, and makes the build tools more portable across host OSes. The code is also much simpler to maintain. Issue: ZEP-2063 Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
parent
dff21de082
commit
ddf9f4be31
7 changed files with 236 additions and 665 deletions
4
Makefile
4
Makefile
|
@ -1276,10 +1276,8 @@ $(help-board-dirs): help-%:
|
|||
host-tools:
|
||||
$(Q)$(MAKE) $(build)=scripts/basic
|
||||
$(Q)$(MAKE) $(build)=scripts/kconfig standalone
|
||||
$(Q)$(MAKE) $(build)=scripts/gen_idt
|
||||
@mkdir -p ${ZEPHYR_BASE}/bin
|
||||
@cp scripts/basic/fixdep scripts/gen_idt/gen_idt scripts/kconfig/conf \
|
||||
${ZEPHYR_BASE}/bin
|
||||
@cp scripts/basic/fixdep scripts/kconfig/conf ${ZEPHYR_BASE}/bin
|
||||
|
||||
|
||||
# Documentation targets
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
ifeq ($(KBUILD_VERBOSE),1)
|
||||
GENIDT_EXTRA_ARGS := -d
|
||||
GENIDT_EXTRA_ARGS := --verbose
|
||||
else
|
||||
GENIDT_EXTRA_ARGS :=
|
||||
endif
|
||||
|
||||
ifeq ($(PREBUILT_HOST_TOOLS),)
|
||||
GENIDT := scripts/gen_idt/gen_idt
|
||||
else
|
||||
GENIDT := $(PREBUILT_HOST_TOOLS)/gen_idt
|
||||
endif
|
||||
GENIDT := $(srctree)/scripts/gen_idt.py
|
||||
|
||||
OUTPUT_FORMAT ?= elf32-i386
|
||||
OUTPUT_ARCH ?= i386
|
||||
|
@ -16,21 +12,18 @@ OUTPUT_ARCH ?= i386
|
|||
quiet_cmd_gen_idt = SIDT $@
|
||||
cmd_gen_idt = \
|
||||
( \
|
||||
$(OBJCOPY) -I $(OUTPUT_FORMAT) -O binary -j intList $< isrList.bin && \
|
||||
$(GENIDT) -i isrList.bin -n $(CONFIG_IDT_NUM_VECTORS) -o staticIdt.bin \
|
||||
-m irq_int_vector_map.bin \
|
||||
-l $(CONFIG_MAX_IRQ_LINES) $(GENIDT_EXTRA_ARGS) && \
|
||||
$(GENIDT) --kernel $(PREBUILT_KERNEL) \
|
||||
--output-idt staticIdt.bin \
|
||||
--vector-map irq_int_vector_map.bin \
|
||||
$(GENIDT_EXTRA_ARGS) && \
|
||||
$(OBJCOPY) -I binary -B $(OUTPUT_ARCH) -O $(OUTPUT_FORMAT) \
|
||||
--rename-section .data=staticIdt staticIdt.bin staticIdt.o && \
|
||||
$(OBJCOPY) -I binary -B $(OUTPUT_ARCH) -O $(OUTPUT_FORMAT) \
|
||||
--rename-section .data=irq_int_vector_map irq_int_vector_map.bin \
|
||||
irq_int_vector_map.o && \
|
||||
rm staticIdt.bin irq_int_vector_map.bin isrList.bin \
|
||||
rm staticIdt.bin irq_int_vector_map.bin \
|
||||
)
|
||||
|
||||
$(GENIDT):
|
||||
$(Q)$(MAKE) $(build)=scripts/gen_idt
|
||||
|
||||
staticIdt.o: $(PREBUILT_KERNEL) $(GENIDT)
|
||||
$(call cmd,gen_idt)
|
||||
|
||||
|
|
228
scripts/gen_idt.py
Executable file
228
scripts/gen_idt.py
Executable file
|
@ -0,0 +1,228 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2017 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import struct
|
||||
import os
|
||||
from elftools.elf.elffile import ELFFile
|
||||
from elftools.elf.sections import SymbolTableSection
|
||||
|
||||
# This will never change, first selector in the GDT after the null selector
|
||||
KERNEL_CODE_SEG = 0x08
|
||||
|
||||
# These exception vectors push an error code onto the stack.
|
||||
ERR_CODE_VECTORS = [8, 10, 11, 12, 13, 14, 17]
|
||||
|
||||
def debug(text):
|
||||
if not args.verbose:
|
||||
return
|
||||
sys.stdout.write(os.path.basename(sys.argv[0]) + ": " + text + "\n")
|
||||
|
||||
def error(text):
|
||||
sys.stderr.write(os.path.basename(sys.argv[0]) + ": " + text + "\n")
|
||||
sys.exit(1)
|
||||
|
||||
# See Section 6.11 of the Intel Architecture Software Developer's Manual
|
||||
irq_gate_desc_format = "<HHBBH"
|
||||
|
||||
def create_irq_gate(handler, dpl):
|
||||
present = 1
|
||||
gate_type = 0xE # 32-bit interrupt gate
|
||||
type_attr = gate_type | (dpl << 5) | (present << 7)
|
||||
|
||||
offset_hi = handler >> 16
|
||||
offset_lo = handler & 0xFFFF
|
||||
|
||||
data = struct.pack(irq_gate_desc_format, offset_lo, KERNEL_CODE_SEG, 0,
|
||||
type_attr, offset_hi)
|
||||
return data
|
||||
|
||||
def create_idt_binary(idt_config, filename):
|
||||
with open(filename, "wb") as fp:
|
||||
for handler, dpl in idt_config:
|
||||
data = create_irq_gate(handler, dpl)
|
||||
fp.write(data)
|
||||
|
||||
map_fmt = "<B"
|
||||
|
||||
def create_irq_vec_map_binary(irq_vec_map, filename):
|
||||
with open(filename, "wb") as fp:
|
||||
for i in irq_vec_map:
|
||||
fp.write(struct.pack(map_fmt, i))
|
||||
|
||||
def priority_range(prio):
|
||||
# Priority levels are represented as groups of 16 vectors within the IDT
|
||||
base = 32 + (prio * 16)
|
||||
return range(base, base + 16)
|
||||
|
||||
|
||||
def update_irq_vec_map(irq_vec_map, irq, vector, max_irq):
|
||||
# No IRQ associated; exception or software interrupt
|
||||
if irq == -1:
|
||||
return
|
||||
|
||||
if irq >= max_irq:
|
||||
error("irq %d specified, but CONFIG_MAX_IRQ_LINES is %d" %
|
||||
(irq, max_irq))
|
||||
|
||||
# This table will never have values less than 32 since those are for
|
||||
# exceptions; 0 means unconfigured
|
||||
if irq_vec_map[irq] != 0:
|
||||
error("multiple vector assignments for interrupt line %d", irq)
|
||||
|
||||
debug("assign IRQ %d to vector %d" % (irq, vector))
|
||||
irq_vec_map[irq] = vector
|
||||
|
||||
|
||||
def setup_idt(spur_code, spur_nocode, intlist, max_vec, max_irq):
|
||||
irq_vec_map = [0 for i in range(max_irq)]
|
||||
vectors = [None for i in range(max_vec)]
|
||||
|
||||
# Pass 1: sanity check and set up hard-coded interrupt vectors
|
||||
for handler, irq, prio, vec, dpl in intlist:
|
||||
if vec == -1:
|
||||
if prio == -1:
|
||||
error("entry does not specify vector or priority level")
|
||||
continue
|
||||
|
||||
if vec >= max_vec:
|
||||
error("Vector %d specified, but size of IDT is only %d vectors" %
|
||||
(vec, max_vec))
|
||||
|
||||
if vectors[vec] != None:
|
||||
error("Multiple assignments for vector %d" % vec)
|
||||
|
||||
vectors[vec] = (handler, dpl)
|
||||
update_irq_vec_map(irq_vec_map, irq, vec, max_irq)
|
||||
|
||||
# Pass 2: set up priority-based interrupt vectors
|
||||
for handler, irq, prio, vec, dpl in intlist:
|
||||
if vec != -1:
|
||||
continue
|
||||
|
||||
for vi in priority_range(prio):
|
||||
if vi >= max_vec:
|
||||
break
|
||||
if vectors[vi] == None:
|
||||
vec = vi
|
||||
break
|
||||
|
||||
if vec == -1:
|
||||
error("can't find a free vector in priority level %d" % prio)
|
||||
|
||||
vectors[vec] = (handler, dpl)
|
||||
update_irq_vec_map(irq_vec_map, irq, vec, max_irq)
|
||||
|
||||
# Pass 3: fill in unused vectors with spurious handler at dpl=0
|
||||
for i in range(max_vec):
|
||||
if vectors[i] != None:
|
||||
continue
|
||||
|
||||
if i in ERR_CODE_VECTORS:
|
||||
handler = spur_code
|
||||
else:
|
||||
handler = spur_nocode
|
||||
|
||||
vectors[i] = (handler, 0)
|
||||
|
||||
return vectors, irq_vec_map
|
||||
|
||||
def get_symbols(obj):
|
||||
for section in obj.iter_sections():
|
||||
if isinstance(section, SymbolTableSection):
|
||||
return {sym.name: sym.entry.st_value
|
||||
for sym in section.iter_symbols()}
|
||||
|
||||
raise LookupError("Could not find symbol table")
|
||||
|
||||
# struct genidt_header_s {
|
||||
# uint32_t spurious_addr;
|
||||
# uint32_t spurious_no_error_addr;
|
||||
# int32_t num_entries;
|
||||
# };
|
||||
|
||||
|
||||
intlist_header_fmt = "<IIi"
|
||||
|
||||
# struct genidt_entry_s {
|
||||
# uint32_t isr;
|
||||
# int32_t irq;
|
||||
# int32_t priority;
|
||||
# int32_t vector_id;
|
||||
# int32_t dpl;
|
||||
# };
|
||||
|
||||
intlist_entry_fmt = "<Iiiii"
|
||||
|
||||
def get_intlist(elf):
|
||||
intdata = elf.get_section_by_name("intList").data()
|
||||
|
||||
header_sz = struct.calcsize(intlist_header_fmt)
|
||||
header = struct.unpack_from(intlist_header_fmt, intdata, 0)
|
||||
intdata = intdata[header_sz:]
|
||||
|
||||
spurious_code = header[0]
|
||||
spurious_nocode = header[1]
|
||||
|
||||
debug("spurious handler (code) : %s" % hex(header[0]))
|
||||
debug("spurious handler (no code) : %s" % hex(header[1]))
|
||||
|
||||
intlist = [i for i in
|
||||
struct.iter_unpack(intlist_entry_fmt, intdata)]
|
||||
|
||||
debug("Configured interrupt routing")
|
||||
debug("handler irq pri vec dpl")
|
||||
debug("--------------------------")
|
||||
|
||||
for irq in intlist:
|
||||
debug("{0:<10} {1:<3} {2:<3} {3:<3} {4:<2}".format(
|
||||
hex(irq[0]),
|
||||
"-" if irq[1] == -1 else irq[1],
|
||||
"-" if irq[2] == -1 else irq[2],
|
||||
"-" if irq[3] == -1 else irq[3],
|
||||
irq[4]))
|
||||
|
||||
return (spurious_code, spurious_nocode, intlist)
|
||||
|
||||
|
||||
def parse_args():
|
||||
global args
|
||||
parser = argparse.ArgumentParser(description = __doc__,
|
||||
formatter_class = argparse.RawDescriptionHelpFormatter)
|
||||
|
||||
parser.add_argument("-m", "--vector-map", required=True,
|
||||
help="Output file mapping IRQ lines to IDT vectors")
|
||||
parser.add_argument("-o", "--output-idt", required=True,
|
||||
help="Output file containing IDT binary")
|
||||
parser.add_argument("-k", "--kernel", required=True,
|
||||
help="Zephyr kernel image")
|
||||
parser.add_argument("-v", "--verbose", action="store_true",
|
||||
help="Print extra debugging information")
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
def main():
|
||||
parse_args()
|
||||
|
||||
with open(args.kernel, "rb") as fp:
|
||||
kernel = ELFFile(fp)
|
||||
|
||||
syms = get_symbols(kernel)
|
||||
spur_code, spur_nocode, intlist = get_intlist(kernel)
|
||||
|
||||
max_irq = syms["CONFIG_MAX_IRQ_LINES"]
|
||||
max_vec = syms["CONFIG_IDT_NUM_VECTORS"]
|
||||
|
||||
vectors, irq_vec_map = setup_idt(spur_code, spur_nocode, intlist, max_vec,
|
||||
max_irq)
|
||||
|
||||
create_idt_binary(vectors, args.output_idt)
|
||||
create_irq_vec_map_binary(irq_vec_map, args.vector_map)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
HOSTCFLAGS_gen_idt.o += -I$(srctree)/include/arch/x86 -I$(srctree)/include
|
||||
HOSTCFLAGS_gen_idt.o += -DKERNEL_VERSION=0 -Wall -Werror -g
|
||||
HOSTCFLAGS_version.o += -DKERNEL_VERSION=0 -Wall -Werror -g
|
||||
HOSTCFLAGS_gen_idt.o += -Wno-unused-result
|
||||
|
||||
hostprogs-y += gen_idt
|
||||
gen_idt-objs := version.o gen_idt.o
|
||||
always := $(hostprogs-y)
|
|
@ -1,603 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2014 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @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 <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
|
||||
* section from the Zephyr Kernel ELF image.
|
||||
*
|
||||
* <number of interrupt vectors> is the same as CONFIG_IDT_NUM_VECTORS.
|
||||
*
|
||||
* It is expected that this program is invoked from within the build system
|
||||
* during the link stage.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include "version.h"
|
||||
|
||||
/* Define __packed for the idtEntry structure defined in idtEnt.h */
|
||||
#define __packed __attribute__((__packed__))
|
||||
|
||||
/* This comes from the shared directory */
|
||||
#include <segmentation.h>
|
||||
|
||||
#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WIN32__)
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
#define MAX_NUM_VECTORS 256
|
||||
#define MAX_PRIORITIES 14
|
||||
#define MAX_VECTORS_PER_PRIORITY 16
|
||||
#define MAX_IRQS 256
|
||||
|
||||
#define UNSPECIFIED_INT_VECTOR ((unsigned int) -1)
|
||||
#define UNSPECIFIED_PRIORITY ((unsigned int) -1)
|
||||
#define UNSPECIFIED_IRQ ((unsigned int) -1)
|
||||
|
||||
#define KERNEL_CODE_SEG_SELECTOR 0x0008
|
||||
|
||||
static void get_exec_name(char *pathname);
|
||||
static void usage(int len);
|
||||
static void get_options(int argc, char *argv[]);
|
||||
static void open_files(void);
|
||||
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);
|
||||
static void debug(const char *format, ...);
|
||||
|
||||
struct genidt_header_s {
|
||||
uint32_t spurious_addr;
|
||||
uint32_t spurious_no_error_addr;
|
||||
unsigned int num_entries;
|
||||
};
|
||||
|
||||
struct genidt_entry_s {
|
||||
uint32_t isr;
|
||||
unsigned int irq;
|
||||
unsigned int priority;
|
||||
unsigned int vector_id;
|
||||
unsigned int dpl;
|
||||
};
|
||||
|
||||
static struct genidt_header_s genidt_header;
|
||||
static struct genidt_entry_s supplied_entry[MAX_NUM_VECTORS];
|
||||
static struct genidt_entry_s generated_entry[MAX_NUM_VECTORS];
|
||||
|
||||
enum {
|
||||
IFILE = 0, /* input file */
|
||||
OFILE, /* output file */
|
||||
MFILE, /* irq to interrupt vector mapping file */
|
||||
NUSERFILES, /* number of user-provided file names */
|
||||
EXECFILE = NUSERFILES, /* for name of executable */
|
||||
NFILES /* total number of file names */
|
||||
};
|
||||
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, 6};
|
||||
static unsigned int num_irq_lines = -1;
|
||||
static int verbose;
|
||||
|
||||
static void debug(const char *format, ...)
|
||||
{
|
||||
va_list vargs;
|
||||
|
||||
if (!verbose)
|
||||
return;
|
||||
|
||||
va_start(vargs, format);
|
||||
vfprintf(stderr, format, vargs);
|
||||
va_end(vargs);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
get_exec_name(argv[0]);
|
||||
get_options(argc, argv); /* may exit */
|
||||
open_files(); /* may exit */
|
||||
read_input_file(); /* may exit */
|
||||
validate_input_file(); /* may exit */
|
||||
generate_interrupt_vector_bitmap(); /* may exit */
|
||||
generate_idt(); /* may exit */
|
||||
close_files();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void get_options(int argc, char *argv[])
|
||||
{
|
||||
char *endptr;
|
||||
int ii, opt;
|
||||
|
||||
while ((opt = getopt(argc, argv, "hi:o:m:n:vl:d")) != -1) {
|
||||
switch (opt) {
|
||||
case 'i':
|
||||
filenames[IFILE] = optarg;
|
||||
break;
|
||||
case 'o':
|
||||
filenames[OFILE] = optarg;
|
||||
break;
|
||||
case 'm':
|
||||
filenames[MFILE] = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
usage(LONG_USAGE);
|
||||
exit(0);
|
||||
case 'l':
|
||||
num_irq_lines = (unsigned int) strtoul(optarg, &endptr, 10);
|
||||
if ((*optarg == '\0') || (*endptr != '\0')) {
|
||||
usage(SHORT_USAGE);
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
num_vectors = (unsigned int) strtoul(optarg, &endptr, 10);
|
||||
if ((*optarg == '\0') || (*endptr != '\0')) {
|
||||
usage(SHORT_USAGE);
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
show_version(filenames[EXECFILE], &version);
|
||||
exit(0);
|
||||
case 'd':
|
||||
verbose = 1;
|
||||
break;
|
||||
default:
|
||||
usage(SHORT_USAGE);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (num_vectors > MAX_NUM_VECTORS) {
|
||||
usage(SHORT_USAGE);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (num_irq_lines > MAX_IRQS) {
|
||||
usage(SHORT_USAGE);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
for (ii = IFILE; ii < NUSERFILES; ii++) {
|
||||
if (!filenames[ii]) {
|
||||
usage(SHORT_USAGE);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void get_exec_name(char *pathname)
|
||||
{
|
||||
int end = strlen(pathname) - 1;
|
||||
|
||||
while (end != -1) {
|
||||
#if defined(WINDOWS) /* Might have both slashes in path */
|
||||
if ((pathname[end] == '/') || (pathname[end] == '\\'))
|
||||
#else
|
||||
if (pathname[end] == '/')
|
||||
#endif
|
||||
{
|
||||
if ((0 == end) || (pathname[end - 1] != '\\')) {
|
||||
++end;
|
||||
break;
|
||||
}
|
||||
}
|
||||
--end;
|
||||
}
|
||||
filenames[EXECFILE] = &pathname[end];
|
||||
}
|
||||
|
||||
static void open_files(void)
|
||||
{
|
||||
int ii;
|
||||
|
||||
fds[IFILE] = open(filenames[IFILE], O_RDONLY | O_BINARY);
|
||||
fds[OFILE] = open(filenames[OFILE], O_WRONLY | O_BINARY |
|
||||
O_TRUNC | O_CREAT,
|
||||
S_IWUSR | S_IRUSR);
|
||||
fds[MFILE] = open(filenames[MFILE], 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;
|
||||
|
||||
if (invalid) {
|
||||
char *invalid = filenames[ii];
|
||||
|
||||
fprintf(stderr, "invalid file %s\n", invalid);
|
||||
for (--ii; ii >= 0; ii--) {
|
||||
close(fds[ii]);
|
||||
}
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void show_entry(struct genidt_entry_s *entry)
|
||||
{
|
||||
debug("Vector %3d: ISR 0x%08x IRQ %3d PRI %2d DPL %2x\n",
|
||||
entry->vector_id, entry->isr, entry->irq, entry->priority,
|
||||
entry->dpl);
|
||||
}
|
||||
|
||||
static void read_input_file(void)
|
||||
{
|
||||
ssize_t bytes_read;
|
||||
size_t bytes_to_read;
|
||||
|
||||
/* Read the header information. */
|
||||
bytes_read = read(fds[IFILE], &genidt_header, sizeof(genidt_header));
|
||||
if (bytes_read != sizeof(genidt_header)) {
|
||||
goto read_error;
|
||||
}
|
||||
|
||||
debug("Spurious interrupt handlers found at 0x%x and 0x%x.\n",
|
||||
genidt_header.spurious_addr, genidt_header.spurious_no_error_addr);
|
||||
debug("There are %d ISR(s).\n", genidt_header.num_entries);
|
||||
|
||||
|
||||
if (genidt_header.num_entries > num_vectors) {
|
||||
fprintf(stderr,
|
||||
"Too many ISRs found. Got %u. Expected no more than %u.\n"
|
||||
"Malformed input file?\n",
|
||||
genidt_header.num_entries, num_vectors);
|
||||
clean_exit(-1);
|
||||
}
|
||||
|
||||
bytes_to_read = sizeof(struct genidt_entry_s) * genidt_header.num_entries;
|
||||
bytes_read = read(fds[IFILE], supplied_entry, bytes_to_read);
|
||||
if (bytes_read != bytes_to_read) {
|
||||
goto read_error;
|
||||
}
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < genidt_header.num_entries; i++) {
|
||||
show_entry(&supplied_entry[i]);
|
||||
}
|
||||
return;
|
||||
|
||||
read_error:
|
||||
fprintf(stderr, "Error occurred while reading input file. Aborting...\n");
|
||||
clean_exit(-1);
|
||||
}
|
||||
|
||||
static void validate_dpl(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < genidt_header.num_entries; i++) {
|
||||
if (supplied_entry[i].dpl != 0) {
|
||||
fprintf(stderr,
|
||||
"Invalid DPL bits specified. Must be zero.\n");
|
||||
show_entry(&supplied_entry[i]);
|
||||
clean_exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void validate_vector_id(void)
|
||||
{
|
||||
int i;
|
||||
int vectors[MAX_NUM_VECTORS] = {0};
|
||||
|
||||
for (i = 0; i < genidt_header.num_entries; i++) {
|
||||
if (supplied_entry[i].vector_id == UNSPECIFIED_INT_VECTOR) {
|
||||
/*
|
||||
* Vector is to be allocated. No further validation to be
|
||||
* done at the moment.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
if (supplied_entry[i].vector_id >= num_vectors) {
|
||||
fprintf(stderr,
|
||||
"Vector ID exceeds specified # of vectors (%d).\n",
|
||||
num_vectors);
|
||||
show_entry(&supplied_entry[i]);
|
||||
clean_exit(-1);
|
||||
}
|
||||
|
||||
if (vectors[supplied_entry[i].vector_id] != 0) {
|
||||
fprintf(stderr, "Duplicate vector ID found.\n");
|
||||
show_entry(&supplied_entry[i]);
|
||||
clean_exit(-1);
|
||||
}
|
||||
vectors[supplied_entry[i].vector_id]++;
|
||||
}
|
||||
}
|
||||
|
||||
static void validate_priority(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Validate the priority. */
|
||||
for (i = 0; i < genidt_header.num_entries; i++) {
|
||||
if (supplied_entry[i].priority == UNSPECIFIED_PRIORITY) {
|
||||
if (supplied_entry[i].vector_id == UNSPECIFIED_INT_VECTOR) {
|
||||
fprintf(stderr,
|
||||
"Either priority or vector ID must be specified.\n");
|
||||
show_entry(&supplied_entry[i]);
|
||||
clean_exit(-1);
|
||||
}
|
||||
} else if (supplied_entry[i].priority >= MAX_PRIORITIES) {
|
||||
fprintf(stderr, "Priority must not exceed %d.\n",
|
||||
MAX_PRIORITIES - 1);
|
||||
show_entry(&supplied_entry[i]);
|
||||
clean_exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void validate_irq(void)
|
||||
{
|
||||
int i;
|
||||
int num_irqs[MAX_IRQS] = {0};
|
||||
|
||||
/* Validate the IRQ number */
|
||||
for (i = 0; i < genidt_header.num_entries; i++) {
|
||||
if (supplied_entry[i].irq == UNSPECIFIED_IRQ) {
|
||||
if (supplied_entry[i].vector_id == UNSPECIFIED_INT_VECTOR) {
|
||||
fprintf(stderr,
|
||||
"Either IRQ or vector ID must be specified.\n");
|
||||
show_entry(&supplied_entry[i]);
|
||||
clean_exit(-1);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (supplied_entry[i].irq >= num_irq_lines) {
|
||||
/*
|
||||
* If code to support the PIC is re-introduced, then this
|
||||
* check will need to be updated.
|
||||
*/
|
||||
fprintf(stderr, "IRQ must be between 0 and %d inclusive.\n",
|
||||
num_irq_lines - 1);
|
||||
show_entry(&supplied_entry[i]);
|
||||
clean_exit(-1);
|
||||
}
|
||||
num_irqs[supplied_entry[i].irq]++;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_irq_lines; i++) {
|
||||
if (num_irqs[i] > 1) {
|
||||
fprintf(stderr, "Multiple requests (%d) for IRQ %d detected.\n",
|
||||
num_irqs[i], i);
|
||||
clean_exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void validate_input_file(void)
|
||||
{
|
||||
validate_dpl(); /* exits on error */
|
||||
validate_irq(); /* exits on error */
|
||||
validate_vector_id(); /* exits on error */
|
||||
validate_priority(); /* exits on error */
|
||||
}
|
||||
|
||||
static void generate_idt(void)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int vector_id;
|
||||
|
||||
/*
|
||||
* Initialize the generated entries with default
|
||||
* spurious interrupt handlers.
|
||||
*/
|
||||
|
||||
for (i = 0; i < num_vectors; i++) {
|
||||
if ((((1 << i) & _EXC_ERROR_CODE_FAULTS)) && (i < 32)) {
|
||||
generated_entry[i].isr = genidt_header.spurious_addr;
|
||||
} else {
|
||||
generated_entry[i].isr = genidt_header.spurious_no_error_addr;
|
||||
}
|
||||
/* Initialize the [irq] and [priority] fields to aid in debugging. */
|
||||
generated_entry[i].irq = UNSPECIFIED_IRQ;
|
||||
generated_entry[i].priority = UNSPECIFIED_PRIORITY;
|
||||
generated_entry[i].vector_id = i;
|
||||
generated_entry[i].dpl = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Overwrite the generated entries as appropriate with the
|
||||
* validated supplied entries.
|
||||
*/
|
||||
|
||||
for (i = 0; i < genidt_header.num_entries; i++) {
|
||||
vector_id = supplied_entry[i].vector_id;
|
||||
generated_entry[vector_id] = supplied_entry[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* We now have the address of all ISR stub/functions captured in
|
||||
* generated_entry[]. Now construct the actual IDT.
|
||||
*/
|
||||
|
||||
for (i = 0; i < num_vectors; i++) {
|
||||
struct segment_descriptor idt_entry;
|
||||
ssize_t bytes_written;
|
||||
|
||||
_init_irq_gate(&idt_entry, KERNEL_CODE_SEG_SELECTOR,
|
||||
generated_entry[i].isr, generated_entry[i].dpl);
|
||||
|
||||
bytes_written = write(fds[OFILE], &idt_entry, sizeof(idt_entry));
|
||||
if (bytes_written != sizeof(idt_entry)) {
|
||||
fprintf(stderr, "Failed to write IDT entry %u.\n", num_vectors);
|
||||
clean_exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int find_first_set_lsb(unsigned int value)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
if ((value & (1 << i)) != 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void generate_interrupt_vector_bitmap(void)
|
||||
{
|
||||
int i;
|
||||
unsigned int num_elements = (num_vectors + 31) / 32;
|
||||
unsigned int interrupt_vector_bitmap[num_elements];
|
||||
uint8_t map_irq_to_vector_id[MAX_IRQS] = {0};
|
||||
unsigned int value;
|
||||
unsigned int index;
|
||||
unsigned int mask_index;
|
||||
int bit;
|
||||
size_t bytes_to_write;
|
||||
ssize_t bytes_written;
|
||||
static unsigned int mask[2] = {0x0000ffff, 0xffff0000};
|
||||
|
||||
/* Initially mark each interrupt vector as available */
|
||||
for (i = 0; i < num_elements; i++) {
|
||||
interrupt_vector_bitmap[i] = 0xffffffff;
|
||||
}
|
||||
|
||||
/* Ensure that any leftover entries are marked as allocated. */
|
||||
for (i = num_vectors; i < num_elements * 32; i++) {
|
||||
index = i / 32;
|
||||
bit = i & 0x1f;
|
||||
|
||||
interrupt_vector_bitmap[index] &= ~(1 << bit);
|
||||
}
|
||||
|
||||
/*
|
||||
* Vector allocation is done in two steps.
|
||||
* 1. Loop through each supplied entry and if an explicit vector was
|
||||
* specified, mark it as allocated.
|
||||
* 2. Loop through each supplied entry and allocate the vector if
|
||||
* it is required.
|
||||
* This approach guarantees that explicitly specified interrupt vectors
|
||||
* will get their requested slots.
|
||||
*/
|
||||
|
||||
for (i = 0; i < genidt_header.num_entries; i++) {
|
||||
if (supplied_entry[i].vector_id == UNSPECIFIED_INT_VECTOR) {
|
||||
/* This vector will be allocated in the next for-loop. */
|
||||
continue;
|
||||
}
|
||||
|
||||
index = supplied_entry[i].vector_id / 32;
|
||||
bit = supplied_entry[i].vector_id & 31;
|
||||
|
||||
interrupt_vector_bitmap[index] &= ~(1 << bit);
|
||||
}
|
||||
|
||||
for (i = 0; i < genidt_header.num_entries; i++) {
|
||||
if (supplied_entry[i].vector_id != UNSPECIFIED_INT_VECTOR) {
|
||||
/* This vector has already been processed. */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We can assume priority has been explicitly set as
|
||||
* validate_priority() enforces that you can't use both
|
||||
* UNSPECIFIED_INT_VECTOR and UNSPECIFIED_INT_PRIORITY
|
||||
*/
|
||||
index = (supplied_entry[i].priority + 2) / 2;
|
||||
mask_index = (supplied_entry[i].priority + 2) & 1;
|
||||
value = interrupt_vector_bitmap[index] & mask[mask_index];
|
||||
bit = find_first_set_lsb(value);
|
||||
if (bit < 0) {
|
||||
fprintf(stderr,
|
||||
"No remaining vectors for priority %d are available.\n",
|
||||
supplied_entry[i].priority);
|
||||
clean_exit(-1);
|
||||
}
|
||||
|
||||
interrupt_vector_bitmap[index] &= ~(1 << bit);
|
||||
map_irq_to_vector_id[supplied_entry[i].irq] = (index * 32) + bit;
|
||||
supplied_entry[i].vector_id = (index * 32) + bit;
|
||||
debug("Assigned IRQ %3d (priority %2d) vector %3d\n",
|
||||
supplied_entry[i].irq, supplied_entry[i].priority,
|
||||
supplied_entry[i].vector_id);
|
||||
}
|
||||
|
||||
bytes_to_write = num_irq_lines;
|
||||
bytes_written = write(fds[MFILE], map_irq_to_vector_id, bytes_to_write);
|
||||
if (bytes_written != bytes_to_write) {
|
||||
fprintf(stderr, "Failed to write all data to '%s'.\n",
|
||||
filenames[MFILE]);
|
||||
clean_exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
static void close_files(void)
|
||||
{
|
||||
int ii;
|
||||
|
||||
for (ii = 0; ii < NUSERFILES; ii++) {
|
||||
close(fds[ii]);
|
||||
}
|
||||
}
|
||||
|
||||
static void clean_exit(int exit_code)
|
||||
{
|
||||
close_files();
|
||||
exit(exit_code);
|
||||
}
|
||||
|
||||
static void usage(int len)
|
||||
{
|
||||
fprintf(stderr, "\n%s -i <input file> -n <n>\n", filenames[EXECFILE]);
|
||||
|
||||
if (len == SHORT_USAGE) {
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(stderr,
|
||||
"\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 <IDT output file>\n\n"
|
||||
" [Mandatory] The IDT output file.\n\n"
|
||||
" -m <IRQ to interrupt vector map file>\n\n"
|
||||
" [Mandatory] The IRQ to interrupt vector output file\n\n"
|
||||
" -n <n>\n\n"
|
||||
" [Mandatory] Number of vectors\n\n"
|
||||
" -l <n>\n\n"
|
||||
" [Mandatory] Number of IRQ lines\n\n"
|
||||
" -v Display version.\n\n"
|
||||
" -h Display this help.\n\n"
|
||||
" -d Display extra debugging output.\n\n"
|
||||
"\nReturns -1 on error, 0 on success\n\n");
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
/* version.c - version number library */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013-2014 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "version.h"
|
||||
|
||||
void show_version(const char *name, const struct version *ver)
|
||||
{
|
||||
fprintf(stdout,
|
||||
"\n%s"
|
||||
" %4d.%d.%d.%3.3d, (c) Wind River Systems, Inc.\n"
|
||||
" Built on %s at %s\n\n",
|
||||
name,
|
||||
ver->kernel, ver->major, ver->minor, ver->maintenance,
|
||||
__DATE__, __TIME__);
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
/* version.h - version number library */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013-2014 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
struct version {
|
||||
int kernel;
|
||||
int major;
|
||||
int minor;
|
||||
int maintenance;
|
||||
};
|
||||
|
||||
extern void show_version(const char *name, const struct version *ver);
|
Loading…
Add table
Add a link
Reference in a new issue