blob: b70bbd58e04172d2672641655af02f227c60b918 [file] [log] [blame]
Andrew Boieddf9f4b2017-07-14 12:48:35 -07001#!/usr/bin/env python3
2#
3# Copyright (c) 2017 Intel Corporation
4#
5# SPDX-License-Identifier: Apache-2.0
6
7import argparse
8import sys
9import struct
10import os
Andrew Boie3aecba12017-07-25 09:44:30 -070011import elftools
12from distutils.version import LooseVersion
Andrew Boieddf9f4b2017-07-14 12:48:35 -070013from elftools.elf.elffile import ELFFile
14from elftools.elf.sections import SymbolTableSection
15
Andrew Boie3aecba12017-07-25 09:44:30 -070016if LooseVersion(elftools.__version__) < LooseVersion('0.24'):
17 sys.stderr.write("pyelftools is out of date, need version 0.24 or later\n")
18 sys.exit(1)
19
Andrew Boieddf9f4b2017-07-14 12:48:35 -070020# This will never change, first selector in the GDT after the null selector
21KERNEL_CODE_SEG = 0x08
22
23# These exception vectors push an error code onto the stack.
24ERR_CODE_VECTORS = [8, 10, 11, 12, 13, 14, 17]
25
Anas Nashif72565532017-12-12 08:19:25 -050026
Andrew Boieddf9f4b2017-07-14 12:48:35 -070027def debug(text):
28 if not args.verbose:
29 return
30 sys.stdout.write(os.path.basename(sys.argv[0]) + ": " + text + "\n")
31
Anas Nashif72565532017-12-12 08:19:25 -050032
Andrew Boieddf9f4b2017-07-14 12:48:35 -070033def error(text):
34 sys.stderr.write(os.path.basename(sys.argv[0]) + ": " + text + "\n")
35 sys.exit(1)
36
Anas Nashif72565532017-12-12 08:19:25 -050037
Andrew Boieddf9f4b2017-07-14 12:48:35 -070038# See Section 6.11 of the Intel Architecture Software Developer's Manual
Andrew Boie8a102e42017-07-14 13:29:19 -070039gate_desc_format = "<HHBBH"
Andrew Boieddf9f4b2017-07-14 12:48:35 -070040
Anas Nashif72565532017-12-12 08:19:25 -050041
Andrew Boieddf9f4b2017-07-14 12:48:35 -070042def create_irq_gate(handler, dpl):
43 present = 1
Anas Nashif72565532017-12-12 08:19:25 -050044 gate_type = 0xE # 32-bit interrupt gate
Andrew Boieddf9f4b2017-07-14 12:48:35 -070045 type_attr = gate_type | (dpl << 5) | (present << 7)
46
47 offset_hi = handler >> 16
48 offset_lo = handler & 0xFFFF
49
Andrew Boie8a102e42017-07-14 13:29:19 -070050 data = struct.pack(gate_desc_format, offset_lo, KERNEL_CODE_SEG, 0,
Anas Nashif72565532017-12-12 08:19:25 -050051 type_attr, offset_hi)
Andrew Boieddf9f4b2017-07-14 12:48:35 -070052 return data
53
Andrew Boie8a102e42017-07-14 13:29:19 -070054
55def create_task_gate(tss, dpl):
56 present = 1
Anas Nashif72565532017-12-12 08:19:25 -050057 gate_type = 0x5 # 32-bit task gate
Andrew Boie8a102e42017-07-14 13:29:19 -070058 type_attr = gate_type | (dpl << 5) | (present << 7)
59
60 data = struct.pack(gate_desc_format, 0, tss, 0, type_attr, 0)
61 return data
62
63
Andrew Boieddf9f4b2017-07-14 12:48:35 -070064def create_idt_binary(idt_config, filename):
65 with open(filename, "wb") as fp:
Andrew Boie8a102e42017-07-14 13:29:19 -070066 for handler, tss, dpl in idt_config:
67 if handler and tss:
68 error("entry specifies both handler function and tss")
69
70 if not handler and not tss:
71 error("entry does not specify either handler or tss")
72
73 if handler:
74 data = create_irq_gate(handler, dpl)
75 else:
76 data = create_task_gate(tss, dpl)
77
Andrew Boieddf9f4b2017-07-14 12:48:35 -070078 fp.write(data)
79
Anas Nashif72565532017-12-12 08:19:25 -050080
Andrew Boieddf9f4b2017-07-14 12:48:35 -070081map_fmt = "<B"
82
Anas Nashif72565532017-12-12 08:19:25 -050083
Andrew Boieddf9f4b2017-07-14 12:48:35 -070084def create_irq_vec_map_binary(irq_vec_map, filename):
85 with open(filename, "wb") as fp:
86 for i in irq_vec_map:
87 fp.write(struct.pack(map_fmt, i))
88
Anas Nashif72565532017-12-12 08:19:25 -050089
Andrew Boieddf9f4b2017-07-14 12:48:35 -070090def priority_range(prio):
91 # Priority levels are represented as groups of 16 vectors within the IDT
92 base = 32 + (prio * 16)
93 return range(base, base + 16)
94
95
96def update_irq_vec_map(irq_vec_map, irq, vector, max_irq):
97 # No IRQ associated; exception or software interrupt
98 if irq == -1:
99 return
100
101 if irq >= max_irq:
102 error("irq %d specified, but CONFIG_MAX_IRQ_LINES is %d" %
Anas Nashif72565532017-12-12 08:19:25 -0500103 (irq, max_irq))
Andrew Boieddf9f4b2017-07-14 12:48:35 -0700104
105 # This table will never have values less than 32 since those are for
106 # exceptions; 0 means unconfigured
107 if irq_vec_map[irq] != 0:
108 error("multiple vector assignments for interrupt line %d", irq)
109
110 debug("assign IRQ %d to vector %d" % (irq, vector))
111 irq_vec_map[irq] = vector
112
113
114def setup_idt(spur_code, spur_nocode, intlist, max_vec, max_irq):
115 irq_vec_map = [0 for i in range(max_irq)]
116 vectors = [None for i in range(max_vec)]
117
118 # Pass 1: sanity check and set up hard-coded interrupt vectors
Andrew Boie8a102e42017-07-14 13:29:19 -0700119 for handler, irq, prio, vec, dpl, tss in intlist:
Andrew Boieddf9f4b2017-07-14 12:48:35 -0700120 if vec == -1:
121 if prio == -1:
122 error("entry does not specify vector or priority level")
123 continue
124
125 if vec >= max_vec:
126 error("Vector %d specified, but size of IDT is only %d vectors" %
Anas Nashif72565532017-12-12 08:19:25 -0500127 (vec, max_vec))
Andrew Boieddf9f4b2017-07-14 12:48:35 -0700128
Anas Nashif72565532017-12-12 08:19:25 -0500129 if vectors[vec] is not None:
Andrew Boieddf9f4b2017-07-14 12:48:35 -0700130 error("Multiple assignments for vector %d" % vec)
131
Andrew Boie8a102e42017-07-14 13:29:19 -0700132 vectors[vec] = (handler, tss, dpl)
Andrew Boieddf9f4b2017-07-14 12:48:35 -0700133 update_irq_vec_map(irq_vec_map, irq, vec, max_irq)
134
135 # Pass 2: set up priority-based interrupt vectors
Andrew Boie8a102e42017-07-14 13:29:19 -0700136 for handler, irq, prio, vec, dpl, tss in intlist:
Andrew Boieddf9f4b2017-07-14 12:48:35 -0700137 if vec != -1:
138 continue
139
140 for vi in priority_range(prio):
141 if vi >= max_vec:
142 break
Anas Nashif72565532017-12-12 08:19:25 -0500143 if vectors[vi] is None:
Andrew Boieddf9f4b2017-07-14 12:48:35 -0700144 vec = vi
145 break
146
147 if vec == -1:
148 error("can't find a free vector in priority level %d" % prio)
149
Andrew Boie8a102e42017-07-14 13:29:19 -0700150 vectors[vec] = (handler, tss, dpl)
Andrew Boieddf9f4b2017-07-14 12:48:35 -0700151 update_irq_vec_map(irq_vec_map, irq, vec, max_irq)
152
153 # Pass 3: fill in unused vectors with spurious handler at dpl=0
154 for i in range(max_vec):
Anas Nashif72565532017-12-12 08:19:25 -0500155 if vectors[i] is not None:
Andrew Boieddf9f4b2017-07-14 12:48:35 -0700156 continue
157
158 if i in ERR_CODE_VECTORS:
159 handler = spur_code
160 else:
161 handler = spur_nocode
162
Andrew Boie8a102e42017-07-14 13:29:19 -0700163 vectors[i] = (handler, 0, 0)
Andrew Boieddf9f4b2017-07-14 12:48:35 -0700164
165 return vectors, irq_vec_map
166
Anas Nashif72565532017-12-12 08:19:25 -0500167
Andrew Boieddf9f4b2017-07-14 12:48:35 -0700168def get_symbols(obj):
169 for section in obj.iter_sections():
170 if isinstance(section, SymbolTableSection):
171 return {sym.name: sym.entry.st_value
172 for sym in section.iter_symbols()}
173
174 raise LookupError("Could not find symbol table")
175
176# struct genidt_header_s {
177# uint32_t spurious_addr;
178# uint32_t spurious_no_error_addr;
179# int32_t num_entries;
180# };
181
182
Sebastian Bøea1e806b2018-06-25 16:46:13 +0200183intlist_header_fmt = "<II"
Andrew Boieddf9f4b2017-07-14 12:48:35 -0700184
185# struct genidt_entry_s {
186# uint32_t isr;
187# int32_t irq;
188# int32_t priority;
189# int32_t vector_id;
190# int32_t dpl;
Andrew Boie8a102e42017-07-14 13:29:19 -0700191# int32_t tss;
Andrew Boieddf9f4b2017-07-14 12:48:35 -0700192# };
193
Andrew Boie8a102e42017-07-14 13:29:19 -0700194intlist_entry_fmt = "<Iiiiii"
Andrew Boieddf9f4b2017-07-14 12:48:35 -0700195
Anas Nashif72565532017-12-12 08:19:25 -0500196
Andrew Boieddf9f4b2017-07-14 12:48:35 -0700197def get_intlist(elf):
198 intdata = elf.get_section_by_name("intList").data()
199
200 header_sz = struct.calcsize(intlist_header_fmt)
201 header = struct.unpack_from(intlist_header_fmt, intdata, 0)
202 intdata = intdata[header_sz:]
203
204 spurious_code = header[0]
205 spurious_nocode = header[1]
206
207 debug("spurious handler (code) : %s" % hex(header[0]))
208 debug("spurious handler (no code) : %s" % hex(header[1]))
209
210 intlist = [i for i in
Anas Nashif72565532017-12-12 08:19:25 -0500211 struct.iter_unpack(intlist_entry_fmt, intdata)]
Andrew Boieddf9f4b2017-07-14 12:48:35 -0700212
213 debug("Configured interrupt routing")
214 debug("handler irq pri vec dpl")
215 debug("--------------------------")
216
217 for irq in intlist:
218 debug("{0:<10} {1:<3} {2:<3} {3:<3} {4:<2}".format(
219 hex(irq[0]),
220 "-" if irq[1] == -1 else irq[1],
221 "-" if irq[2] == -1 else irq[2],
222 "-" if irq[3] == -1 else irq[3],
223 irq[4]))
224
225 return (spurious_code, spurious_nocode, intlist)
226
227
228def parse_args():
229 global args
Anas Nashif72565532017-12-12 08:19:25 -0500230 parser = argparse.ArgumentParser(
231 description=__doc__,
232 formatter_class=argparse.RawDescriptionHelpFormatter)
Andrew Boieddf9f4b2017-07-14 12:48:35 -0700233
234 parser.add_argument("-m", "--vector-map", required=True,
Anas Nashif72565532017-12-12 08:19:25 -0500235 help="Output file mapping IRQ lines to IDT vectors")
Andrew Boieddf9f4b2017-07-14 12:48:35 -0700236 parser.add_argument("-o", "--output-idt", required=True,
Anas Nashif72565532017-12-12 08:19:25 -0500237 help="Output file containing IDT binary")
Andrew Boie7bac15f2018-10-30 16:55:38 -0700238 parser.add_argument("-a", "--output-vectors-alloc", required=False,
239 help="Output file indicating allocated vectors")
Andrew Boieddf9f4b2017-07-14 12:48:35 -0700240 parser.add_argument("-k", "--kernel", required=True,
Anas Nashif72565532017-12-12 08:19:25 -0500241 help="Zephyr kernel image")
Andrew Boieddf9f4b2017-07-14 12:48:35 -0700242 parser.add_argument("-v", "--verbose", action="store_true",
Anas Nashif72565532017-12-12 08:19:25 -0500243 help="Print extra debugging information")
Andrew Boieddf9f4b2017-07-14 12:48:35 -0700244 args = parser.parse_args()
Sebastian Bøe4971d2a2017-12-28 17:34:50 +0100245 if "VERBOSE" in os.environ:
246 args.verbose = 1
Andrew Boieddf9f4b2017-07-14 12:48:35 -0700247
248
Andrew Boie7bac15f2018-10-30 16:55:38 -0700249def create_irq_vectors_allocated(vectors, spur_code, spur_nocode, filename):
250 # Construct a bitfield over all the IDT vectors, where if bit n is 1,
251 # that vector is free. those vectors have either of the two spurious
252 # interrupt handlers installed, they are free for runtime installation
253 # of interrupts
254 num_chars = (len(vectors) + 7) // 8
255 vbits = [0 for i in range(num_chars)]
256 for i in range(len(vectors)):
257 handler, _, _ = vectors[i]
258 if handler != spur_code and handler != spur_nocode:
259 continue
260
261 vbit_index = i // 8
262 vbit_val = 1 << (i % 8)
263 vbits[vbit_index] = vbits[vbit_index] | vbit_val
264
265 with open(filename, "wb") as fp:
266 for char in vbits:
267 fp.write(struct.pack("<B", char))
268
269
Andrew Boieddf9f4b2017-07-14 12:48:35 -0700270def main():
271 parse_args()
272
273 with open(args.kernel, "rb") as fp:
274 kernel = ELFFile(fp)
275
276 syms = get_symbols(kernel)
277 spur_code, spur_nocode, intlist = get_intlist(kernel)
278
279 max_irq = syms["CONFIG_MAX_IRQ_LINES"]
280 max_vec = syms["CONFIG_IDT_NUM_VECTORS"]
281
282 vectors, irq_vec_map = setup_idt(spur_code, spur_nocode, intlist, max_vec,
283 max_irq)
284
285 create_idt_binary(vectors, args.output_idt)
286 create_irq_vec_map_binary(irq_vec_map, args.vector_map)
Andrew Boie7bac15f2018-10-30 16:55:38 -0700287 if args.output_vectors_alloc:
288 create_irq_vectors_allocated(vectors, spur_code, spur_nocode,
289 args.output_vectors_alloc)
Andrew Boieddf9f4b2017-07-14 12:48:35 -0700290
Anas Nashif72565532017-12-12 08:19:25 -0500291
Andrew Boieddf9f4b2017-07-14 12:48:35 -0700292if __name__ == "__main__":
293 main()