pyOS-kernel 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyos/__init__.py +22 -0
- pyos/boot/__init__.py +3 -0
- pyos/boot/bootloader.asm +174 -0
- pyos/builder.py +177 -0
- pyos/cli.py +286 -0
- pyos/compiler/__init__.py +8 -0
- pyos/compiler/assembler.py +180 -0
- pyos/compiler/codegen.py +238 -0
- pyos/drivers/__init__.py +8 -0
- pyos/drivers/keyboard.py +319 -0
- pyos/drivers/screen.py +310 -0
- pyos/emulator.py +195 -0
- pyos/interrupts/__init__.py +8 -0
- pyos/interrupts/handler.py +237 -0
- pyos/interrupts/idt.py +165 -0
- pyos/kernel.py +288 -0
- pyos/memory/__init__.py +8 -0
- pyos/memory/gdt.py +295 -0
- pyos/memory/manager.py +397 -0
- pyos/syscalls/__init__.py +7 -0
- pyos/syscalls/handler.py +179 -0
- pyos_kernel-0.1.0.dist-info/METADATA +323 -0
- pyos_kernel-0.1.0.dist-info/RECORD +27 -0
- pyos_kernel-0.1.0.dist-info/WHEEL +5 -0
- pyos_kernel-0.1.0.dist-info/entry_points.txt +2 -0
- pyos_kernel-0.1.0.dist-info/licenses/LICENSE +21 -0
- pyos_kernel-0.1.0.dist-info/top_level.txt +1 -0
pyos/kernel.py
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
"""
|
|
2
|
+
pyOS Kernel - The core of your operating system
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Callable, Optional, List, Dict, Any
|
|
6
|
+
from dataclasses import dataclass, field
|
|
7
|
+
from enum import Enum
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Architecture(Enum):
|
|
11
|
+
X86 = "x86"
|
|
12
|
+
X86_64 = "x86_64"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class KernelConfig:
|
|
17
|
+
"""Configuration for the kernel"""
|
|
18
|
+
arch: Architecture = Architecture.X86
|
|
19
|
+
stack_size: int = 16384 # 16KB stack
|
|
20
|
+
heap_size: int = 1048576 # 1MB heap
|
|
21
|
+
video_mode: str = "text" # text or graphics
|
|
22
|
+
enable_interrupts: bool = True
|
|
23
|
+
enable_gdt: bool = True
|
|
24
|
+
enable_paging: bool = False
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class KernelFunction:
|
|
29
|
+
"""Represents a registered kernel function"""
|
|
30
|
+
name: str
|
|
31
|
+
func: Callable
|
|
32
|
+
event: str
|
|
33
|
+
priority: int = 0
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Kernel:
|
|
37
|
+
"""
|
|
38
|
+
The main Kernel class for building operating systems.
|
|
39
|
+
|
|
40
|
+
Example:
|
|
41
|
+
kernel = Kernel(arch="x86")
|
|
42
|
+
|
|
43
|
+
@kernel.on_boot
|
|
44
|
+
def main():
|
|
45
|
+
Screen.print("Hello from MyOS!")
|
|
46
|
+
|
|
47
|
+
kernel.build("myos.iso")
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
def __init__(
|
|
51
|
+
self,
|
|
52
|
+
arch: str = "x86",
|
|
53
|
+
stack_size: int = 16384,
|
|
54
|
+
heap_size: int = 1048576,
|
|
55
|
+
enable_interrupts: bool = True,
|
|
56
|
+
enable_gdt: bool = True,
|
|
57
|
+
):
|
|
58
|
+
"""
|
|
59
|
+
Initialize a new Kernel.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
arch: Target architecture ("x86" or "x86_64")
|
|
63
|
+
stack_size: Stack size in bytes (default 16KB)
|
|
64
|
+
heap_size: Heap size in bytes (default 1MB)
|
|
65
|
+
enable_interrupts: Enable interrupt handling
|
|
66
|
+
enable_gdt: Enable Global Descriptor Table
|
|
67
|
+
"""
|
|
68
|
+
self.config = KernelConfig(
|
|
69
|
+
arch=Architecture(arch),
|
|
70
|
+
stack_size=stack_size,
|
|
71
|
+
heap_size=heap_size,
|
|
72
|
+
enable_interrupts=enable_interrupts,
|
|
73
|
+
enable_gdt=enable_gdt,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
self._boot_functions: List[KernelFunction] = []
|
|
77
|
+
self._interrupt_handlers: Dict[int, KernelFunction] = {}
|
|
78
|
+
self._syscall_handlers: Dict[int, KernelFunction] = {}
|
|
79
|
+
self._keypress_handlers: List[KernelFunction] = []
|
|
80
|
+
self._timer_handlers: List[KernelFunction] = []
|
|
81
|
+
self._custom_handlers: Dict[str, List[KernelFunction]] = {}
|
|
82
|
+
|
|
83
|
+
self._compiled_asm: Optional[str] = None
|
|
84
|
+
self._compiled_binary: Optional[bytes] = None
|
|
85
|
+
|
|
86
|
+
def on_boot(self, func: Callable = None, *, priority: int = 0):
|
|
87
|
+
"""
|
|
88
|
+
Decorator to register a function to run at boot.
|
|
89
|
+
|
|
90
|
+
Example:
|
|
91
|
+
@kernel.on_boot
|
|
92
|
+
def start():
|
|
93
|
+
Screen.print("Booting...")
|
|
94
|
+
"""
|
|
95
|
+
def decorator(f: Callable) -> Callable:
|
|
96
|
+
self._boot_functions.append(KernelFunction(
|
|
97
|
+
name=f.__name__,
|
|
98
|
+
func=f,
|
|
99
|
+
event="boot",
|
|
100
|
+
priority=priority,
|
|
101
|
+
))
|
|
102
|
+
# Sort by priority (higher first)
|
|
103
|
+
self._boot_functions.sort(key=lambda x: -x.priority)
|
|
104
|
+
return f
|
|
105
|
+
|
|
106
|
+
if func is not None:
|
|
107
|
+
return decorator(func)
|
|
108
|
+
return decorator
|
|
109
|
+
|
|
110
|
+
def on_keypress(self, func: Callable = None, *, key: str = None):
|
|
111
|
+
"""
|
|
112
|
+
Decorator to handle keyboard input.
|
|
113
|
+
|
|
114
|
+
Example:
|
|
115
|
+
@kernel.on_keypress
|
|
116
|
+
def handle_key(key):
|
|
117
|
+
Screen.print(f"Pressed: {key}")
|
|
118
|
+
"""
|
|
119
|
+
def decorator(f: Callable) -> Callable:
|
|
120
|
+
self._keypress_handlers.append(KernelFunction(
|
|
121
|
+
name=f.__name__,
|
|
122
|
+
func=f,
|
|
123
|
+
event="keypress",
|
|
124
|
+
))
|
|
125
|
+
return f
|
|
126
|
+
|
|
127
|
+
if func is not None:
|
|
128
|
+
return decorator(func)
|
|
129
|
+
return decorator
|
|
130
|
+
|
|
131
|
+
def on_interrupt(self, interrupt_number: int):
|
|
132
|
+
"""
|
|
133
|
+
Decorator to handle a specific interrupt.
|
|
134
|
+
|
|
135
|
+
Example:
|
|
136
|
+
@kernel.on_interrupt(0x21) # Keyboard interrupt
|
|
137
|
+
def keyboard_handler():
|
|
138
|
+
pass
|
|
139
|
+
"""
|
|
140
|
+
def decorator(func: Callable) -> Callable:
|
|
141
|
+
self._interrupt_handlers[interrupt_number] = KernelFunction(
|
|
142
|
+
name=func.__name__,
|
|
143
|
+
func=func,
|
|
144
|
+
event=f"interrupt_{interrupt_number}",
|
|
145
|
+
)
|
|
146
|
+
return func
|
|
147
|
+
return decorator
|
|
148
|
+
|
|
149
|
+
def on_syscall(self, syscall_number: int):
|
|
150
|
+
"""
|
|
151
|
+
Decorator to register a system call handler.
|
|
152
|
+
|
|
153
|
+
Example:
|
|
154
|
+
@kernel.on_syscall(1) # sys_write
|
|
155
|
+
def sys_write(fd, buf, count):
|
|
156
|
+
pass
|
|
157
|
+
"""
|
|
158
|
+
def decorator(func: Callable) -> Callable:
|
|
159
|
+
self._syscall_handlers[syscall_number] = KernelFunction(
|
|
160
|
+
name=func.__name__,
|
|
161
|
+
func=func,
|
|
162
|
+
event=f"syscall_{syscall_number}",
|
|
163
|
+
)
|
|
164
|
+
return func
|
|
165
|
+
return decorator
|
|
166
|
+
|
|
167
|
+
def on_timer(self, interval_ms: int = 1000):
|
|
168
|
+
"""
|
|
169
|
+
Decorator to register a timer handler.
|
|
170
|
+
|
|
171
|
+
Example:
|
|
172
|
+
@kernel.on_timer(interval_ms=1000)
|
|
173
|
+
def every_second():
|
|
174
|
+
pass
|
|
175
|
+
"""
|
|
176
|
+
def decorator(func: Callable) -> Callable:
|
|
177
|
+
handler = KernelFunction(
|
|
178
|
+
name=func.__name__,
|
|
179
|
+
func=func,
|
|
180
|
+
event="timer",
|
|
181
|
+
)
|
|
182
|
+
handler.interval_ms = interval_ms
|
|
183
|
+
self._timer_handlers.append(handler)
|
|
184
|
+
return func
|
|
185
|
+
return decorator
|
|
186
|
+
|
|
187
|
+
def on_event(self, event_name: str):
|
|
188
|
+
"""
|
|
189
|
+
Decorator to register a custom event handler.
|
|
190
|
+
|
|
191
|
+
Example:
|
|
192
|
+
@kernel.on_event("custom_event")
|
|
193
|
+
def handle_custom():
|
|
194
|
+
pass
|
|
195
|
+
"""
|
|
196
|
+
def decorator(func: Callable) -> Callable:
|
|
197
|
+
if event_name not in self._custom_handlers:
|
|
198
|
+
self._custom_handlers[event_name] = []
|
|
199
|
+
self._custom_handlers[event_name].append(KernelFunction(
|
|
200
|
+
name=func.__name__,
|
|
201
|
+
func=func,
|
|
202
|
+
event=event_name,
|
|
203
|
+
))
|
|
204
|
+
return func
|
|
205
|
+
return decorator
|
|
206
|
+
|
|
207
|
+
def compile(self) -> str:
|
|
208
|
+
"""
|
|
209
|
+
Compile the kernel to Assembly code.
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
The generated Assembly code as a string.
|
|
213
|
+
"""
|
|
214
|
+
from .compiler.codegen import CodeGenerator
|
|
215
|
+
|
|
216
|
+
generator = CodeGenerator(self)
|
|
217
|
+
self._compiled_asm = generator.generate()
|
|
218
|
+
return self._compiled_asm
|
|
219
|
+
|
|
220
|
+
def assemble(self) -> bytes:
|
|
221
|
+
"""
|
|
222
|
+
Assemble the kernel to machine code.
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
The binary machine code.
|
|
226
|
+
"""
|
|
227
|
+
if self._compiled_asm is None:
|
|
228
|
+
self.compile()
|
|
229
|
+
|
|
230
|
+
from .compiler.assembler import Assembler
|
|
231
|
+
|
|
232
|
+
assembler = Assembler(self.config.arch)
|
|
233
|
+
self._compiled_binary = assembler.assemble(self._compiled_asm)
|
|
234
|
+
return self._compiled_binary
|
|
235
|
+
|
|
236
|
+
def build(self, output: str, format: str = "iso") -> str:
|
|
237
|
+
"""
|
|
238
|
+
Build the complete OS image.
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
output: Output file path
|
|
242
|
+
format: Output format ("iso" or "bin")
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
Path to the generated file.
|
|
246
|
+
"""
|
|
247
|
+
from .builder import OSBuilder
|
|
248
|
+
|
|
249
|
+
if self._compiled_binary is None:
|
|
250
|
+
self.assemble()
|
|
251
|
+
|
|
252
|
+
builder = OSBuilder(self)
|
|
253
|
+
|
|
254
|
+
if format == "iso":
|
|
255
|
+
return builder.build_iso(output)
|
|
256
|
+
elif format == "bin":
|
|
257
|
+
return builder.build_bin(output)
|
|
258
|
+
else:
|
|
259
|
+
raise ValueError(f"Unknown format: {format}")
|
|
260
|
+
|
|
261
|
+
def run(self, image_path: str = None, debug: bool = False):
|
|
262
|
+
"""
|
|
263
|
+
Run the OS in QEMU.
|
|
264
|
+
|
|
265
|
+
Args:
|
|
266
|
+
image_path: Path to the OS image (builds if None)
|
|
267
|
+
debug: Enable QEMU debug mode
|
|
268
|
+
"""
|
|
269
|
+
from .emulator import QEMURunner
|
|
270
|
+
|
|
271
|
+
if image_path is None:
|
|
272
|
+
image_path = self.build("temp_os.iso")
|
|
273
|
+
|
|
274
|
+
runner = QEMURunner(self.config.arch)
|
|
275
|
+
runner.run(image_path, debug=debug)
|
|
276
|
+
|
|
277
|
+
def get_info(self) -> Dict[str, Any]:
|
|
278
|
+
"""Get information about the kernel configuration."""
|
|
279
|
+
return {
|
|
280
|
+
"architecture": self.config.arch.value,
|
|
281
|
+
"stack_size": self.config.stack_size,
|
|
282
|
+
"heap_size": self.config.heap_size,
|
|
283
|
+
"interrupts_enabled": self.config.enable_interrupts,
|
|
284
|
+
"gdt_enabled": self.config.enable_gdt,
|
|
285
|
+
"boot_functions": len(self._boot_functions),
|
|
286
|
+
"interrupt_handlers": len(self._interrupt_handlers),
|
|
287
|
+
"syscall_handlers": len(self._syscall_handlers),
|
|
288
|
+
}
|
pyos/memory/__init__.py
ADDED
pyos/memory/gdt.py
ADDED
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
"""
|
|
2
|
+
pyOS GDT (Global Descriptor Table) Management
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import List, Optional
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from enum import Enum, Flag
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SegmentType(Enum):
|
|
11
|
+
"""Segment types for GDT entries"""
|
|
12
|
+
NULL = 0
|
|
13
|
+
CODE_EXECUTE_ONLY = 0x8
|
|
14
|
+
CODE_EXECUTE_READ = 0xA
|
|
15
|
+
CODE_CONFORMING_EXECUTE_ONLY = 0xC
|
|
16
|
+
CODE_CONFORMING_EXECUTE_READ = 0xE
|
|
17
|
+
DATA_READ_ONLY = 0x0
|
|
18
|
+
DATA_READ_WRITE = 0x2
|
|
19
|
+
DATA_EXPAND_DOWN_READ_ONLY = 0x4
|
|
20
|
+
DATA_EXPAND_DOWN_READ_WRITE = 0x6
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class PrivilegeLevel(Enum):
|
|
24
|
+
"""CPU privilege levels (rings)"""
|
|
25
|
+
RING0 = 0 # Kernel mode
|
|
26
|
+
RING1 = 1
|
|
27
|
+
RING2 = 2
|
|
28
|
+
RING3 = 3 # User mode
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class GDTEntry:
|
|
33
|
+
"""
|
|
34
|
+
Represents a single GDT entry.
|
|
35
|
+
|
|
36
|
+
Attributes:
|
|
37
|
+
base: Base address of the segment
|
|
38
|
+
limit: Size of the segment
|
|
39
|
+
segment_type: Type of segment (code/data)
|
|
40
|
+
privilege: Privilege level (ring)
|
|
41
|
+
present: Is segment present in memory
|
|
42
|
+
granularity: Limit granularity (byte or 4KB)
|
|
43
|
+
is_32bit: 32-bit or 16-bit segment
|
|
44
|
+
"""
|
|
45
|
+
base: int = 0
|
|
46
|
+
limit: int = 0xFFFFF
|
|
47
|
+
segment_type: SegmentType = SegmentType.DATA_READ_WRITE
|
|
48
|
+
privilege: PrivilegeLevel = PrivilegeLevel.RING0
|
|
49
|
+
present: bool = True
|
|
50
|
+
granularity: bool = True # True = 4KB, False = 1 byte
|
|
51
|
+
is_32bit: bool = True
|
|
52
|
+
|
|
53
|
+
def to_bytes(self) -> bytes:
|
|
54
|
+
"""Convert GDT entry to 8-byte descriptor."""
|
|
55
|
+
# Limit (bits 0-15)
|
|
56
|
+
limit_low = self.limit & 0xFFFF
|
|
57
|
+
# Base (bits 0-15)
|
|
58
|
+
base_low = self.base & 0xFFFF
|
|
59
|
+
# Base (bits 16-23)
|
|
60
|
+
base_mid = (self.base >> 16) & 0xFF
|
|
61
|
+
|
|
62
|
+
# Access byte
|
|
63
|
+
access = 0
|
|
64
|
+
if self.present:
|
|
65
|
+
access |= 0x80 # Present bit
|
|
66
|
+
access |= (self.privilege.value << 5) # DPL
|
|
67
|
+
access |= 0x10 # Descriptor type (1 = code/data)
|
|
68
|
+
access |= self.segment_type.value
|
|
69
|
+
|
|
70
|
+
# Flags + Limit (bits 16-19)
|
|
71
|
+
flags_limit = (self.limit >> 16) & 0x0F
|
|
72
|
+
if self.granularity:
|
|
73
|
+
flags_limit |= 0x80 # Granularity
|
|
74
|
+
if self.is_32bit:
|
|
75
|
+
flags_limit |= 0x40 # 32-bit
|
|
76
|
+
|
|
77
|
+
# Base (bits 24-31)
|
|
78
|
+
base_high = (self.base >> 24) & 0xFF
|
|
79
|
+
|
|
80
|
+
return bytes([
|
|
81
|
+
limit_low & 0xFF,
|
|
82
|
+
(limit_low >> 8) & 0xFF,
|
|
83
|
+
base_low & 0xFF,
|
|
84
|
+
(base_low >> 8) & 0xFF,
|
|
85
|
+
base_mid,
|
|
86
|
+
access,
|
|
87
|
+
flags_limit,
|
|
88
|
+
base_high,
|
|
89
|
+
])
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class GDT:
|
|
93
|
+
"""
|
|
94
|
+
Global Descriptor Table Manager.
|
|
95
|
+
|
|
96
|
+
The GDT defines memory segments for the CPU.
|
|
97
|
+
|
|
98
|
+
Example:
|
|
99
|
+
gdt = GDT()
|
|
100
|
+
gdt.add_null_descriptor()
|
|
101
|
+
gdt.add_code_segment(base=0, limit=0xFFFFF, ring=0)
|
|
102
|
+
gdt.add_data_segment(base=0, limit=0xFFFFF, ring=0)
|
|
103
|
+
gdt.install()
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
_entries: List[GDTEntry] = []
|
|
107
|
+
_operations: list = []
|
|
108
|
+
|
|
109
|
+
def __init__(self):
|
|
110
|
+
"""Initialize GDT with empty entries."""
|
|
111
|
+
self._entries = []
|
|
112
|
+
self._operations = []
|
|
113
|
+
|
|
114
|
+
def add_null_descriptor(self) -> 'GDT':
|
|
115
|
+
"""
|
|
116
|
+
Add the required null descriptor (first entry).
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
Self for chaining.
|
|
120
|
+
|
|
121
|
+
Example:
|
|
122
|
+
gdt.add_null_descriptor()
|
|
123
|
+
"""
|
|
124
|
+
self._entries.append(GDTEntry(
|
|
125
|
+
base=0,
|
|
126
|
+
limit=0,
|
|
127
|
+
segment_type=SegmentType.NULL,
|
|
128
|
+
present=False,
|
|
129
|
+
))
|
|
130
|
+
self._operations.append({"type": "add_null"})
|
|
131
|
+
return self
|
|
132
|
+
|
|
133
|
+
def add_code_segment(
|
|
134
|
+
self,
|
|
135
|
+
base: int = 0,
|
|
136
|
+
limit: int = 0xFFFFF,
|
|
137
|
+
ring: int = 0,
|
|
138
|
+
readable: bool = True,
|
|
139
|
+
) -> 'GDT':
|
|
140
|
+
"""
|
|
141
|
+
Add a code segment descriptor.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
base: Base address (default: 0)
|
|
145
|
+
limit: Segment limit (default: 4GB)
|
|
146
|
+
ring: Privilege level 0-3 (default: 0 = kernel)
|
|
147
|
+
readable: Allow reading code (default: True)
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
Self for chaining.
|
|
151
|
+
|
|
152
|
+
Example:
|
|
153
|
+
gdt.add_code_segment(ring=0) # Kernel code
|
|
154
|
+
gdt.add_code_segment(ring=3) # User code
|
|
155
|
+
"""
|
|
156
|
+
seg_type = SegmentType.CODE_EXECUTE_READ if readable else SegmentType.CODE_EXECUTE_ONLY
|
|
157
|
+
|
|
158
|
+
self._entries.append(GDTEntry(
|
|
159
|
+
base=base,
|
|
160
|
+
limit=limit,
|
|
161
|
+
segment_type=seg_type,
|
|
162
|
+
privilege=PrivilegeLevel(ring),
|
|
163
|
+
))
|
|
164
|
+
self._operations.append({
|
|
165
|
+
"type": "add_code",
|
|
166
|
+
"base": base,
|
|
167
|
+
"limit": limit,
|
|
168
|
+
"ring": ring,
|
|
169
|
+
})
|
|
170
|
+
return self
|
|
171
|
+
|
|
172
|
+
def add_data_segment(
|
|
173
|
+
self,
|
|
174
|
+
base: int = 0,
|
|
175
|
+
limit: int = 0xFFFFF,
|
|
176
|
+
ring: int = 0,
|
|
177
|
+
writable: bool = True,
|
|
178
|
+
) -> 'GDT':
|
|
179
|
+
"""
|
|
180
|
+
Add a data segment descriptor.
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
base: Base address (default: 0)
|
|
184
|
+
limit: Segment limit (default: 4GB)
|
|
185
|
+
ring: Privilege level 0-3 (default: 0 = kernel)
|
|
186
|
+
writable: Allow writing (default: True)
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
Self for chaining.
|
|
190
|
+
|
|
191
|
+
Example:
|
|
192
|
+
gdt.add_data_segment(ring=0) # Kernel data
|
|
193
|
+
gdt.add_data_segment(ring=3) # User data
|
|
194
|
+
"""
|
|
195
|
+
seg_type = SegmentType.DATA_READ_WRITE if writable else SegmentType.DATA_READ_ONLY
|
|
196
|
+
|
|
197
|
+
self._entries.append(GDTEntry(
|
|
198
|
+
base=base,
|
|
199
|
+
limit=limit,
|
|
200
|
+
segment_type=seg_type,
|
|
201
|
+
privilege=PrivilegeLevel(ring),
|
|
202
|
+
))
|
|
203
|
+
self._operations.append({
|
|
204
|
+
"type": "add_data",
|
|
205
|
+
"base": base,
|
|
206
|
+
"limit": limit,
|
|
207
|
+
"ring": ring,
|
|
208
|
+
})
|
|
209
|
+
return self
|
|
210
|
+
|
|
211
|
+
def add_tss_segment(self, base: int, limit: int) -> 'GDT':
|
|
212
|
+
"""
|
|
213
|
+
Add a Task State Segment descriptor.
|
|
214
|
+
|
|
215
|
+
Args:
|
|
216
|
+
base: TSS base address
|
|
217
|
+
limit: TSS size
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
Self for chaining.
|
|
221
|
+
"""
|
|
222
|
+
# TSS descriptor has special format
|
|
223
|
+
self._entries.append(GDTEntry(
|
|
224
|
+
base=base,
|
|
225
|
+
limit=limit,
|
|
226
|
+
segment_type=SegmentType.CODE_EXECUTE_ONLY, # Will be modified
|
|
227
|
+
privilege=PrivilegeLevel.RING0,
|
|
228
|
+
))
|
|
229
|
+
self._operations.append({
|
|
230
|
+
"type": "add_tss",
|
|
231
|
+
"base": base,
|
|
232
|
+
"limit": limit,
|
|
233
|
+
})
|
|
234
|
+
return self
|
|
235
|
+
|
|
236
|
+
def install(self) -> None:
|
|
237
|
+
"""
|
|
238
|
+
Install the GDT and reload segment registers.
|
|
239
|
+
|
|
240
|
+
This must be called after adding all segments.
|
|
241
|
+
|
|
242
|
+
Example:
|
|
243
|
+
gdt.install()
|
|
244
|
+
"""
|
|
245
|
+
self._operations.append({"type": "install"})
|
|
246
|
+
|
|
247
|
+
def get_selector(self, index: int, ring: int = 0) -> int:
|
|
248
|
+
"""
|
|
249
|
+
Get the segment selector for an entry.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
index: GDT entry index
|
|
253
|
+
ring: Requested privilege level
|
|
254
|
+
|
|
255
|
+
Returns:
|
|
256
|
+
The segment selector value.
|
|
257
|
+
"""
|
|
258
|
+
return (index << 3) | ring
|
|
259
|
+
|
|
260
|
+
def to_bytes(self) -> bytes:
|
|
261
|
+
"""Convert entire GDT to bytes."""
|
|
262
|
+
result = b''
|
|
263
|
+
for entry in self._entries:
|
|
264
|
+
result += entry.to_bytes()
|
|
265
|
+
return result
|
|
266
|
+
|
|
267
|
+
def get_size(self) -> int:
|
|
268
|
+
"""Get GDT size in bytes."""
|
|
269
|
+
return len(self._entries) * 8
|
|
270
|
+
|
|
271
|
+
def _get_operations(self) -> list:
|
|
272
|
+
"""Get all recorded operations (used by compiler)."""
|
|
273
|
+
return self._operations.copy()
|
|
274
|
+
|
|
275
|
+
@classmethod
|
|
276
|
+
def create_flat_model(cls) -> 'GDT':
|
|
277
|
+
"""
|
|
278
|
+
Create a standard flat memory model GDT.
|
|
279
|
+
|
|
280
|
+
This is the most common setup for modern OS.
|
|
281
|
+
|
|
282
|
+
Returns:
|
|
283
|
+
Configured GDT instance.
|
|
284
|
+
|
|
285
|
+
Example:
|
|
286
|
+
gdt = GDT.create_flat_model()
|
|
287
|
+
gdt.install()
|
|
288
|
+
"""
|
|
289
|
+
gdt = cls()
|
|
290
|
+
gdt.add_null_descriptor()
|
|
291
|
+
gdt.add_code_segment(ring=0) # Kernel code
|
|
292
|
+
gdt.add_data_segment(ring=0) # Kernel data
|
|
293
|
+
gdt.add_code_segment(ring=3) # User code
|
|
294
|
+
gdt.add_data_segment(ring=3) # User data
|
|
295
|
+
return gdt
|