blob: bf8b5eb7f46d255c4aaf5ff1ec35d2f76d4a1226 [file] [log] [blame]
Andrew Boie08c29132017-07-14 15:29:17 -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 Boie08c29132017-07-14 15:29:17 -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 Boiebc666ae2017-07-14 16:35:17 -070020def debug(text):
21 if not args.verbose:
22 return
23 sys.stdout.write(os.path.basename(sys.argv[0]) + ": " + text + "\n")
24
25def error(text):
26 sys.stderr.write(os.path.basename(sys.argv[0]) + ": " + text + "\n")
27 sys.exit(1)
28
29
Andrew Boie08c29132017-07-14 15:29:17 -070030gdt_pd_fmt = "<HIH"
31
32FLAGS_GRAN = 1 << 7 # page granularity
33ACCESS_EX = 1 << 3 # executable
34ACCESS_DC = 1 << 2 # direction/conforming
35ACCESS_RW = 1 << 1 # read or write permission
36
37# 6 byte pseudo descriptor, but we're going to actually use this as the
38# zero descriptor and return 8 bytes
39def create_gdt_pseudo_desc(addr, size):
40 # ...and take back one byte for the Intel god whose Ark this is...
41 size = size - 1
42 return struct.pack(gdt_pd_fmt, size, addr, 0)
43
44
45# Limit argument always in bytes
46def chop_base_limit(base, limit):
47 base_lo = base & 0xFFFF
48 base_mid = (base >> 16) & 0xFF
49 base_hi = (base >> 24) & 0xFF
50
51 limit_lo = limit & 0xFFFF
52 limit_hi = (limit >> 16) & 0xF
53
54 return (base_lo, base_mid, base_hi, limit_lo, limit_hi)
55
56
57gdt_ent_fmt = "<HHBBBB"
58
59def create_code_data_entry(base, limit, dpl, flags, access):
60 base_lo, base_mid, base_hi, limit_lo, limit_hi = chop_base_limit(base,
61 limit)
62
63 # This is a valid descriptor
64 present = 1
65
66 # 32-bit protected mode
67 size = 1
68
69 # 1 = code or data, 0 = system type
70 desc_type = 1
71
72 # Just set accessed to 1 already so the CPU doesn't need it update it,
73 # prevents freakouts if the GDT is in ROM, we don't care about this
74 # bit in the OS
75 accessed = 1
76
Andrew Boiea0da6322017-08-01 09:30:09 -070077 access = access | (present << 7) | (dpl << 5) | (desc_type << 4) | accessed
Andrew Boie08c29132017-07-14 15:29:17 -070078 flags = flags | (size << 6) | limit_hi
79
80 return struct.pack(gdt_ent_fmt, limit_lo, base_lo, base_mid,
81 access, flags, base_hi)
82
83
Andrew Boiebc666ae2017-07-14 16:35:17 -070084def create_tss_entry(base, limit, dpl):
85 present = 1
86
87 base_lo, base_mid, base_hi, limit_lo, limit_hi, = chop_base_limit(base,
88 limit)
89
90 type_code = 0x9 # non-busy 32-bit TSS descriptor
91 gran = 0
92
93 flags = (gran << 7) | limit_hi
94 type_byte = ((present << 7) | (dpl << 5) | type_code)
95
96
97 return struct.pack(gdt_ent_fmt, limit_lo, base_lo, base_mid,
98 type_byte, flags, base_hi)
99
100
Andrew Boie08c29132017-07-14 15:29:17 -0700101def get_symbols(obj):
102 for section in obj.iter_sections():
103 if isinstance(section, SymbolTableSection):
104 return {sym.name: sym.entry.st_value
105 for sym in section.iter_symbols()}
106
107 raise LookupError("Could not find symbol table")
108
109
110def parse_args():
111 global args
112 parser = argparse.ArgumentParser(description = __doc__,
113 formatter_class = argparse.RawDescriptionHelpFormatter)
114
115 parser.add_argument("-k", "--kernel", required=True,
116 help="Zephyr kernel image")
117 parser.add_argument("-v", "--verbose", action="store_true",
118 help="Print extra debugging information")
119 parser.add_argument("-o", "--output-gdt", required=True,
120 help="output GDT binary")
121 args = parser.parse_args()
122
123
124def main():
125 parse_args()
126
127 with open(args.kernel, "rb") as fp:
128 kernel = ELFFile(fp)
129 syms = get_symbols(kernel)
130
Andrew Boiebc666ae2017-07-14 16:35:17 -0700131 # NOTE: use-cases are extremely limited; we always have a basic flat
132 # code/data segments. If we are doing stack protection, we are going to
133 # have two TSS to manage the main task and the special task for double
134 # fault exception handling
135
136 if "CONFIG_X86_STACK_PROTECTION" in syms:
137 stackprot = True
138 num_entries = 5
139 else:
140 stackprot = False
141 num_entries = 3
Andrew Boie08c29132017-07-14 15:29:17 -0700142
143 gdt_base = syms["_gdt"]
144
145 with open(args.output_gdt, "wb") as fp:
146 # The pseudo descriptor is stuffed into the NULL descriptor
147 # since the CPU never looks at it
148 fp.write(create_gdt_pseudo_desc(gdt_base, num_entries * 8))
149
150 # Selector 0x08: code descriptor
151 fp.write(create_code_data_entry(0, 0xFFFFF, 0,
152 FLAGS_GRAN, ACCESS_EX | ACCESS_RW))
153
154 # Selector 0x10: data descriptor
155 fp.write(create_code_data_entry(0, 0xFFFFF, 0,
156 FLAGS_GRAN, ACCESS_RW))
157
Andrew Boiebc666ae2017-07-14 16:35:17 -0700158 if stackprot:
159 main_tss = syms["_main_tss"]
160 df_tss = syms["_df_tss"]
161
162 # Selector 0x18: main TSS
163 fp.write(create_tss_entry(main_tss, 0x67, 0))
164
165 # Selector 0x20: double-fault TSS
166 fp.write(create_tss_entry(df_tss, 0x67, 0))
167
168
Andrew Boie08c29132017-07-14 15:29:17 -0700169if __name__ == "__main__":
170 main()
171