-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsegments.pyx
561 lines (546 loc) · 39.6 KB
/
segments.pyx
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
#cython: language_level=3, boundscheck=False, wraparound=False, cdivision=True, profile=False, c_string_type=bytes
include "globals.pxi"
include "cpu_globals.pxi"
from cpu import HirnwichseException
cdef class Gdt:
def __init__(self, Segments segments):
self.segments = segments
self.tableBase = self.tableLimit = 0
cdef void loadTablePosition(self, uint32_t tableBase, uint16_t tableLimit):
if (tableLimit > GDT_HARD_LIMIT):
self.segments.main.exitError("Gdt::loadTablePosition: tableLimit 0x%04x > GDT_HARD_LIMIT 0x%04x.", tableLimit, GDT_HARD_LIMIT)
return
self.tableBase, self.tableLimit = tableBase, tableLimit
#self.segments.main.debug("Gdt::loadTablePosition: tableBase: 0x%08x; tableLimit: 0x%04x", self.tableBase, self.tableLimit)
cdef uint8_t getEntry(self, GdtEntry *gdtEntry, uint16_t num) except BITMASK_BYTE_CONST:
cdef uint64_t entryData
self.segments.paging.implicitSV = True
num &= 0xfff8
if (not num):
##self.segments.main.debug("GDT::getEntry: num == 0!")
return False
#self.segments.main.debug("Gdt::getEntry: tableBase==0x%08x; tableLimit==0x%04x; num==0x%04x", self.tableBase, self.tableLimit, num)
entryData = self.tableBase+num
entryData = self.segments.registers.mmReadValueUnsignedQword(entryData, NULL, False)
gdtEntry[0].accessByte = <uint8_t>(entryData>>40)
gdtEntry[0].flags = (entryData>>52)&0xf
gdtEntry[0].base = (entryData>>16)&0xffffff
gdtEntry[0].limit = entryData&0xffff
gdtEntry[0].base |= (<uint8_t>(entryData>>56))<<24
gdtEntry[0].limit |= ((entryData>>48)&0xf)<<16
# segment size: 1==32bit; 0==16bit; segSize is 4 for 32bit and 2 for 16bit
gdtEntry[0].segSize = OP_SIZE_DWORD if (gdtEntry[0].flags & GDT_FLAG_SIZE) else OP_SIZE_WORD
gdtEntry[0].segPresent = (gdtEntry[0].accessByte & GDT_ACCESS_PRESENT)!=0
gdtEntry[0].segIsCodeSeg = (gdtEntry[0].accessByte & GDT_ACCESS_EXECUTABLE)!=0
gdtEntry[0].segIsRW = (gdtEntry[0].accessByte & GDT_ACCESS_READABLE_WRITABLE)!=0
gdtEntry[0].segIsConforming = (gdtEntry[0].accessByte & GDT_ACCESS_CONFORMING)!=0
gdtEntry[0].segIsNormal = (gdtEntry[0].accessByte & GDT_ACCESS_NORMAL_SEGMENT)!=0
gdtEntry[0].segUse4K = (gdtEntry[0].flags & GDT_FLAG_USE_4K)!=0
gdtEntry[0].segDPL = ((gdtEntry[0].accessByte & GDT_ACCESS_DPL)>>5)&3
gdtEntry[0].anotherLimit = gdtEntry[0].segIsNormal and not gdtEntry[0].segIsCodeSeg and gdtEntry[0].segIsConforming
if (gdtEntry[0].segUse4K):
gdtEntry[0].limit <<= 12
gdtEntry[0].limit |= 0xfff
#if (not gdtEntry[0].segIsCodeSeg and gdtEntry[0].segIsConforming and self.main.debugEnabled):
# self.main.notice("GdtEntry::parseEntryData: TODO: expand-down data segment may not supported yet!")
#if (gdtEntry[0].flags & GDT_FLAG_LONGMODE): # TODO: int-mode isn't implemented yet...
# self.main.notice("GdtEntry::parseEntryData: WTF: Did you just tried to use int-mode?!? Maybe I'll implement it in a few decades... (long-mode; AMD64)")
return True
cdef uint8_t getSegType(self, uint16_t num) except? BITMASK_BYTE_CONST: # access byte
self.segments.paging.implicitSV = True
num &= 0xfff8
return (self.segments.registers.mmReadValueUnsignedByte(self.tableBase+num+5, NULL, False) & TABLE_ENTRY_SYSTEM_TYPE_MASK)
cdef uint8_t setSegType(self, uint16_t num, uint8_t segmentType) except BITMASK_BYTE_CONST: # access byte
self.segments.paging.implicitSV = True
num &= 0xfff8
return self.segments.registers.mmWriteValue(self.tableBase+num+5, <uint8_t>((self.segments.registers.\
mmReadValueUnsignedByte(self.tableBase+num+5, NULL, False) & (~TABLE_ENTRY_SYSTEM_TYPE_MASK)) | \
(segmentType & TABLE_ENTRY_SYSTEM_TYPE_MASK)), OP_SIZE_BYTE, NULL, False)
cdef uint8_t checkAccessAllowed(self, uint16_t num, uint8_t isStackSegment) except BITMASK_BYTE_CONST:
cdef uint8_t cpl
cdef GdtEntry gdtEntry
if (not (num&0xfff8) or num > self.tableLimit):
#self.segments.main.notice("Gdt::checkAccessAllowed: test1")
if (not (num&0xfff8)):
raise HirnwichseException(CPU_EXCEPTION_GP, 0)
else:
raise HirnwichseException(CPU_EXCEPTION_GP, num)
#cpl = self.segments.cs.segmentIndex&3
cpl = self.segments.registers.getCPL()
if (not self.getEntry(&gdtEntry, num) or (isStackSegment and ( num&3 != cpl or \
gdtEntry.segDPL != cpl))):# or 0):
#self.segments.main.notice("Gdt::checkAccessAllowed: test2")
raise HirnwichseException(CPU_EXCEPTION_GP, num)
elif (not gdtEntry.segPresent):
#self.segments.main.notice("Gdt::checkAccessAllowed: test3")
if (isStackSegment):
raise HirnwichseException(CPU_EXCEPTION_SS, num)
else:
raise HirnwichseException(CPU_EXCEPTION_NP, num)
return True
cdef uint8_t checkReadAllowed(self, uint16_t num) except BITMASK_BYTE_CONST: # for VERR
cdef uint8_t rpl
cdef GdtEntry gdtEntry
rpl = num&3
num &= 0xfff8
if (num == 0 or num > self.tableLimit):
return False
if (not self.getEntry(&gdtEntry, num)):
return False
if (((self.getSegType(num) == 0) or not gdtEntry.segIsConforming) and \
((self.segments.registers.getCPL() > gdtEntry.segDPL) or (rpl > gdtEntry.segDPL))):
return False
if (gdtEntry.segIsCodeSeg and not gdtEntry.segIsRW):
return False
return True
cdef uint8_t checkWriteAllowed(self, uint16_t num) except BITMASK_BYTE_CONST: # for VERW
cdef uint8_t rpl
cdef GdtEntry gdtEntry
rpl = num&3
num &= 0xfff8
if (num == 0 or num > self.tableLimit):
return False
if (not self.getEntry(&gdtEntry, num)):
return False
if (((self.getSegType(num) == 0) or not gdtEntry.segIsConforming) and \
((self.segments.registers.getCPL() > gdtEntry.segDPL) or (rpl > gdtEntry.segDPL))):
return False
if (not gdtEntry.segIsCodeSeg and gdtEntry.segIsRW):
return True
return False
cdef uint8_t checkSegmentLoadAllowed(self, uint16_t num, uint16_t segId) except BITMASK_BYTE_CONST:
cdef uint8_t numSegDPL, cpl
cdef GdtEntry gdtEntry
if ((num&0xfff8) > self.tableLimit):
#self.segments.main.notice("test1: segId==%u, num==0x%04x, tableLimit==0x%04x", segId, num, self.tableLimit)
raise HirnwichseException(CPU_EXCEPTION_GP, num)
if (not (num&0xfff8)):
if (segId == CPU_SEGMENT_CS or segId == CPU_SEGMENT_SS):
#self.segments.main.notice("test4: segId==%u, num==0x%04x, tableLimit==0x%04x, EIP: 0x%04x, CS: 0x%04x", segId, num, self.tableLimit, self.segments.main.cpu.savedEip, self.segments.main.cpu.savedCs)
raise HirnwichseException(CPU_EXCEPTION_GP, 0)
return False
if (not self.getEntry(&gdtEntry, num) or not gdtEntry.segPresent):
if (segId == CPU_SEGMENT_SS):
raise HirnwichseException(CPU_EXCEPTION_SS, num)
raise HirnwichseException(CPU_EXCEPTION_NP, num)
#cpl = self.segments.cs.segmentIndex&3
cpl = self.segments.registers.getCPL()
numSegDPL = gdtEntry.segDPL
if (segId == CPU_SEGMENT_TSS): # TODO?
return True
if (segId == CPU_SEGMENT_SS): # TODO: TODO!
##if ((num&3 != cpl or numSegDPL != cpl) or \
if (((gdtEntry.segIsCodeSeg) or (not gdtEntry.segIsCodeSeg and not gdtEntry.segIsRW))):
#self.segments.main.notice("test2: segId==0x%02x, num 0x%04x, numSegDPL %u, cpl %u", segId, num, numSegDPL, cpl)
raise HirnwichseException(CPU_EXCEPTION_GP, num)
else: # not stack segment
if ( ((not gdtEntry.segIsCodeSeg or not gdtEntry.segIsConforming) and (num&3 > numSegDPL and \
cpl > numSegDPL)) or (not (<Paging>(<Segments>self.segments).paging).instrFetch and gdtEntry.segIsCodeSeg and not gdtEntry.segIsRW) ):
#self.segments.main.notice("test3: segId==%u, segId)
raise HirnwichseException(CPU_EXCEPTION_GP, num)
return True
cdef class Idt:
def __init__(self, Segments segments):
self.segments = segments
self.tableBase = self.tableLimit = 0
cdef void loadTable(self, uint32_t tableBase, uint16_t tableLimit):
if (tableLimit > IDT_HARD_LIMIT):
self.segments.main.exitError("Idt::loadTablePosition: tableLimit 0x%04x > IDT_HARD_LIMIT 0x%04x.",\
tableLimit, IDT_HARD_LIMIT)
return
self.tableBase, self.tableLimit = tableBase, tableLimit
cdef uint8_t getEntry(self, IdtEntry *idtEntry, uint8_t num) except BITMASK_BYTE_CONST:
cdef uint64_t entryData
self.segments.paging.implicitSV = True
if (not self.tableLimit):
#self.segments.main.notice("Idt::getEntry: tableLimit is zero.")
return False
entryData = (num<<3)
if (entryData >= self.tableLimit):
#self.segments.main.notice("Idt::getEntry: tableLimit is too small.")
return False
entryData += self.tableBase
entryData = self.segments.registers.mmReadValueUnsignedQword(entryData, NULL, False)
idtEntry[0].entryEip = entryData&0xffff # interrupt eip: lower word
idtEntry[0].entryEip |= ((entryData>>48)&0xffff)<<16 # interrupt eip: upper word
idtEntry[0].entrySegment = (entryData>>16)&0xffff # interrupt segment
idtEntry[0].entryType = (entryData>>40)&0xf # interrupt type
idtEntry[0].entryNeededDPL = (entryData>>45)&0x3 # interrupt: Need this DPL
idtEntry[0].entryPresent = (entryData>>47)&1 # is interrupt present
idtEntry[0].entrySize = OP_SIZE_DWORD if (idtEntry[0].entryType in (TABLE_ENTRY_SYSTEM_TYPE_LDT, \
TABLE_ENTRY_SYSTEM_TYPE_TASK_GATE, TABLE_ENTRY_SYSTEM_TYPE_32BIT_TSS, TABLE_ENTRY_SYSTEM_TYPE_32BIT_TSS_BUSY, \
TABLE_ENTRY_SYSTEM_TYPE_32BIT_CALL_GATE, TABLE_ENTRY_SYSTEM_TYPE_32BIT_INTERRUPT_GATE, \
TABLE_ENTRY_SYSTEM_TYPE_32BIT_TRAP_GATE)) else OP_SIZE_WORD
if (idtEntry[0].entryType in (TABLE_ENTRY_SYSTEM_TYPE_LDT, TABLE_ENTRY_SYSTEM_TYPE_32BIT_TSS, TABLE_ENTRY_SYSTEM_TYPE_32BIT_TSS_BUSY)):
#self.segments.main.notice("Idt::getEntry: entryType is LDT or TSS. (is this allowed?)")
return False
if (not idtEntry[0].entryPresent):
#self.segments.main.notice("Idt::getEntry: idtEntry is not present.")
return False
return True
cdef class Paging: # TODO
def __init__(self, Segments segments):
self.instrFetch = self.implicitSV = False
self.segments = segments
self.tlbDirectories = ConfigSpace(PAGE_DIRECTORY_LENGTH, self.segments.main)
self.tlbTables = ConfigSpace(TLB_SIZE, self.segments.main)
self.pageDirectoryBaseAddress = self.pageDirectoryOffset = self.pageTableOffset = self.pageDirectoryEntry = self.pageTableEntry = 0
cdef void invalidateTables(self, uint32_t pageDirectoryBaseAddress, uint8_t noGlobal):
cdef uint32_t pageDirectoryEntry, pageTableEntry, i, j
if (pageDirectoryBaseAddress&0xfff):
if (pageDirectoryBaseAddress&0xfff == 0x18):
self.segments.main.notice("Paging::invalidateTables: PCD and PWT aren't supported yet.")
else:
self.segments.main.exitError("Paging::invalidateTables: pageDirectoryBaseAddress&0xfff")
return
self.pageDirectoryBaseAddress = (pageDirectoryBaseAddress&<uint32_t>0xfffff000)
# TODO: handle global flag for non 4KB PDEs
self.tlbDirectories.csWrite(0, self.segments.main.mm.mmPhyRead(self.pageDirectoryBaseAddress, PAGE_DIRECTORY_LENGTH), PAGE_DIRECTORY_LENGTH)
for i in range(PAGE_DIRECTORY_ENTRIES):
pageDirectoryEntry = self.tlbDirectories.csReadValueUnsignedDword(i<<2) # page directory
if (pageDirectoryEntry & PAGE_PRESENT):
for j in range(PAGE_DIRECTORY_ENTRIES):
j <<= 2
pageTableEntry = self.segments.main.mm.mmPhyReadValueUnsignedDword((pageDirectoryEntry&<uint32_t>0xfffff000)|j) # page table
#if (not noGlobal or not (pageTableEntry & PAGE_GLOBAL)):
if (not noGlobal or (self.segments.registers.getFlagDword(CPU_REGISTER_CR4, CR4_FLAG_PGE) != 0 and not (pageTableEntry & PAGE_GLOBAL))):
self.tlbTables.csWriteValueDword((i<<12)|j, pageTableEntry)
else:
self.tlbTables.csResetAddr((i<<12), 0, PAGE_DIRECTORY_LENGTH)
cdef void invalidateTable(self, uint32_t virtualAddress):
cdef uint32_t pageDirectoryOffset, pageTableOffset, pageDirectoryEntry, pageTableEntry
pageDirectoryOffset = (virtualAddress>>22) << 2
pageTableOffset = ((virtualAddress>>12)&0x3ff) << 2
pageDirectoryEntry = self.segments.main.mm.mmPhyReadValueUnsignedDword(self.pageDirectoryBaseAddress|pageDirectoryOffset) # page directory
self.tlbDirectories.csWriteValueDword(pageDirectoryOffset, pageDirectoryEntry)
pageTableEntry = self.segments.main.mm.mmPhyReadValueUnsignedDword((pageDirectoryEntry&<uint32_t>0xfffff000)|pageTableOffset) # page table
self.tlbTables.csWriteValueDword(((pageDirectoryOffset>>2)<<12)|pageTableOffset, pageTableEntry)
cdef void invalidatePage(self, uint32_t virtualAddress):
cdef uint8_t updateDir
cdef uint32_t pageDirectoryEntry, pageTableEntry, pageDirectoryOffset, pageTableOffset, pageDirectoryEntryV, i, j
pageDirectoryOffset = (virtualAddress>>22) << 2
pageTableOffset = ((virtualAddress>>12)&0x3ff) << 2
pageDirectoryEntryV = self.segments.main.mm.mmPhyReadValueUnsignedDword(self.pageDirectoryBaseAddress|pageDirectoryOffset)&<uint32_t>0xfffff000 # page directory
virtualAddress = self.segments.main.mm.mmPhyReadValueUnsignedDword(pageDirectoryEntryV|pageTableOffset)&<uint32_t>0xfffff000
for i in range(0, PAGE_DIRECTORY_LENGTH, 4):
updateDir = False
pageDirectoryEntry = self.segments.main.mm.mmPhyReadValueUnsignedDword(self.pageDirectoryBaseAddress|i)
if (not (pageDirectoryEntry & PAGE_PRESENT)):
self.tlbDirectories.csWriteValueDword(i, 0)
self.tlbTables.csResetAddr(((i>>2)<<12), 0, PAGE_DIRECTORY_LENGTH)
continue
elif ((pageDirectoryEntry&<uint32_t>0xfffff000) == pageDirectoryEntryV):
self.tlbDirectories.csWriteValueDword(i, pageDirectoryEntry)
updateDir = True
for j in range(0, PAGE_DIRECTORY_LENGTH, 4):
pageTableEntry = self.segments.main.mm.mmPhyReadValueUnsignedDword((pageDirectoryEntry&<uint32_t>0xfffff000)|j) # page table
if (not (pageTableEntry & PAGE_PRESENT)):
self.tlbTables.csWriteValueDword(((i>>2)<<12)|j, 0)
continue
elif (virtualAddress == (pageTableEntry&<uint32_t>0xfffff000) or updateDir):
self.tlbDirectories.csWriteValueDword(i, pageDirectoryEntry)
self.tlbTables.csWriteValueDword(((i>>2)<<12)|j, pageTableEntry)
cdef uint8_t doPF(self, uint32_t virtualAddress, uint8_t written) except BITMASK_BYTE_CONST:
cdef uint32_t errorFlags
IF COMP_DEBUG:
cdef uint32_t pageDirectoryEntryMem, pageTableEntryMem
if (not self.segments.registers.ignoreExceptions):
self.invalidatePage(virtualAddress)
if (self.pageDirectoryEntry & PAGE_SIZE):
errorFlags = (self.pageDirectoryEntry & PAGE_PRESENT) != 0
else:
errorFlags = ((self.pageDirectoryEntry & PAGE_PRESENT) and (self.pageTableEntry & PAGE_PRESENT)) != 0
errorFlags |= written << 1
errorFlags |= (self.segments.registers.getCPL() == 3) << 2
# TODO: reserved bits are set ; only with 4MB pages ; << 3
#errorFlags |= self.instrFetch << 4 # TODO: CR4
#if (self.segments.main.cpu.savedCs == 0x167 and self.segments.main.cpu.savedEip == <uint32_t>0xbff77db0):
# self.segments.main.debugEnabled = True
# self.segments.main.debugEnabledTest = True
IF COMP_DEBUG:
#IF 1:
pageDirectoryEntryMem = self.segments.main.mm.mmPhyReadValueUnsignedDword(self.pageDirectoryBaseAddress|self.pageDirectoryOffset) # page directory
pageTableEntryMem = self.segments.main.mm.mmPhyReadValueUnsignedDword((pageDirectoryEntryMem&<uint32_t>0xfffff000)|self.pageTableOffset) # page table
self.segments.main.notice("Paging::doPF: savedEip==0x%08x; savedCs==0x%04x", self.segments.main.cpu.savedEip, self.segments.main.cpu.savedCs)
self.segments.main.notice("Paging::doPF: virtualAddress==0x%08x; errorFlags==0x%02x", virtualAddress, errorFlags)
self.segments.main.notice("Paging::doPF: PDEL==0x%08x, PTEL==0x%08x", self.pageDirectoryEntry, self.pageTableEntry)
self.segments.main.notice("Paging::doPF: PDEM==0x%08x, PTEM==0x%08x", pageDirectoryEntryMem, pageTableEntryMem)
self.segments.main.notice("Paging::doPF: PDO==0x%04x, PTO==0x%04x, PO==0x%04x", self.pageDirectoryOffset, self.pageTableOffset, self.pageOffset)
self.segments.registers.regs[CPU_REGISTER_CR2]._union.dword.erx = virtualAddress
self.instrFetch = self.implicitSV = False
raise HirnwichseException(CPU_EXCEPTION_PF, errorFlags)
else:
self.segments.registers.ignoreExceptions = False
return BITMASK_BYTE
cdef uint8_t setFlags(self, uint32_t virtualAddress, uint32_t dataSize, uint8_t written):
cdef uint32_t pageDirectoryOffsetWithoutShift, pageDirectoryOffset, pageTableOffset, pageDirectoryEntry, pageTableEntry, pageDirectoryEntryMem, pageTableEntryMem, pageTablesEntryNew
# TODO: for now only handling 4KB pages. (very inefficient)
if (not dataSize):
return True
while (dataSize >= 0):
pageDirectoryOffsetWithoutShift = (virtualAddress>>22)
pageDirectoryOffset = pageDirectoryOffsetWithoutShift << 2
pageTableOffset = ((virtualAddress>>12)&0x3ff) << 2
pageDirectoryEntry = self.tlbDirectories.csReadValueUnsignedDword(pageDirectoryOffset) # page directory
pageTableEntry = self.tlbTables.csReadValueUnsignedDword((pageDirectoryOffsetWithoutShift<<12)|pageTableOffset) # page table
if ((pageDirectoryEntry & PAGE_PRESENT) and ((pageDirectoryEntry & PAGE_SIZE) or (pageTableEntry & PAGE_PRESENT))):
#self.segments.main.debug("Paging::setFlags: test3: pdo addr 0x%08x; pto addr 0x%08x", (self.pageDirectoryBaseAddress|pageDirectoryOffset), ((pageDirectoryEntry&<uint32_t>0xfffff000)|pageTableOffset))
#self.segments.main.debug("Paging::setFlags: test4: pdo 0x%08x; pto 0x%08x", pageDirectoryEntry, pageTableEntry)
#self.segments.main.debug("Paging::setFlags: test5: pdo 0x%08x; pto 0x%08x", self.segments.main.mm.mmPhyReadValueUnsignedDword((self.pageDirectoryBaseAddress|pageDirectoryOffset)), self.segments.main.mm.mmPhyReadValueUnsignedDword(((pageDirectoryEntry&<uint32_t>0xfffff000)|pageTableOffset)))
pageDirectoryEntryMem = self.segments.main.mm.mmPhyReadValueUnsignedDword(self.pageDirectoryBaseAddress|pageDirectoryOffset) # page directory
if (not (pageDirectoryEntry & PAGE_WAS_USED) or (written and not (pageDirectoryEntry & PAGE_WRITTEN_ON_PAGE))):
pageTablesEntryNew = pageDirectoryEntry|(PAGE_WAS_USED | (written and PAGE_WRITTEN_ON_PAGE))
self.tlbDirectories.csWriteValueDword(pageDirectoryOffset, pageTablesEntryNew)
if (pageDirectoryEntry&<uint32_t>0xfffff19f == pageDirectoryEntryMem&<uint32_t>0xfffff19f):
pageTablesEntryNew = pageDirectoryEntryMem|(PAGE_WAS_USED | (written and PAGE_WRITTEN_ON_PAGE))
self.segments.main.mm.mmPhyWriteValue(self.pageDirectoryBaseAddress|pageDirectoryOffset, pageTablesEntryNew, OP_SIZE_DWORD) # page directory
if (not (pageDirectoryEntry & PAGE_SIZE) and (not (pageTableEntry & PAGE_WAS_USED) or (written and not (pageTableEntry & PAGE_WRITTEN_ON_PAGE)))):
pageTablesEntryNew = pageTableEntry|(PAGE_WAS_USED | (written and PAGE_WRITTEN_ON_PAGE))
self.tlbTables.csWriteValueDword((pageDirectoryOffsetWithoutShift<<12)|pageTableOffset, pageTablesEntryNew)
pageTableEntryMem = self.segments.main.mm.mmPhyReadValueUnsignedDword((pageDirectoryEntryMem&<uint32_t>0xfffff000)|pageTableOffset) # page table
if (pageDirectoryEntry&<uint32_t>0xfffff19f == pageDirectoryEntryMem&<uint32_t>0xfffff19f and pageTableEntry&<uint32_t>0xfffff19f == pageTableEntryMem&<uint32_t>0xfffff19f):
pageTablesEntryNew = pageTableEntryMem|(PAGE_WAS_USED | (written and PAGE_WRITTEN_ON_PAGE))
self.segments.main.mm.mmPhyWriteValue(((pageDirectoryEntryMem&<uint32_t>0xfffff000)|pageTableOffset), pageTablesEntryNew, OP_SIZE_DWORD) # page table
#self.segments.main.debug("Paging::setFlags: test6: pdo 0x%08x; pto 0x%08x", self.segments.main.mm.mmPhyReadValueUnsignedDword((self.pageDirectoryBaseAddress|pageDirectoryOffset)), self.segments.main.mm.mmPhyReadValueUnsignedDword(((pageDirectoryEntry&<uint32_t>0xfffff000)|pageTableOffset)))
if (not dataSize):
break
elif (dataSize < PAGE_DIRECTORY_LENGTH):
virtualAddress += dataSize
dataSize = 0
else:
virtualAddress += PAGE_DIRECTORY_LENGTH
dataSize -= PAGE_DIRECTORY_LENGTH
return True
cdef uint32_t getPhysicalAddress(self, uint32_t virtualAddress, uint32_t dataSize, uint8_t written) except? BITMASK_BYTE_CONST:
#IF 0:
cdef uint8_t cpl
IF COMP_DEBUG:
cdef uint32_t pageDirectoryEntryMem, pageTableEntryMem
#self.segments.main.notice("Paging::getPhysicalAddress: TODO! (savedEip: 0x%08x, savedCs: 0x%04x)", self.segments.main.cpu.savedEip, self.segments.main.cpu.savedCs)
#self.invalidateTables(self.pageDirectoryBaseAddress, False)
#self.invalidatePage(virtualAddress)
#if (self.segments.registers.cacheDisabled): # TODO?
# self.invalidateTable(virtualAddress)
self.pageDirectoryOffset = (virtualAddress>>22) << 2
self.pageTableOffset = ((virtualAddress>>12)&0x3ff) << 2
self.pageOffset = virtualAddress&0xfff
self.pageDirectoryEntry = self.tlbDirectories.csReadValueUnsignedDword(self.pageDirectoryOffset) # page directory
if (not self.pageDirectoryEntry):
IF COMP_DEBUG:
if (self.segments.main.debugEnabled):
self.segments.main.notice("Paging::getPhysicalAddress: PDE-Entry is zero, reloading. (entry: 0x%08x; addr: 0x%08x; vaddr: 0x%08x)", self.pageDirectoryEntry, self.pageDirectoryBaseAddress|self.pageDirectoryOffset, virtualAddress)
self.segments.main.notice("Paging::getPhysicalAddress: PDE-Entry is zero, reloading, PTE. (entry: 0x%08x; addr: 0x%08x; vaddr: 0x%08x)", self.tlbTables.csReadValueUnsignedDword((self.pageDirectoryOffset<<10)|self.pageTableOffset), (self.pageDirectoryEntry&<uint32_t>0xfffff000)|self.pageTableOffset, virtualAddress)
#self.invalidateTable(virtualAddress)
self.invalidatePage(virtualAddress)
self.pageDirectoryEntry = self.tlbDirectories.csReadValueUnsignedDword(self.pageDirectoryOffset) # page directory
IF COMP_DEBUG:
if (self.segments.main.debugEnabled):
self.segments.main.notice("Paging::getPhysicalAddress: PDE-Entry was zero, reloaded. (entry: 0x%08x; addr: 0x%08x; vaddr: 0x%08x)", self.pageDirectoryEntry, self.pageDirectoryBaseAddress|self.pageDirectoryOffset, virtualAddress)
self.segments.main.notice("Paging::getPhysicalAddress: PDE-Entry was zero, reloaded, PTE. (entry: 0x%08x; addr: 0x%08x; vaddr: 0x%08x)", self.tlbTables.csReadValueUnsignedDword((self.pageDirectoryOffset<<10)|self.pageTableOffset), (self.pageDirectoryEntry&<uint32_t>0xfffff000)|self.pageTableOffset, virtualAddress)
if (not (self.pageDirectoryEntry & PAGE_PRESENT)):
IF COMP_DEBUG:
if (self.segments.main.debugEnabled):
self.segments.main.notice("Paging::getPhysicalAddress: PDE-Entry is not present 1. (entry: 0x%08x; addr: 0x%08x; vaddr: 0x%08x)", self.pageDirectoryEntry, self.pageDirectoryBaseAddress|self.pageDirectoryOffset, virtualAddress)
self.segments.main.notice("Paging::getPhysicalAddress: TODO! (savedEip: 0x%08x, savedCs: 0x%04x)", self.segments.main.cpu.savedEip, self.segments.main.cpu.savedCs)
#self.invalidateTable(virtualAddress)
self.invalidatePage(virtualAddress)
self.pageDirectoryEntry = self.tlbDirectories.csReadValueUnsignedDword(self.pageDirectoryOffset) # page directory
if (not (self.pageDirectoryEntry & PAGE_PRESENT)):
IF COMP_DEBUG:
#IF 1:
self.segments.main.notice("Paging::getPhysicalAddress: PDE-Entry is not present 2. (entry: 0x%08x; addr: 0x%08x; vaddr: 0x%08x)", self.pageDirectoryEntry, self.pageDirectoryBaseAddress|self.pageDirectoryOffset, virtualAddress)
return self.doPF(virtualAddress, written)
if (self.pageDirectoryEntry & PAGE_SIZE): # it's a 4MB page
# size is 4MB if CR4/PSE is set
# size is 2MB if CR4/PAE is set
# if CR4/PAE bit is set size is 2MB and CR4/PSE bit appears as always set.
if (self.segments.registers.getFlagDword(CPU_REGISTER_CR4, CR4_FLAG_PAE) != 0):
self.segments.main.exitError("Paging::getPhysicalAddress: CR4/PAE is set.")
return False
elif (not self.segments.registers.getFlagDword(CPU_REGISTER_CR4, CR4_FLAG_PSE)):
self.segments.main.notice("Paging::getPhysicalAddress: not PSE. (entry: 0x%08x; addr: 0x%08x; vaddr: 0x%08x)", self.pageDirectoryEntry, self.pageDirectoryBaseAddress|self.pageDirectoryOffset, virtualAddress)
self.segments.main.notice("Paging::getPhysicalAddress: TODO! (savedEip: 0x%08x, savedCs: 0x%04x)", self.segments.main.cpu.savedEip, self.segments.main.cpu.savedCs)
self.segments.main.exitError("Paging::getPhysicalAddress: CR4/PSE isn't set.")
return False
self.segments.main.notice("Paging::getPhysicalAddress: EIP: 0x%08x, CS: 0x%04x", self.segments.main.cpu.savedEip, self.segments.main.cpu.savedCs)
self.segments.main.notice("Paging::getPhysicalAddress: PDE & PAGE_SIZE. (entry: 0x%08x; addr: 0x%08x; vaddr: 0x%08x)", self.pageDirectoryEntry, self.pageDirectoryBaseAddress|self.pageDirectoryOffset, virtualAddress)
self.segments.main.notice("Paging::getPhysicalAddress: 4MB pages are NOT FULLY SUPPORTED yet.")
self.segments.main.exitError("Paging::getPhysicalAddress: TODO... exiting.")
else:
self.pageTableEntry = self.tlbTables.csReadValueUnsignedDword((self.pageDirectoryOffset<<10)|self.pageTableOffset) # page table
if (not self.pageTableEntry):
IF COMP_DEBUG:
if (self.segments.main.debugEnabled):
self.segments.main.notice("Paging::getPhysicalAddress: PTE-Entry is zero, reloading. (entry: 0x%08x; addr: 0x%08x; vaddr: 0x%08x)", self.pageTableEntry, (self.pageDirectoryEntry&<uint32_t>0xfffff000)|self.pageTableOffset, virtualAddress)
#self.invalidateTable(virtualAddress)
self.invalidatePage(virtualAddress)
self.pageTableEntry = self.tlbTables.csReadValueUnsignedDword((self.pageDirectoryOffset<<10)|self.pageTableOffset) # page table
IF COMP_DEBUG:
if (self.segments.main.debugEnabled):
self.segments.main.notice("Paging::getPhysicalAddress: PTE-Entry was zero, reloaded. (entry: 0x%08x; addr: 0x%08x; vaddr: 0x%08x)", self.pageTableEntry, (self.pageDirectoryEntry&<uint32_t>0xfffff000)|self.pageTableOffset, virtualAddress)
if (not (self.pageTableEntry & PAGE_PRESENT)):
IF COMP_DEBUG:
if (self.segments.main.debugEnabled):
self.segments.main.notice("Paging::getPhysicalAddress: PTE-Entry is not present 1. (entry: 0x%08x; addr: 0x%08x; vaddr: 0x%08x)", self.pageTableEntry, (self.pageDirectoryEntry&<uint32_t>0xfffff000)|self.pageTableOffset, virtualAddress)
#self.invalidateTable(virtualAddress)
self.invalidatePage(virtualAddress)
self.pageTableEntry = self.tlbTables.csReadValueUnsignedDword((self.pageDirectoryOffset<<10)|self.pageTableOffset) # page table
if (not (self.pageTableEntry & PAGE_PRESENT)):
#if (virtualAddress == <uint32_t>0xe1005000):
# self.main.debugEnabledTest = self.main.debugEnabled = True
IF COMP_DEBUG:
#IF 1:
self.segments.main.notice("Paging::getPhysicalAddress: PTE-Entry is not present 2. (entry: 0x%08x; addr: 0x%08x; vaddr: 0x%08x)", self.pageTableEntry, (self.pageDirectoryEntry&<uint32_t>0xfffff000)|self.pageTableOffset, virtualAddress)
return self.doPF(virtualAddress, written)
cpl = self.segments.registers.getCPL()
if (self.pageDirectoryEntry & PAGE_SIZE):
if (not self.implicitSV and ((cpl == 3 and (not (self.pageDirectoryEntry&PAGE_EVERY_RING))) or \
(written and ((cpl == 3 or self.segments.registers.writeProtectionOn) and not (self.pageDirectoryEntry&PAGE_WRITABLE))))):
IF COMP_DEBUG:
#IF 1:
self.segments.main.notice("Paging::getPhysicalAddress: doPF_1")
return self.doPF(virtualAddress, written)
else:
if (not self.implicitSV and ((cpl == 3 and (not (self.pageDirectoryEntry&PAGE_EVERY_RING and self.pageTableEntry&PAGE_EVERY_RING))) or \
(written and ((cpl == 3 or self.segments.registers.writeProtectionOn) and not (self.pageDirectoryEntry&PAGE_WRITABLE and self.pageTableEntry&PAGE_WRITABLE))))):
IF COMP_DEBUG:
#IF 1:
self.segments.main.notice("Paging::getPhysicalAddress: doPF_2")
return self.doPF(virtualAddress, written)
self.setFlags(virtualAddress, dataSize, written)
self.instrFetch = self.implicitSV = False
#if (self.segments.main.debugEnabled):
#IF 1:
#IF 0:
IF COMP_DEBUG:
#self.pageDirectoryEntry = self.tlbDirectories.csReadValueUnsignedDword(self.pageDirectoryOffset) # page directory
#self.pageTableEntry = self.tlbTables.csReadValueUnsignedDword((self.pageDirectoryOffset<<10)|self.pageTableOffset) # page table
pageDirectoryEntryMem = self.segments.main.mm.mmPhyReadValueUnsignedDword(self.pageDirectoryBaseAddress|self.pageDirectoryOffset) # page directory
pageTableEntryMem = self.segments.main.mm.mmPhyReadValueUnsignedDword((pageDirectoryEntryMem&<uint32_t>0xfffff000)|self.pageTableOffset) # page table
if (self.segments.main.debugEnabled):
#if (self.segments.main.debugEnabled or self.pageDirectoryEntry != pageDirectoryEntryMem or self.pageTableEntry != pageTableEntryMem):
self.segments.main.notice("Paging::getPhysicalAddress: savedEip==0x%08x; savedCs==0x%04x", self.segments.main.cpu.savedEip, self.segments.main.cpu.savedCs)
self.segments.main.notice("Paging::getPhysicalAddress: virtualAddress==0x%08x; physicalAddress==0x%08x", virtualAddress, (self.pageTableEntry&<uint32_t>0xfffff000)|self.pageOffset)
self.segments.main.notice("Paging::getPhysicalAddress: PDEL==0x%08x, PTEL==0x%08x", self.pageDirectoryEntry, self.pageTableEntry)
self.segments.main.notice("Paging::getPhysicalAddress: PDEM==0x%08x, PTEM==0x%08x", pageDirectoryEntryMem, pageTableEntryMem)
self.segments.main.notice("Paging::getPhysicalAddress: PDO==0x%04x, PTO==0x%04x, PO==0x%04x", self.pageDirectoryOffset, self.pageTableOffset, self.pageOffset)
if (self.pageDirectoryEntry != pageDirectoryEntryMem):
if (self.pageDirectoryEntry&<uint32_t>0xfffff19f != pageDirectoryEntryMem&<uint32_t>0xfffff19f):
self.segments.main.notice("Paging::getPhysicalAddress: PDE too diff; virtualAddress==0x%08x", virtualAddress)
elif (self.segments.main.debugEnabled):
self.segments.main.notice("Paging::getPhysicalAddress: PDE diff; virtualAddress==0x%08x", virtualAddress)
if (self.pageTableEntry != pageTableEntryMem):
if (self.pageTableEntry&<uint32_t>0xfffff19f != pageTableEntryMem&<uint32_t>0xfffff19f):
self.segments.main.notice("Paging::getPhysicalAddress: PTE too diff; virtualAddress==0x%08x", virtualAddress)
elif (self.segments.main.debugEnabled):
self.segments.main.notice("Paging::getPhysicalAddress: PTE diff; virtualAddress==0x%08x", virtualAddress)
if (self.pageDirectoryEntry & PAGE_SIZE):
return (self.pageDirectoryEntry & <uint32_t>0xffc00000) | (self.pageTableOffset >> 2) | self.pageOffset
else:
return (self.pageTableEntry & <uint32_t>0xfffff000) | self.pageOffset
cdef class Segments:
def __init__(self, Registers registers, Hirnwichse main):
self.registers = registers
self.main = main
cdef uint8_t loadSegment(self, Segment *segment, uint16_t segmentIndex, uint8_t doInit) except BITMASK_BYTE_CONST:
cdef GdtEntry gdtEntry
cdef uint8_t protectedModeOn
if (segment[0].segId == CPU_SEGMENT_CS):
protectedModeOn = self.registers.protectedModeOn
else:
protectedModeOn = self.registers.getFlagDword(CPU_REGISTER_CR0, CR0_FLAG_PE) != 0
protectedModeOn = (protectedModeOn and not self.registers.regs[CPU_REGISTER_EFLAGS]._union.eflags_struct.vm)
segment[0].segmentIndex = segmentIndex
segment[0].readChecked = segment[0].writeChecked = False
if (not protectedModeOn):
segment[0].gdtEntry.base = <uint32_t>segmentIndex<<4
segment[0].isValid = segment[0].gdtEntry.segPresent = segment[0].gdtEntry.segIsNormal = True
segment[0].useGDT = segment[0].gdtEntry.anotherLimit = segment[0].segIsGDTandNormal = False
segment[0].gdtEntry.segSize = OP_SIZE_WORD
if (doInit or (self.registers.protectedModeOn and self.registers.regs[CPU_REGISTER_EFLAGS]._union.eflags_struct.vm)):
segment[0].gdtEntry.accessByte = 0x92
if (self.registers.protectedModeOn and self.registers.regs[CPU_REGISTER_EFLAGS]._union.eflags_struct.vm):
segment[0].segmentIndex |= 0x3
segment[0].gdtEntry.segDPL = 0x3
segment[0].gdtEntry.accessByte |= 0x60
segment[0].gdtEntry.limit = 0xffff
segment[0].gdtEntry.segIsRW = True
segment[0].gdtEntry.segIsConforming = segment[0].gdtEntry.segUse4K = False
segment[0].gdtEntry.flags = 0
segment[0].gdtEntry.segDPL = self.registers.getCPL()
if (segment[0].segId == CPU_SEGMENT_CS):
segment[0].gdtEntry.segIsCodeSeg = True
return True
if (not segmentIndex or not self.getEntry(&gdtEntry, segmentIndex)):
segment[0].useGDT = segment[0].gdtEntry.base = segment[0].gdtEntry.limit = segment[0].gdtEntry.accessByte = segment[0].gdtEntry.flags = segment[0].gdtEntry.segSize = segment[0].isValid = \
segment[0].gdtEntry.segPresent = segment[0].gdtEntry.segIsCodeSeg = segment[0].gdtEntry.segIsRW = segment[0].gdtEntry.segIsConforming = segment[0].gdtEntry.segIsNormal = \
segment[0].gdtEntry.segUse4K = segment[0].gdtEntry.segDPL = segment[0].gdtEntry.anotherLimit = segment[0].segIsGDTandNormal = 0
return False
segment[0].useGDT = True
segment[0].isValid = True
segment[0].gdtEntry.base = gdtEntry.base
segment[0].gdtEntry.limit = gdtEntry.limit
segment[0].gdtEntry.accessByte = gdtEntry.accessByte
segment[0].gdtEntry.flags = gdtEntry.flags
segment[0].gdtEntry.segSize = gdtEntry.segSize
segment[0].gdtEntry.segPresent = gdtEntry.segPresent
segment[0].gdtEntry.segIsCodeSeg = gdtEntry.segIsCodeSeg
segment[0].gdtEntry.segIsRW = gdtEntry.segIsRW
segment[0].gdtEntry.segIsConforming = gdtEntry.segIsConforming
segment[0].gdtEntry.segIsNormal = gdtEntry.segIsNormal
segment[0].gdtEntry.segUse4K = gdtEntry.segUse4K
segment[0].gdtEntry.segDPL = gdtEntry.segDPL
segment[0].gdtEntry.anotherLimit = gdtEntry.anotherLimit
segment[0].segIsGDTandNormal = segment[0].gdtEntry.segIsNormal
return True
cdef inline uint8_t getEntry(self, GdtEntry *gdtEntry, uint16_t num) except BITMASK_BYTE_CONST:
if (num & SELECTOR_USE_LDT):
return self.ldt.getEntry(gdtEntry, num)
return self.gdt.getEntry(gdtEntry, num)
cdef inline uint8_t getSegType(self, uint16_t num) except? BITMASK_BYTE_CONST:
if (num & SELECTOR_USE_LDT):
return self.ldt.getSegType(num)
return self.gdt.getSegType(num)
cdef inline uint8_t setSegType(self, uint16_t num, uint8_t segmentType) except BITMASK_BYTE_CONST:
if (num & SELECTOR_USE_LDT):
return self.ldt.setSegType(num, segmentType)
return self.gdt.setSegType(num, segmentType)
cdef inline uint8_t checkAccessAllowed(self, uint16_t num, uint8_t isStackSegment) except BITMASK_BYTE_CONST:
if (num & SELECTOR_USE_LDT):
return self.ldt.checkAccessAllowed(num, isStackSegment)
return self.gdt.checkAccessAllowed(num, isStackSegment)
cdef inline uint8_t checkReadAllowed(self, uint16_t num) except BITMASK_BYTE_CONST:
if (num & SELECTOR_USE_LDT):
return self.ldt.checkReadAllowed(num)
return self.gdt.checkReadAllowed(num)
cdef inline uint8_t checkWriteAllowed(self, uint16_t num) except BITMASK_BYTE_CONST:
if (num & SELECTOR_USE_LDT):
return self.ldt.checkWriteAllowed(num)
return self.gdt.checkWriteAllowed(num)
cdef inline uint8_t checkSegmentLoadAllowed(self, uint16_t num, uint16_t segId) except BITMASK_BYTE_CONST:
if (num & SELECTOR_USE_LDT):
return self.ldt.checkSegmentLoadAllowed(num, segId)
return self.gdt.checkSegmentLoadAllowed(num, segId)
cdef inline uint8_t inLimit(self, uint16_t num):
if (num & SELECTOR_USE_LDT):
return ((num&0xfff8) <= self.ldt.tableLimit)
return ((num&0xfff8) <= self.gdt.tableLimit)
cdef void run(self):
self.gdt = Gdt(self)
self.ldt = Gdt(self)
self.idt = Idt(self)
self.paging = Paging(self)
self.cs.segId = CPU_SEGMENT_CS
self.loadSegment(&self.cs, 0, True)
self.ss.segId = CPU_SEGMENT_SS
self.loadSegment(&self.ss, 0, True)
self.ds.segId = CPU_SEGMENT_DS
self.loadSegment(&self.ds, 0, True)
self.es.segId = CPU_SEGMENT_ES
self.loadSegment(&self.es, 0, True)
self.fs.segId = CPU_SEGMENT_FS
self.loadSegment(&self.fs, 0, True)
self.gs.segId = CPU_SEGMENT_GS
self.loadSegment(&self.gs, 0, True)
self.tss.segId = CPU_SEGMENT_TSS
self.loadSegment(&self.tss, 0, True)