1 /*
2 * Copyright (c) 2017-2021, Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22 //!
23 //! \file memory_block.cpp
24 //! \brief Implements functionalities pertaining to memory blocks
25 //!
26
27 #include "memory_block.h"
28 #include "heap.h"
29
AddData(void * data,uint32_t dataOffset,uint32_t dataSize,bool zeroBlock)30 MOS_STATUS MemoryBlockInternal::AddData(
31 void* data,
32 uint32_t dataOffset,
33 uint32_t dataSize,
34 bool zeroBlock)
35 {
36 HEAP_FUNCTION_ENTER_VERBOSE;
37
38 if (m_state != allocated)
39 {
40 HEAP_ASSERTMESSAGE("Memory blocks may only have data added while in allocated state");
41 return MOS_STATUS_INVALID_PARAMETER;
42 }
43
44 if (data == nullptr && !zeroBlock)
45 {
46 HEAP_ASSERTMESSAGE("No data was passed in to be added");
47 return MOS_STATUS_INVALID_PARAMETER;
48 }
49
50 if (m_offset + dataOffset + dataSize > m_heap->GetSize() ||
51 dataOffset + dataSize > m_size)
52 {
53 HEAP_ASSERTMESSAGE("Data will not fit within the this memory block or state heap");
54 return MOS_STATUS_INVALID_PARAMETER;
55 }
56
57 uint8_t *lockedResource = m_heap->Lock();
58 HEAP_CHK_NULL(lockedResource);
59 lockedResource += m_offset + dataOffset;
60
61 if (zeroBlock)
62 {
63 memset(lockedResource, 0, m_size);
64 }
65 else
66 {
67 MOS_SecureMemcpy(
68 lockedResource,
69 m_size - dataOffset,
70 data,
71 dataSize);
72 }
73
74 m_heap->Unlock();
75
76 return MOS_STATUS_SUCCESS;
77 }
78
ReadData(void * data,uint32_t dataOffset,uint32_t dataSize)79 MOS_STATUS MemoryBlockInternal::ReadData(
80 void* data,
81 uint32_t dataOffset,
82 uint32_t dataSize)
83 {
84 HEAP_FUNCTION_ENTER_VERBOSE;
85
86 if (data == nullptr)
87 {
88 HEAP_ASSERTMESSAGE("Pointer for data to be read back must be valid");
89 return MOS_STATUS_INVALID_PARAMETER;
90 }
91
92 if (m_offset + dataOffset + dataSize > m_heap->GetSize() ||
93 dataOffset + dataSize > m_size)
94 {
95 HEAP_ASSERTMESSAGE("Data attempting to read is outside this memory block or state heap");
96 return MOS_STATUS_INVALID_PARAMETER;
97 }
98
99 uint8_t *lockedResource = m_heap->Lock();
100 HEAP_CHK_NULL(lockedResource);
101 lockedResource += m_offset + dataOffset;
102
103 MOS_SecureMemcpy(
104 data,
105 dataSize,
106 lockedResource,
107 dataSize);
108
109 m_heap->Unlock();
110
111 return MOS_STATUS_SUCCESS;
112 }
113
Dump(std::string filename,uint32_t offset,uint32_t size,bool dumpInBinary)114 MOS_STATUS MemoryBlockInternal::Dump(
115 std::string filename,
116 uint32_t offset,
117 uint32_t size,
118 bool dumpInBinary)
119 {
120 HEAP_FUNCTION_ENTER_VERBOSE;
121
122 if (m_state != allocated && m_state != submitted)
123 {
124 HEAP_ASSERTMESSAGE("Memory blocks not in allocated or submitted state do not containe valid data");
125 return MOS_STATUS_INVALID_PARAMETER;
126 }
127
128 size = size ? size : m_size;
129
130 if (m_offset + offset + size > m_heap->GetSize() ||
131 offset + size > m_size)
132 {
133 HEAP_ASSERTMESSAGE("Data will not fit within the this memory block or state heap");
134 return MOS_STATUS_INVALID_PARAMETER;
135 }
136
137 uint8_t *lockedResource = m_heap->Lock();
138 HEAP_CHK_NULL(lockedResource);
139 lockedResource += offset + m_offset;
140 if (dumpInBinary)
141 {
142 HEAP_CHK_STATUS(MosUtilities::MosWriteFileFromPtr(
143 filename.c_str(),
144 lockedResource,
145 size));
146 }
147 else
148 {
149 uint32_t *lockedResourceIn4Bytes = (uint32_t*)lockedResource;
150 uint32_t sizeIn32BitHex = size / sizeof(uint32_t);
151 uint32_t sizeOfLastHex = size % sizeof(uint32_t);
152 std::string formattedData = "";
153 char dataInHex[10] = {0};
154
155 for (uint32_t i = 0; i < sizeIn32BitHex; i++)
156 {
157 MOS_SecureStringPrint(
158 dataInHex,
159 sizeof(dataInHex),
160 sizeof(dataInHex),
161 "%.8x ",
162 lockedResourceIn4Bytes[i]);
163 formattedData += dataInHex;
164 if (i % 4 == 3)
165 {
166 formattedData += "\r\n";
167 }
168 }
169
170 if (sizeOfLastHex > 0) // one last incomplete dword to print out
171 {
172 uint32_t lastHex = lockedResourceIn4Bytes[sizeIn32BitHex];
173 lastHex = lastHex & ((4 - sizeOfLastHex) * 8);
174
175 MOS_SecureStringPrint(dataInHex, sizeof(dataInHex), sizeof(dataInHex), "%.8x ", lastHex);
176 formattedData += dataInHex;
177 }
178
179 HEAP_CHK_STATUS(MosUtilities::MosWriteFileFromPtr(
180 filename.c_str(),
181 (void*)formattedData.c_str(),
182 formattedData.size()));
183 }
184
185 m_heap->Unlock();
186
187 return MOS_STATUS_SUCCESS;
188 }
189
Create(Heap * heap,State requestedState,MemoryBlockInternal * prev,uint32_t offset,uint32_t size,uint32_t trackerId)190 MOS_STATUS MemoryBlockInternal::Create(
191 Heap *heap,
192 State requestedState,
193 MemoryBlockInternal *prev,
194 uint32_t offset,
195 uint32_t size,
196 uint32_t trackerId)
197 {
198 HEAP_FUNCTION_ENTER_VERBOSE;
199
200 HEAP_CHK_NULL(prev);
201
202 if (m_state == State::deleted)
203 {
204 HEAP_ASSERTMESSAGE("Deleted blocks may not be re-used.");
205 return MOS_STATUS_INVALID_PARAMETER;
206 }
207
208 if (heap == nullptr)
209 {
210 HEAP_ASSERTMESSAGE("Heap pointer is not valid");
211 return MOS_STATUS_INVALID_PARAMETER;
212 }
213 else if (!heap->IsValid())
214 {
215 HEAP_ASSERTMESSAGE("Heap is not valid");
216 return MOS_STATUS_INVALID_PARAMETER;
217 }
218
219 if (offset + size > heap->GetSize())
220 {
221 HEAP_ASSERTMESSAGE("Data will not fit within the state heap");
222 return MOS_STATUS_INVALID_PARAMETER;
223 }
224
225 m_heap = heap;
226 m_offset = offset;
227 m_size = size;
228
229 if (requestedState == State::free)
230 {
231 HEAP_CHK_STATUS(Free());
232 }
233 else if (requestedState == State::allocated)
234 {
235 HEAP_CHK_STATUS(Allocate(trackerId));
236 }
237 else
238 {
239 HEAP_ASSERTMESSAGE("Only free and allocated blocks can be created");
240 return MOS_STATUS_INVALID_PARAMETER;
241 }
242
243 m_prev = prev;
244 m_next = prev->m_next;
245 prev->m_next = this;
246 auto next = GetNext();
247 if (next)
248 {
249 next->m_prev = this;
250 }
251
252 // expected to be inserted into a sorted list by MemoryBlockManager
253 m_statePrev = m_stateNext = nullptr;
254
255 return MOS_STATUS_SUCCESS;
256 }
257
Combine(MemoryBlockInternal * block)258 MOS_STATUS MemoryBlockInternal::Combine(MemoryBlockInternal *block)
259 {
260 HEAP_FUNCTION_ENTER_VERBOSE;
261
262 HEAP_CHK_NULL(block);
263
264 if (block->m_state != State::free || m_state != State::free)
265 {
266 HEAP_ASSERTMESSAGE("Only free blocks may be combined");
267 return MOS_STATUS_INVALID_PARAMETER;
268 }
269 if (m_static)
270 {
271 HEAP_ASSERTMESSAGE("Static blocks may not be modified");
272 return MOS_STATUS_INVALID_PARAMETER;
273 }
274
275 auto currPrev = GetPrev();
276 auto currNext = GetNext();
277 if (currPrev == block)
278 {
279 m_offset = block->m_offset;
280 m_prev = block->m_prev;
281 currPrev = GetPrev();
282 if (currPrev)
283 {
284 currPrev->m_next = this;
285 }
286 }
287 else if (currNext == block)
288 {
289 m_next = block->m_next;
290 currNext = GetNext();
291 if (currNext)
292 {
293 currNext->m_prev = this;
294 }
295 }
296 else
297 {
298 HEAP_ASSERTMESSAGE("Only adjacent blocks may be combined");
299 return MOS_STATUS_INVALID_PARAMETER;
300 }
301
302 m_size += block->m_size;
303 block->Pool();
304
305 return MOS_STATUS_SUCCESS;
306 }
307
Split(MemoryBlockInternal * block,uint32_t size)308 MOS_STATUS MemoryBlockInternal::Split(MemoryBlockInternal *block, uint32_t size)
309 {
310 HEAP_FUNCTION_ENTER_VERBOSE;
311
312 HEAP_CHK_NULL(block);
313
314 if (size == 0 || m_size == size)
315 {
316 HEAP_ASSERTMESSAGE("It is not possible to split a block if the new block has no size");
317 return MOS_STATUS_INVALID_PARAMETER;
318 }
319
320 if (m_state != State::free)
321 {
322 HEAP_ASSERTMESSAGE("Only free blocks may be resized");
323 return MOS_STATUS_INVALID_PARAMETER;
324 }
325 if (m_static)
326 {
327 HEAP_ASSERTMESSAGE("Static blocks may not be modified");
328 return MOS_STATUS_INVALID_PARAMETER;
329 }
330
331 uint32_t newBlockSize = m_size - size;
332 HEAP_CHK_STATUS(block->Create(
333 m_heap,
334 State::free,
335 this,
336 m_offset + size,
337 newBlockSize,
338 m_invalidTrackerId));
339
340 m_size = size;
341
342 return MOS_STATUS_SUCCESS;
343 }
344
Pool()345 MOS_STATUS MemoryBlockInternal::Pool()
346 {
347 HEAP_FUNCTION_ENTER_VERBOSE;
348
349 if (m_state == State::allocated || m_state == State::submitted)
350 {
351 HEAP_ASSERTMESSAGE("Allocated and submitted blocks may not be added to the pool");
352 return MOS_STATUS_INVALID_PARAMETER;
353 }
354 if (m_stateListType != State::stateCount)
355 {
356 HEAP_ASSERTMESSAGE("Blocks must be removed from sorted list before changing state");
357 return MOS_STATUS_INVALID_PARAMETER;
358 }
359 if (m_static)
360 {
361 HEAP_ASSERTMESSAGE("Static blocks may not be added to the pool");
362 return MOS_STATUS_INVALID_PARAMETER;
363 }
364
365 m_state = State::pool;
366 m_heap = nullptr;
367 m_offset = 0;
368 m_size = 0;
369 m_static = false;
370 m_trackerId = m_invalidTrackerId;
371 m_trackerToken.Clear();
372 m_prev = m_next = nullptr;
373 m_statePrev = m_stateNext = nullptr;
374 m_stateListType = State::stateCount;
375
376 return MOS_STATUS_SUCCESS;
377 }
378
Free()379 MOS_STATUS MemoryBlockInternal::Free()
380 {
381 HEAP_FUNCTION_ENTER_VERBOSE;
382
383 if (m_state == State::deleted)
384 {
385 HEAP_ASSERTMESSAGE("Deleted blocks may not be moved to any state but pool");
386 return MOS_STATUS_INVALID_PARAMETER;
387 }
388 if (m_stateListType != State::stateCount)
389 {
390 HEAP_ASSERTMESSAGE("Blocks must be removed from sorted list before changing state");
391 return MOS_STATUS_INVALID_PARAMETER;
392 }
393 if (m_static)
394 {
395 HEAP_ASSERTMESSAGE("Static blocks may not be freed");
396 return MOS_STATUS_INVALID_PARAMETER;
397 }
398
399 if (m_state != State::pool &&
400 m_state != State::free)
401 {
402 HEAP_CHK_STATUS(m_heap->AdjustFreeSpace(m_size));
403 }
404
405 m_state = State::free;
406 m_trackerId = m_invalidTrackerId;
407 m_trackerToken.Clear();
408
409 return MOS_STATUS_SUCCESS;
410 }
411
Allocate(uint32_t trackerId)412 MOS_STATUS MemoryBlockInternal::Allocate(uint32_t trackerId)
413 {
414 HEAP_FUNCTION_ENTER_VERBOSE;
415
416 if (m_state != State::free)
417 {
418 HEAP_ASSERTMESSAGE("Only free blocks may be moved to allocated");
419 return MOS_STATUS_INVALID_PARAMETER;
420 }
421 if (m_stateListType != State::stateCount)
422 {
423 HEAP_ASSERTMESSAGE("Blocks must be removed from sorted list before changing state");
424 return MOS_STATUS_INVALID_PARAMETER;
425 }
426
427 if (trackerId == m_invalidTrackerId && !m_static)
428 {
429 HEAP_ASSERTMESSAGE("Only static blocks may have invalid tracker IDs");
430 return MOS_STATUS_INVALID_PARAMETER;
431 }
432
433 // Reflect the change in state from free space to used state.
434 HEAP_CHK_STATUS(m_heap->AdjustUsedSpace(m_size));
435
436 m_state = State::allocated;
437 m_trackerId = trackerId;
438
439 return MOS_STATUS_SUCCESS;
440 }
441
Allocate(uint32_t index,uint32_t trackerId,FrameTrackerProducer * producer)442 MOS_STATUS MemoryBlockInternal::Allocate(uint32_t index, uint32_t trackerId, FrameTrackerProducer *producer)
443 {
444 HEAP_FUNCTION_ENTER_VERBOSE;
445
446 if (m_state != State::free)
447 {
448 HEAP_ASSERTMESSAGE("Only free blocks may be moved to allocated");
449 return MOS_STATUS_INVALID_PARAMETER;
450 }
451 if (m_stateListType != State::stateCount)
452 {
453 HEAP_ASSERTMESSAGE("Blocks must be removed from sorted list before changing state");
454 return MOS_STATUS_INVALID_PARAMETER;
455 }
456
457 if (trackerId == m_invalidTrackerId && !m_static)
458 {
459 HEAP_ASSERTMESSAGE("Only static blocks may have invalid tracker IDs");
460 return MOS_STATUS_INVALID_PARAMETER;
461 }
462
463 // Reflect the change in state from free space to used state.
464 HEAP_CHK_STATUS(m_heap->AdjustUsedSpace(m_size));
465
466 m_state = State::allocated;
467 if (producer)
468 {
469 m_trackerToken.SetProducer(producer);
470 }
471 m_trackerToken.Merge(index, trackerId);
472
473 return MOS_STATUS_SUCCESS;
474 }
475
476
Submit()477 MOS_STATUS MemoryBlockInternal::Submit()
478 {
479 HEAP_FUNCTION_ENTER_VERBOSE;
480
481 if (m_state != State::allocated)
482 {
483 HEAP_ASSERTMESSAGE("Only allocated blocks may be submitted");
484 return MOS_STATUS_INVALID_PARAMETER;
485 }
486 if (m_static)
487 {
488 HEAP_ASSERTMESSAGE("Static blocks may not enter submitted state");
489 return MOS_STATUS_INVALID_PARAMETER;
490 }
491 if (m_stateListType != State::stateCount)
492 {
493 HEAP_ASSERTMESSAGE("Blocks must be removed from sorted list before changing state");
494 return MOS_STATUS_INVALID_PARAMETER;
495 }
496
497 m_state = State::submitted;
498
499 return MOS_STATUS_SUCCESS;
500 }
501
Delete()502 MOS_STATUS MemoryBlockInternal::Delete()
503 {
504 HEAP_FUNCTION_ENTER_VERBOSE;
505
506 MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
507
508 if (m_state == State::pool)
509 {
510 HEAP_ASSERTMESSAGE("Pool blocks should not be deleted");
511 return MOS_STATUS_INVALID_PARAMETER;
512 }
513 if (m_stateListType != State::stateCount)
514 {
515 HEAP_ASSERTMESSAGE("Blocks must be removed from sorted list before changing state");
516 return MOS_STATUS_INVALID_PARAMETER;
517 }
518 if (m_static)
519 {
520 HEAP_ASSERTMESSAGE("Static blocks may not be deleted");
521 return MOS_STATUS_INVALID_PARAMETER;
522 }
523
524 if (!m_heap->IsFreeInProgress())
525 {
526 HEAP_ASSERTMESSAGE("Blocks should not be deleted unless the heap is being freed");
527 return MOS_STATUS_INVALID_PARAMETER;
528 }
529
530 if (m_state != State::free && m_state != State::deleted)
531 {
532 HEAP_CHK_STATUS(m_heap->AdjustFreeSpace(m_size));
533 }
534
535 m_state = State::deleted;
536 m_trackerId = m_invalidTrackerId;
537 m_trackerToken.Clear();
538
539 return MOS_STATUS_SUCCESS;
540 }
541