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/memory/manager.py ADDED
@@ -0,0 +1,397 @@
1
+ """
2
+ pyOS Memory Manager - Static and Dynamic Memory Allocation
3
+ """
4
+
5
+ from typing import Optional, Dict, List, Tuple
6
+ from dataclasses import dataclass
7
+ from enum import Enum
8
+
9
+
10
+ class AllocationType(Enum):
11
+ """Memory allocation types"""
12
+ STATIC = "static"
13
+ DYNAMIC = "dynamic"
14
+
15
+
16
+ @dataclass
17
+ class MemoryBlock:
18
+ """Represents a memory block"""
19
+ address: int
20
+ size: int
21
+ used: bool = False
22
+ name: Optional[str] = None
23
+
24
+
25
+ @dataclass
26
+ class MemoryRegion:
27
+ """Represents a memory region"""
28
+ start: int
29
+ end: int
30
+ name: str
31
+ writable: bool = True
32
+ executable: bool = False
33
+
34
+
35
+ class Memory:
36
+ """
37
+ Memory Manager for pyOS.
38
+
39
+ Provides both static and dynamic memory allocation.
40
+
41
+ Example:
42
+ # Static allocation
43
+ buffer = Memory.allocate_static(1024, name="my_buffer")
44
+
45
+ # Dynamic allocation (heap)
46
+ ptr = Memory.malloc(256)
47
+ Memory.free(ptr)
48
+ """
49
+
50
+ # Memory layout constants
51
+ KERNEL_START = 0x100000 # 1MB - Kernel starts here
52
+ KERNEL_SIZE = 0x100000 # 1MB for kernel
53
+ HEAP_START = 0x200000 # 2MB - Heap starts here
54
+ HEAP_SIZE = 0x1000000 # 16MB heap
55
+ STACK_TOP = 0x90000 # Stack top (grows down)
56
+ STACK_SIZE = 0x10000 # 64KB stack
57
+ VGA_ADDRESS = 0xB8000 # VGA text buffer
58
+
59
+ _static_allocations: List[MemoryBlock] = []
60
+ _heap_blocks: List[MemoryBlock] = []
61
+ _next_static_address: int = KERNEL_START + KERNEL_SIZE
62
+ _heap_initialized: bool = False
63
+ _operations: list = []
64
+
65
+ @classmethod
66
+ def allocate_static(cls, size: int, name: Optional[str] = None, align: int = 4) -> int:
67
+ """
68
+ Allocate static memory (compile-time allocation).
69
+
70
+ Args:
71
+ size: Size in bytes
72
+ name: Optional name for the allocation
73
+ align: Alignment in bytes (default: 4)
74
+
75
+ Returns:
76
+ The allocated address.
77
+
78
+ Example:
79
+ buffer_addr = Memory.allocate_static(1024, name="screen_buffer")
80
+ """
81
+ # Align address
82
+ if cls._next_static_address % align != 0:
83
+ cls._next_static_address += align - (cls._next_static_address % align)
84
+
85
+ address = cls._next_static_address
86
+ cls._next_static_address += size
87
+
88
+ block = MemoryBlock(
89
+ address=address,
90
+ size=size,
91
+ used=True,
92
+ name=name,
93
+ )
94
+ cls._static_allocations.append(block)
95
+
96
+ cls._operations.append({
97
+ "type": "allocate_static",
98
+ "address": address,
99
+ "size": size,
100
+ "name": name,
101
+ })
102
+
103
+ return address
104
+
105
+ @classmethod
106
+ def malloc(cls, size: int) -> int:
107
+ """
108
+ Allocate dynamic memory from heap.
109
+
110
+ Args:
111
+ size: Size in bytes
112
+
113
+ Returns:
114
+ Pointer to allocated memory, or 0 if failed.
115
+
116
+ Example:
117
+ ptr = Memory.malloc(256)
118
+ if ptr:
119
+ # Use memory
120
+ Memory.free(ptr)
121
+ """
122
+ cls._operations.append({
123
+ "type": "malloc",
124
+ "size": size,
125
+ })
126
+
127
+ # Find free block (first-fit algorithm)
128
+ for block in cls._heap_blocks:
129
+ if not block.used and block.size >= size:
130
+ # Split block if much larger
131
+ if block.size > size + 32:
132
+ new_block = MemoryBlock(
133
+ address=block.address + size,
134
+ size=block.size - size,
135
+ used=False,
136
+ )
137
+ cls._heap_blocks.append(new_block)
138
+ block.size = size
139
+
140
+ block.used = True
141
+ return block.address
142
+
143
+ # No free block found, allocate new
144
+ if cls._heap_blocks:
145
+ last = max(cls._heap_blocks, key=lambda b: b.address)
146
+ new_address = last.address + last.size
147
+ else:
148
+ new_address = cls.HEAP_START
149
+
150
+ if new_address + size > cls.HEAP_START + cls.HEAP_SIZE:
151
+ return 0 # Out of memory
152
+
153
+ block = MemoryBlock(address=new_address, size=size, used=True)
154
+ cls._heap_blocks.append(block)
155
+ return new_address
156
+
157
+ @classmethod
158
+ def free(cls, address: int) -> bool:
159
+ """
160
+ Free dynamically allocated memory.
161
+
162
+ Args:
163
+ address: Pointer returned by malloc
164
+
165
+ Returns:
166
+ True if freed successfully.
167
+
168
+ Example:
169
+ Memory.free(ptr)
170
+ """
171
+ cls._operations.append({
172
+ "type": "free",
173
+ "address": address,
174
+ })
175
+
176
+ for block in cls._heap_blocks:
177
+ if block.address == address:
178
+ block.used = False
179
+ cls._coalesce_free_blocks()
180
+ return True
181
+ return False
182
+
183
+ @classmethod
184
+ def _coalesce_free_blocks(cls) -> None:
185
+ """Merge adjacent free blocks."""
186
+ cls._heap_blocks.sort(key=lambda b: b.address)
187
+
188
+ i = 0
189
+ while i < len(cls._heap_blocks) - 1:
190
+ current = cls._heap_blocks[i]
191
+ next_block = cls._heap_blocks[i + 1]
192
+
193
+ if not current.used and not next_block.used:
194
+ if current.address + current.size == next_block.address:
195
+ current.size += next_block.size
196
+ cls._heap_blocks.pop(i + 1)
197
+ continue
198
+ i += 1
199
+
200
+ @classmethod
201
+ def realloc(cls, address: int, new_size: int) -> int:
202
+ """
203
+ Reallocate memory with new size.
204
+
205
+ Args:
206
+ address: Existing pointer
207
+ new_size: New size in bytes
208
+
209
+ Returns:
210
+ New pointer (may be different from original).
211
+ """
212
+ cls._operations.append({
213
+ "type": "realloc",
214
+ "address": address,
215
+ "new_size": new_size,
216
+ })
217
+
218
+ # Find existing block
219
+ for block in cls._heap_blocks:
220
+ if block.address == address:
221
+ if block.size >= new_size:
222
+ return address # Already big enough
223
+
224
+ # Allocate new, copy, free old
225
+ new_ptr = cls.malloc(new_size)
226
+ if new_ptr:
227
+ cls.free(address)
228
+ return new_ptr
229
+
230
+ return cls.malloc(new_size)
231
+
232
+ @classmethod
233
+ def calloc(cls, count: int, size: int) -> int:
234
+ """
235
+ Allocate and zero-initialize memory.
236
+
237
+ Args:
238
+ count: Number of elements
239
+ size: Size of each element
240
+
241
+ Returns:
242
+ Pointer to zeroed memory.
243
+
244
+ Example:
245
+ array = Memory.calloc(100, 4) # 100 integers
246
+ """
247
+ total = count * size
248
+ cls._operations.append({
249
+ "type": "calloc",
250
+ "count": count,
251
+ "size": size,
252
+ })
253
+ return cls.malloc(total)
254
+
255
+ @classmethod
256
+ def memset(cls, address: int, value: int, size: int) -> None:
257
+ """
258
+ Fill memory with a value.
259
+
260
+ Args:
261
+ address: Start address
262
+ value: Byte value to fill
263
+ size: Number of bytes
264
+
265
+ Example:
266
+ Memory.memset(buffer, 0, 1024) # Zero out buffer
267
+ """
268
+ cls._operations.append({
269
+ "type": "memset",
270
+ "address": address,
271
+ "value": value,
272
+ "size": size,
273
+ })
274
+
275
+ @classmethod
276
+ def memcpy(cls, dest: int, src: int, size: int) -> None:
277
+ """
278
+ Copy memory from source to destination.
279
+
280
+ Args:
281
+ dest: Destination address
282
+ src: Source address
283
+ size: Number of bytes to copy
284
+
285
+ Example:
286
+ Memory.memcpy(dest_buffer, src_buffer, 256)
287
+ """
288
+ cls._operations.append({
289
+ "type": "memcpy",
290
+ "dest": dest,
291
+ "src": src,
292
+ "size": size,
293
+ })
294
+
295
+ @classmethod
296
+ def read_byte(cls, address: int) -> int:
297
+ """
298
+ Read a byte from memory.
299
+
300
+ Args:
301
+ address: Memory address
302
+
303
+ Returns:
304
+ Byte value (0-255).
305
+ """
306
+ cls._operations.append({
307
+ "type": "read_byte",
308
+ "address": address,
309
+ })
310
+ return 0
311
+
312
+ @classmethod
313
+ def write_byte(cls, address: int, value: int) -> None:
314
+ """
315
+ Write a byte to memory.
316
+
317
+ Args:
318
+ address: Memory address
319
+ value: Byte value (0-255)
320
+ """
321
+ cls._operations.append({
322
+ "type": "write_byte",
323
+ "address": address,
324
+ "value": value & 0xFF,
325
+ })
326
+
327
+ @classmethod
328
+ def read_word(cls, address: int) -> int:
329
+ """Read a 16-bit word from memory."""
330
+ cls._operations.append({"type": "read_word", "address": address})
331
+ return 0
332
+
333
+ @classmethod
334
+ def write_word(cls, address: int, value: int) -> None:
335
+ """Write a 16-bit word to memory."""
336
+ cls._operations.append({
337
+ "type": "write_word",
338
+ "address": address,
339
+ "value": value & 0xFFFF,
340
+ })
341
+
342
+ @classmethod
343
+ def read_dword(cls, address: int) -> int:
344
+ """Read a 32-bit dword from memory."""
345
+ cls._operations.append({"type": "read_dword", "address": address})
346
+ return 0
347
+
348
+ @classmethod
349
+ def write_dword(cls, address: int, value: int) -> None:
350
+ """Write a 32-bit dword to memory."""
351
+ cls._operations.append({
352
+ "type": "write_dword",
353
+ "address": address,
354
+ "value": value & 0xFFFFFFFF,
355
+ })
356
+
357
+ @classmethod
358
+ def get_free_memory(cls) -> int:
359
+ """Get total free heap memory."""
360
+ used = sum(b.size for b in cls._heap_blocks if b.used)
361
+ return cls.HEAP_SIZE - used
362
+
363
+ @classmethod
364
+ def get_used_memory(cls) -> int:
365
+ """Get total used heap memory."""
366
+ return sum(b.size for b in cls._heap_blocks if b.used)
367
+
368
+ @classmethod
369
+ def get_memory_map(cls) -> List[MemoryRegion]:
370
+ """
371
+ Get the memory map.
372
+
373
+ Returns:
374
+ List of memory regions.
375
+ """
376
+ return [
377
+ MemoryRegion(0x0, 0x500, "Real Mode IVT/BDA", writable=False),
378
+ MemoryRegion(0x7C00, 0x7E00, "Bootloader", executable=True),
379
+ MemoryRegion(cls.STACK_TOP - cls.STACK_SIZE, cls.STACK_TOP, "Stack"),
380
+ MemoryRegion(cls.VGA_ADDRESS, cls.VGA_ADDRESS + 0x8000, "VGA Buffer"),
381
+ MemoryRegion(cls.KERNEL_START, cls.KERNEL_START + cls.KERNEL_SIZE, "Kernel", executable=True),
382
+ MemoryRegion(cls.HEAP_START, cls.HEAP_START + cls.HEAP_SIZE, "Heap"),
383
+ ]
384
+
385
+ @classmethod
386
+ def _reset(cls) -> None:
387
+ """Reset memory state (used internally)."""
388
+ cls._static_allocations = []
389
+ cls._heap_blocks = []
390
+ cls._next_static_address = cls.KERNEL_START + cls.KERNEL_SIZE
391
+ cls._heap_initialized = False
392
+ cls._operations = []
393
+
394
+ @classmethod
395
+ def _get_operations(cls) -> list:
396
+ """Get all recorded operations (used by compiler)."""
397
+ return cls._operations.copy()
@@ -0,0 +1,7 @@
1
+ """
2
+ pyOS System Calls
3
+ """
4
+
5
+ from .handler import SysCall
6
+
7
+ __all__ = ["SysCall"]
@@ -0,0 +1,179 @@
1
+ """
2
+ pyOS System Call Handler
3
+ """
4
+
5
+ from typing import Callable, Dict, Optional, Any
6
+ from dataclasses import dataclass
7
+ from enum import Enum
8
+
9
+
10
+ class SysCallNumber(Enum):
11
+ """Standard system call numbers"""
12
+ SYS_EXIT = 1
13
+ SYS_READ = 3
14
+ SYS_WRITE = 4
15
+ SYS_OPEN = 5
16
+ SYS_CLOSE = 6
17
+ SYS_GETPID = 20
18
+ SYS_MALLOC = 90
19
+ SYS_FREE = 91
20
+ SYS_SLEEP = 162
21
+ SYS_TIME = 201
22
+
23
+
24
+ @dataclass
25
+ class SysCallContext:
26
+ """Context passed to system call handlers"""
27
+ syscall_number: int
28
+ arg1: int = 0
29
+ arg2: int = 0
30
+ arg3: int = 0
31
+ arg4: int = 0
32
+ arg5: int = 0
33
+
34
+
35
+ class SysCall:
36
+ """
37
+ System Call Manager.
38
+
39
+ Provides methods to define and handle system calls.
40
+
41
+ Example:
42
+ @SysCall.handler(SysCallNumber.SYS_WRITE)
43
+ def sys_write(ctx):
44
+ fd = ctx.arg1
45
+ buf = ctx.arg2
46
+ count = ctx.arg3
47
+ # Write implementation
48
+ return count
49
+ """
50
+
51
+ _handlers: Dict[int, Callable] = {}
52
+ _operations: list = []
53
+
54
+ @classmethod
55
+ def handler(cls, syscall: SysCallNumber):
56
+ """
57
+ Decorator to register a system call handler.
58
+
59
+ Args:
60
+ syscall: The system call number
61
+
62
+ Example:
63
+ @SysCall.handler(SysCallNumber.SYS_EXIT)
64
+ def sys_exit(ctx):
65
+ # Exit implementation
66
+ pass
67
+ """
68
+ def decorator(func: Callable) -> Callable:
69
+ cls._handlers[syscall.value] = func
70
+ cls._operations.append({
71
+ "type": "register_handler",
72
+ "syscall": syscall.value,
73
+ "name": func.__name__,
74
+ })
75
+ return func
76
+ return decorator
77
+
78
+ @classmethod
79
+ def register(cls, syscall_number: int, handler: Callable) -> None:
80
+ """
81
+ Register a system call handler by number.
82
+
83
+ Args:
84
+ syscall_number: System call number
85
+ handler: Handler function
86
+
87
+ Example:
88
+ def my_syscall(ctx):
89
+ return 0
90
+ SysCall.register(100, my_syscall)
91
+ """
92
+ cls._handlers[syscall_number] = handler
93
+ cls._operations.append({
94
+ "type": "register_handler",
95
+ "syscall": syscall_number,
96
+ "name": handler.__name__,
97
+ })
98
+
99
+ @classmethod
100
+ def call(cls, syscall_number: int, *args) -> int:
101
+ """
102
+ Invoke a system call.
103
+
104
+ Args:
105
+ syscall_number: System call number
106
+ *args: Arguments to pass
107
+
108
+ Returns:
109
+ Return value from syscall.
110
+
111
+ Example:
112
+ result = SysCall.call(SysCallNumber.SYS_WRITE.value, 1, buffer, length)
113
+ """
114
+ cls._operations.append({
115
+ "type": "call",
116
+ "syscall": syscall_number,
117
+ "args": args,
118
+ })
119
+
120
+ handler = cls._handlers.get(syscall_number)
121
+ if handler:
122
+ ctx = SysCallContext(
123
+ syscall_number=syscall_number,
124
+ arg1=args[0] if len(args) > 0 else 0,
125
+ arg2=args[1] if len(args) > 1 else 0,
126
+ arg3=args[2] if len(args) > 2 else 0,
127
+ arg4=args[3] if len(args) > 3 else 0,
128
+ arg5=args[4] if len(args) > 4 else 0,
129
+ )
130
+ return handler(ctx)
131
+ return -1
132
+
133
+ @classmethod
134
+ def exit(cls, code: int = 0) -> None:
135
+ """
136
+ Exit the current process.
137
+
138
+ Args:
139
+ code: Exit code (default: 0)
140
+ """
141
+ cls._operations.append({
142
+ "type": "exit",
143
+ "code": code,
144
+ })
145
+
146
+ @classmethod
147
+ def sleep(cls, milliseconds: int) -> None:
148
+ """
149
+ Sleep for specified milliseconds.
150
+
151
+ Args:
152
+ milliseconds: Time to sleep
153
+ """
154
+ cls._operations.append({
155
+ "type": "sleep",
156
+ "ms": milliseconds,
157
+ })
158
+
159
+ @classmethod
160
+ def get_time(cls) -> int:
161
+ """
162
+ Get current system time.
163
+
164
+ Returns:
165
+ Time in milliseconds since boot.
166
+ """
167
+ cls._operations.append({"type": "get_time"})
168
+ return 0
169
+
170
+ @classmethod
171
+ def _reset(cls) -> None:
172
+ """Reset syscall state (used internally)."""
173
+ cls._handlers = {}
174
+ cls._operations = []
175
+
176
+ @classmethod
177
+ def _get_operations(cls) -> list:
178
+ """Get all recorded operations (used by compiler)."""
179
+ return cls._operations.copy()