-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgenerate-gdt
executable file
·117 lines (94 loc) · 3.56 KB
/
generate-gdt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#!/usr/bin/env python3
#
# Global Descriptor Table generator
# https://wiki.osdev.org/Global_Descriptor_Table
#
import os
class GdtEntry:
def __init__(self, name, base, limit, *, system, privilege_level, granularity_4k):
self.name = name
self.base = base
self.limit = limit
self.system = system
self.privilege_level = privilege_level
self.granularity_4k = granularity_4k
self.bits32 = True
self.bits64 = False
self.present = True
self.accessed = False
def encode(self):
access = (
self.present << 7 |
self.privilege_level << 5 |
(not self.system) << 4 |
self._type()
)
flags = (
self.granularity_4k << 3 |
self.bits32 << 2 |
self.bits64 << 1
)
data = ", ".join(
gdt_word if isinstance(gdt_word, str) else "0x{:04x}".format(gdt_word)
for gdt_word in (
self.limit if isinstance(self.limit, str) else self.limit & 0xFFFF,
self.base if isinstance(self.base, str) else self.base & 0xFFFF,
access << 8 | (0 if isinstance(self.base, str) else self.base >> 16 & 0xFF),
(0 if isinstance(self.base, str) else self.base >> 24 & 0xFF) << 8 | flags << 4 | (0 if isinstance(self.limit, str) else self.limit >> 16 & 0xF),
)
)
return "{name}_gdte: dw {data}".format(name=self.name, data=data)
class GdtCodeEntry(GdtEntry):
def __init__(self, name, base, limit, *, conforming, readable, **kwargs):
super().__init__(name, base, limit, system=False, granularity_4k=True, **kwargs)
self.__conforming = conforming
self.__readable = readable
def _type(self):
return (
True << 3 |
self.__conforming << 2 |
self.__readable << 1 |
self.accessed << 0
)
class GdtDataEntry(GdtEntry):
def __init__(self, name, base, limit, *, writable, **kwargs):
super().__init__(name, base, limit, system=False, granularity_4k=True, **kwargs)
self.__grows_down = False
self.__writable = writable
def _type(self):
return (
False << 3 |
self.__grows_down << 2 |
self.__writable << 1 |
self.accessed << 0
)
class GdtSystemEntry(GdtEntry):
def __init__(self, name, base, limit):
super().__init__(name, base, limit, system=True, privilege_level=0, granularity_4k=False)
def _type(self):
return 0x9
TEMPLATE = """\
; Generated by {generator}, DO NOT EDIT
gdt:
null_gdte: dw 0x0000, 0x0000, 0x0000, 0x0000
{entries}
gdtr:
gdt_size: dw gdtr - gdt
gdt_base: dd gdt
"""
def generate(path):
encoded_entries = [entry.encode() for entry in [
GdtCodeEntry("kernel_code", 0, 0xFFFFF, readable=True, conforming=False, privilege_level=0),
GdtDataEntry("kernel_data", 0, 0xFFFFF, writable=True, privilege_level=0),
GdtCodeEntry("user_code", 0, 0xFFFFF, readable=True, conforming=False, privilege_level=3),
GdtDataEntry("user_data", 0, 0xFFFFF, writable=True, privilege_level=3),
GdtSystemEntry("tss", "tss", "tss_end - tss"),
]]
data = TEMPLATE.format(
generator=os.path.basename(__file__),
entries="\n ".join(encoded_entries),
)
with open(path, "w") as file:
file.write(data)
if __name__ == "__main__":
generate(os.path.join(os.path.dirname(__file__), "gdt.asm"))