@@ -30,28 +30,15 @@ class MemoryState(Enum):
30
30
MEM_RESERVE = 0x2000
31
31
MEM_FREE = 0x10000
32
32
33
- class MemoryBasicInformation :
34
- def __init__ (self , base : int , allocation_base : int , allocation_protect : MemoryProtect ):
35
- self .base = base
36
- self .allocation_base = allocation_base
37
- self .allocation_protect = allocation_protect
38
- self .region_size : int = PAGE_SIZE
39
- self .state : MemoryState = None
40
- self .protect : MemoryProtect = None
41
- self .type : MemoryType = None
42
-
43
- def __str__ (self ):
44
- return f"MemoryBasicInformation(base: { hex (self .base )} , allocation_base: { hex (self .allocation_base )} , region_size: { hex (self .region_size )} , state: { self .state } , protect: { self .protect } , type: { self .type } )"
45
-
46
33
class MemoryRegion :
47
- def __init__ (self , start : int , size : int , protect : MemoryProtect = MemoryProtect .PAGE_NOACCESS , type : MemoryType = MemoryType .MEM_PRIVATE , comment : str = "" ):
34
+ def __init__ (self , start : int , size : int , protect : MemoryProtect = MemoryProtect .PAGE_NOACCESS , type : MemoryType = MemoryType .MEM_PRIVATE , info : Any = None ):
48
35
assert start & 0xFFF == 0
49
36
assert size & 0xFFF == 0
50
37
self .start = start
51
38
self .size = size
52
39
self .protect = protect
53
40
self .type = type
54
- self .comment = comment
41
+ self .info = info
55
42
56
43
@property
57
44
def end (self ):
@@ -84,12 +71,12 @@ def overlaps(self, other):
84
71
85
72
def __str__ (self ):
86
73
result = f"{ hex (self .start )} [{ hex (self .size )} ]"
87
- if len ( self .comment ) > 0 :
88
- result += f" ({ self .comment } )"
74
+ if self .info is not None :
75
+ result += f" ({ self .info } )"
89
76
return result
90
77
91
78
def __repr__ (self ) -> str :
92
- return f"MemoryRegion({ hex (self .start )} , { hex (self .size )} , { self .protect } , { self .type } , { self .comment } "
79
+ return f"MemoryRegion({ hex (self .start )} , { hex (self .size )} , { self .protect } , { self .type } , { repr ( self .info ) } ) "
93
80
94
81
def pages (self ):
95
82
for page in range (self .start , self .end , PAGE_SIZE ):
@@ -105,6 +92,20 @@ def decommit(self, addr: int, size: int) -> None:
105
92
def protect (self , addr : int , size : int , protect : MemoryProtect ) -> None :
106
93
raise NotImplementedError ()
107
94
95
+ class MemoryBasicInformation :
96
+ def __init__ (self , base : int , allocation_base : int , allocation_protect : MemoryProtect ):
97
+ self .base = base
98
+ self .allocation_base = allocation_base
99
+ self .allocation_protect = allocation_protect
100
+ self .region_size : int = PAGE_SIZE
101
+ self .state : MemoryState = None
102
+ self .protect : MemoryProtect = None
103
+ self .type : MemoryType = None
104
+ self .info : Any = None
105
+
106
+ def __str__ (self ):
107
+ return f"MemoryBasicInformation(base: { hex (self .base )} , allocation_base: { hex (self .allocation_base )} , region_size: { hex (self .region_size )} , state: { self .state } , protect: { self .protect } , type: { self .type } )"
108
+
108
109
class MemoryManager :
109
110
def __init__ (self , page_manager : PageManager , minimum = 0x10000 , maximum = 0x7fffffff0000 , granularity = 0x10000 ):
110
111
self ._page_manager = page_manager
@@ -114,9 +115,9 @@ def __init__(self, page_manager: PageManager, minimum = 0x10000, maximum = 0x7ff
114
115
self ._regions : List [MemoryRegion ] = []
115
116
self ._committed : Dict [int , MemoryRegion ] = {}
116
117
117
- def find_parent (self , region : Union [MemoryRegion , int ]):
118
+ def find_region (self , region : Union [MemoryRegion , int ]):
118
119
if isinstance (region , int ):
119
- region = MemoryRegion (self .page_align (region ), 0 )
120
+ region = MemoryRegion (self .align_page (region ), 0 )
120
121
index = bisect .bisect_right (self ._regions , region )
121
122
if index == 0 :
122
123
return None
@@ -127,31 +128,35 @@ def find_parent(self, region: Union[MemoryRegion, int]):
127
128
else :
128
129
return None
129
130
130
- def page_align (self , addr : int ):
131
+ def find_commit (self , addr : int ):
132
+ addr = self .align_page (addr )
133
+ return self ._committed .get (addr , None )
134
+
135
+ def align_page (self , addr : int ):
131
136
mask = PAGE_SIZE - 1
132
137
return (addr + mask ) & ~ mask
133
138
134
- def allocation_align (self , addr : int ):
139
+ def align_allocation (self , addr : int ):
135
140
mask = self ._granularity - 1
136
141
return (addr + mask ) & ~ mask
137
142
138
143
def find_free (self , size : int ):
139
- assert size > 0 and self .page_align (size ) == size
144
+ assert size > 0 and self .align_page (size ) == size
140
145
base = self ._minimum
141
146
while base < self ._maximum :
142
147
info = self .query (base )
143
148
assert info .base == base
144
- if info .state == MemoryState .MEM_FREE and info .region_size >= size and self .allocation_align (base ) == base :
149
+ if info .state == MemoryState .MEM_FREE and info .region_size >= size and self .align_allocation (base ) == base :
145
150
return info .base
146
151
base += info .region_size
147
152
return None
148
153
149
- def reserve (self , start : int , size : int , protect : MemoryProtect , type : MemoryType = MemoryType .MEM_PRIVATE , comment : str = "" ):
154
+ def reserve (self , start : int , size : int , protect : MemoryProtect , type : MemoryType = MemoryType .MEM_PRIVATE , info : Any = None ):
150
155
assert isinstance (protect , MemoryProtect )
151
156
assert isinstance (type , MemoryType )
152
- assert size > 0 and self .page_align (size ) == size
153
- assert self .allocation_align (start ) == start
154
- region = MemoryRegion (start , size , protect , type , comment )
157
+ assert size > 0 and self .align_page (size ) == size
158
+ assert self .align_allocation (start ) == start
159
+ region = MemoryRegion (start , size , protect , type , info )
155
160
if region .start < self ._minimum or region .end > self ._maximum :
156
161
raise KeyError (f"Requested region { region } is out of bounds" )
157
162
@@ -170,9 +175,9 @@ def check_overlaps(index):
170
175
self ._regions .insert (index , region )
171
176
172
177
def release (self , start : int ):
173
- assert self .allocation_align (start ) == start
178
+ assert self .align_allocation (start ) == start
174
179
175
- parent_region = self .find_parent (start )
180
+ parent_region = self .find_region (start )
176
181
if parent_region is None :
177
182
raise KeyError (f"Could not find parent for { hex (start )} " )
178
183
if parent_region .start != start :
@@ -191,10 +196,10 @@ def release(self, start: int):
191
196
192
197
def commit (self , start : int , size : int , protect : MemoryProtect = MemoryProtect .UNDEFINED ):
193
198
assert isinstance (protect , MemoryProtect )
194
- assert size > 0 and self .page_align (size ) == size
195
- assert self .page_align (start ) == start
199
+ assert size > 0 and self .align_page (size ) == size
200
+ assert self .align_page (start ) == start
196
201
region = MemoryRegion (start , size )
197
- parent_region = self .find_parent (region )
202
+ parent_region = self .find_region (region )
198
203
if parent_region is None :
199
204
raise KeyError (f"Could not find parent for { region } " )
200
205
@@ -208,17 +213,19 @@ def commit(self, start: int, size: int, protect: MemoryProtect = MemoryProtect.U
208
213
else :
209
214
for page in region .pages ():
210
215
if page in self ._committed :
211
- self ._page_manager .protect (page , PAGE_SIZE , protect )
212
- self ._committed [page ].protect = protect
216
+ page_region = self ._committed [page ]
217
+ if page_region .protect != protect :
218
+ self ._page_manager .protect (page , PAGE_SIZE , protect )
219
+ page_region .protect = protect
213
220
else :
214
221
self ._page_manager .commit (page , PAGE_SIZE , protect )
215
222
self ._committed [page ] = MemoryRegion (page , PAGE_SIZE , protect , parent_region .type )
216
223
217
224
def decommit (self , start : int , size : int ):
218
- assert size > 0 and self .page_align (size ) == size
219
- assert self .page_align (start ) == start
225
+ assert size > 0 and self .align_page (size ) == size
226
+ assert self .align_page (start ) == start
220
227
region = MemoryRegion (start , size )
221
- parent_region = self .find_parent (region )
228
+ parent_region = self .find_region (region )
222
229
if parent_region is None :
223
230
raise KeyError (f"Could not find parent for { region } " )
224
231
@@ -234,10 +241,10 @@ def decommit(self, start: int, size: int):
234
241
235
242
def protect (self , start : int , size : int , protect : MemoryProtect ):
236
243
assert isinstance (protect , MemoryProtect )
237
- assert size > 0 and self .page_align (size ) == size
238
- assert self .page_align (start ) == start
244
+ assert size > 0 and self .align_page (size ) == size
245
+ assert self .align_page (start ) == start
239
246
region = MemoryRegion (start , size )
240
- parent_region = self .find_parent (region )
247
+ parent_region = self .find_region (region )
241
248
if parent_region is None :
242
249
raise KeyError (f"Could not find parent for { region } " )
243
250
@@ -250,15 +257,17 @@ def protect(self, start: int, size: int, protect: MemoryProtect):
250
257
old_protect = self ._committed [region .start ].protect
251
258
self ._page_manager .protect (region .start , region .size , protect )
252
259
for page in region .pages ():
253
- self ._committed [page ].protect = protect
260
+ page_region = self ._committed [page ]
261
+ if page_region .protect != protect :
262
+ page_region .protect = protect
254
263
255
264
return old_protect
256
265
257
266
def query (self , start : int ):
258
- assert self .page_align (start ) == start
267
+ start = self .align_page (start )
259
268
260
269
region = MemoryRegion (start , 0 )
261
- parent_region = self .find_parent (region )
270
+ parent_region = self .find_region (region )
262
271
if parent_region is None :
263
272
index = bisect .bisect_right (self ._regions , region )
264
273
next_start = self ._maximum
@@ -279,11 +288,15 @@ def query(self, start: int):
279
288
continue
280
289
elif result is None :
281
290
result = MemoryBasicInformation (page , parent_region .start , parent_region .protect )
291
+ if page == parent_region .start :
292
+ result .info = parent_region .info
282
293
if page in self ._committed :
283
294
result .state = MemoryState .MEM_COMMIT
284
295
commited_page = self ._committed [page ]
285
296
result .protect = commited_page .protect
286
297
result .type = commited_page .type
298
+ if commited_page .info :
299
+ result .info = commited_page .info
287
300
assert commited_page .type == parent_region .type
288
301
else :
289
302
result .state = MemoryState .MEM_RESERVE
@@ -292,6 +305,8 @@ def query(self, start: int):
292
305
else :
293
306
commited_page = self ._committed .get (page , None )
294
307
if result .state == MemoryState .MEM_RESERVE :
308
+ if commited_page is not None :
309
+ break
295
310
result .region_size += PAGE_SIZE
296
311
elif result .state == MemoryState .MEM_COMMIT :
297
312
if commited_page is not None and commited_page .type == result .type and commited_page .protect == result .protect :
@@ -301,3 +316,12 @@ def query(self, start: int):
301
316
else :
302
317
assert False # unreachable
303
318
return result
319
+
320
+ def map (self ):
321
+ addr = self ._minimum
322
+ regions : List [MemoryBasicInformation ] = []
323
+ while addr < self ._maximum :
324
+ info = self .query (addr )
325
+ regions .append (info )
326
+ addr += info .region_size
327
+ return regions
0 commit comments