blob: d430cdf84b2ba990bdb88fb94792488590eae1a5 [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
Anas Nashif72565532017-12-12 08:19:25 -050020
Andrew Boiebc666ae2017-07-14 16:35:17 -070021def debug(text):
22 if not args.verbose:
23 return
24 sys.stdout.write(os.path.basename(sys.argv[0]) + ": " + text + "\n")
25
Anas Nashif72565532017-12-12 08:19:25 -050026
Andrew Boiebc666ae2017-07-14 16:35:17 -070027def error(text):
28 sys.stderr.write(os.path.basename(sys.argv[0]) + ": " + text + "\n")
29 sys.exit(1)
30
31
Andrew Boie08c29132017-07-14 15:29:17 -070032gdt_pd_fmt = "<HIH"
33
Anas Nashif72565532017-12-12 08:19:25 -050034FLAGS_GRAN = 1 << 7 # page granularity
Andrew Boie08c29132017-07-14 15:29:17 -070035ACCESS_EX = 1 << 3 # executable
36ACCESS_DC = 1 << 2 # direction/conforming
37ACCESS_RW = 1 << 1 # read or write permission
38
39# 6 byte pseudo descriptor, but we're going to actually use this as the
40# zero descriptor and return 8 bytes
Anas Nashif72565532017-12-12 08:19:25 -050041
42
Andrew Boie08c29132017-07-14 15:29:17 -070043def create_gdt_pseudo_desc(addr, size):
Andrew Boiea705eae2017-11-03 10:39:08 -070044 debug("create pseudo decriptor: %x %x" % (addr, size))
Andrew Boie08c29132017-07-14 15:29:17 -070045 # ...and take back one byte for the Intel god whose Ark this is...
46 size = size - 1
47 return struct.pack(gdt_pd_fmt, size, addr, 0)
48
49
50# Limit argument always in bytes
51def chop_base_limit(base, limit):
52 base_lo = base & 0xFFFF
53 base_mid = (base >> 16) & 0xFF
54 base_hi = (base >> 24) & 0xFF
55
56 limit_lo = limit & 0xFFFF
57 limit_hi = (limit >> 16) & 0xF
58
59 return (base_lo, base_mid, base_hi, limit_lo, limit_hi)
60
61
62gdt_ent_fmt = "<HHBBBB"
63
Anas Nashif72565532017-12-12 08:19:25 -050064
Andrew Boie08c29132017-07-14 15:29:17 -070065def create_code_data_entry(base, limit, dpl, flags, access):
Andrew Boiea705eae2017-11-03 10:39:08 -070066 debug("create code or data entry: %x %x %x %x %x" %
Anas Nashif72565532017-12-12 08:19:25 -050067 (base, limit, dpl, flags, access))
Andrew Boiea705eae2017-11-03 10:39:08 -070068
Andrew Boie08c29132017-07-14 15:29:17 -070069 base_lo, base_mid, base_hi, limit_lo, limit_hi = chop_base_limit(base,
Anas Nashif72565532017-12-12 08:19:25 -050070 limit)
Andrew Boie08c29132017-07-14 15:29:17 -070071
72 # This is a valid descriptor
73 present = 1
74
75 # 32-bit protected mode
76 size = 1
77
78 # 1 = code or data, 0 = system type
79 desc_type = 1
80
81 # Just set accessed to 1 already so the CPU doesn't need it update it,
82 # prevents freakouts if the GDT is in ROM, we don't care about this
83 # bit in the OS
84 accessed = 1
85
Andrew Boiea0da6322017-08-01 09:30:09 -070086 access = access | (present << 7) | (dpl << 5) | (desc_type << 4) | accessed
Andrew Boie08c29132017-07-14 15:29:17 -070087 flags = flags | (size << 6) | limit_hi
88
89 return struct.pack(gdt_ent_fmt, limit_lo, base_lo, base_mid,
90 access, flags, base_hi)
91
92
Andrew Boiebc666ae2017-07-14 16:35:17 -070093def create_tss_entry(base, limit, dpl):
Anas Nashif72565532017-12-12 08:19:25 -050094 debug("create TSS entry: %x %x %x" % (base, limit, dpl))
Andrew Boiebc666ae2017-07-14 16:35:17 -070095 present = 1
96
97 base_lo, base_mid, base_hi, limit_lo, limit_hi, = chop_base_limit(base,
Anas Nashif72565532017-12-12 08:19:25 -050098 limit)
Andrew Boiebc666ae2017-07-14 16:35:17 -070099
Anas Nashif72565532017-12-12 08:19:25 -0500100 type_code = 0x9 # non-busy 32-bit TSS descriptor
Andrew Boiebc666ae2017-07-14 16:35:17 -0700101 gran = 0
102
103 flags = (gran << 7) | limit_hi
104 type_byte = ((present << 7) | (dpl << 5) | type_code)
105
Andrew Boiebc666ae2017-07-14 16:35:17 -0700106 return struct.pack(gdt_ent_fmt, limit_lo, base_lo, base_mid,
107 type_byte, flags, base_hi)
108
109
Andrew Boie08c29132017-07-14 15:29:17 -0700110def get_symbols(obj):
111 for section in obj.iter_sections():
112 if isinstance(section, SymbolTableSection):
113 return {sym.name: sym.entry.st_value
114 for sym in section.iter_symbols()}
115
116 raise LookupError("Could not find symbol table")
117
118
119def parse_args():
120 global args
Anas Nashif72565532017-12-12 08:19:25 -0500121 parser = argparse.ArgumentParser(
122 description=__doc__,
123 formatter_class=argparse.RawDescriptionHelpFormatter)
Andrew Boie08c29132017-07-14 15:29:17 -0700124
125 parser.add_argument("-k", "--kernel", required=True,
Anas Nashif72565532017-12-12 08:19:25 -0500126 help="Zephyr kernel image")
Andrew Boie08c29132017-07-14 15:29:17 -0700127 parser.add_argument("-v", "--verbose", action="store_true",
Anas Nashif72565532017-12-12 08:19:25 -0500128 help="Print extra debugging information")
Andrew Boie08c29132017-07-14 15:29:17 -0700129 parser.add_argument("-o", "--output-gdt", required=True,
Anas Nashif72565532017-12-12 08:19:25 -0500130 help="output GDT binary")
Andrew Boie08c29132017-07-14 15:29:17 -0700131 args = parser.parse_args()
Sebastian Bøe4971d2a2017-12-28 17:34:50 +0100132 if "VERBOSE" in os.environ:
133 args.verbose = 1
Andrew Boie08c29132017-07-14 15:29:17 -0700134
135
136def main():
137 parse_args()
138
139 with open(args.kernel, "rb") as fp:
140 kernel = ELFFile(fp)
141 syms = get_symbols(kernel)
142
Andrew Boiebc666ae2017-07-14 16:35:17 -0700143 # NOTE: use-cases are extremely limited; we always have a basic flat
144 # code/data segments. If we are doing stack protection, we are going to
145 # have two TSS to manage the main task and the special task for double
146 # fault exception handling
Andrew Boiea705eae2017-11-03 10:39:08 -0700147 if "CONFIG_USERSPACE" in syms:
148 num_entries = 7
149 elif "CONFIG_HW_STACK_PROTECTION" in syms:
150 num_entries = 5
Andrew Boiebc666ae2017-07-14 16:35:17 -0700151 else:
Andrew Boiebc666ae2017-07-14 16:35:17 -0700152 num_entries = 3
Andrew Boie08c29132017-07-14 15:29:17 -0700153
154 gdt_base = syms["_gdt"]
155
156 with open(args.output_gdt, "wb") as fp:
157 # The pseudo descriptor is stuffed into the NULL descriptor
158 # since the CPU never looks at it
159 fp.write(create_gdt_pseudo_desc(gdt_base, num_entries * 8))
160
161 # Selector 0x08: code descriptor
162 fp.write(create_code_data_entry(0, 0xFFFFF, 0,
Anas Nashif72565532017-12-12 08:19:25 -0500163 FLAGS_GRAN, ACCESS_EX | ACCESS_RW))
Andrew Boie08c29132017-07-14 15:29:17 -0700164
165 # Selector 0x10: data descriptor
166 fp.write(create_code_data_entry(0, 0xFFFFF, 0,
Anas Nashif72565532017-12-12 08:19:25 -0500167 FLAGS_GRAN, ACCESS_RW))
Andrew Boie08c29132017-07-14 15:29:17 -0700168
Andrew Boiea705eae2017-11-03 10:39:08 -0700169 if num_entries >= 5:
Andrew Boiebc666ae2017-07-14 16:35:17 -0700170 main_tss = syms["_main_tss"]
171 df_tss = syms["_df_tss"]
172
173 # Selector 0x18: main TSS
174 fp.write(create_tss_entry(main_tss, 0x67, 0))
175
176 # Selector 0x20: double-fault TSS
177 fp.write(create_tss_entry(df_tss, 0x67, 0))
178
Andrew Boiea705eae2017-11-03 10:39:08 -0700179 if num_entries == 7:
180 # Selector 0x28: code descriptor, dpl = 3
181 fp.write(create_code_data_entry(0, 0xFFFFF, 3,
Anas Nashif72565532017-12-12 08:19:25 -0500182 FLAGS_GRAN, ACCESS_EX | ACCESS_RW))
Andrew Boie424e9932017-08-30 14:06:30 -0700183
Andrew Boiea705eae2017-11-03 10:39:08 -0700184 # Selector 0x30: data descriptor, dpl = 3
185 fp.write(create_code_data_entry(0, 0xFFFFF, 3,
Anas Nashif72565532017-12-12 08:19:25 -0500186 FLAGS_GRAN, ACCESS_RW))
Andrew Boie424e9932017-08-30 14:06:30 -0700187
Andrew Boiebc666ae2017-07-14 16:35:17 -0700188
Andrew Boie08c29132017-07-14 15:29:17 -0700189if __name__ == "__main__":
190 main()