Skip to content

Conversation

@andyross
Copy link
Contributor

@andyross andyross commented Oct 6, 2021

The heap code was invalidating blocks on allocation, but that's the
wrong side of the pipe. By definition, new heap memory
will/should/must be written before being used (because the memory is
undefined), so any cached contents are irrelevant as they'll be
overwritten.

But when the user is finished with the block and frees it, there may
still be live dirty cache lines in the region on the current CPU.
Those must be invalidated, otherwise they will be evicted from the
cache at some point in the future, on top of the memory region now
being used for different purposes on another CPU.

Remove the invalidate on allocation. Add it back in free. Leverage a
new Zephyr sys_heap_block_size() routine to get the size so we don't
have to store it in an extra header.

Signed-off-by: Andy Ross andrew.j.ross@intel.com

@andyross
Copy link
Contributor Author

andyross commented Oct 6, 2021

As with all my submissions, this is more suggestion than validated submission. The logic is correct, but I can test it only through driver initialization right now.

Note that this needs a Zephyr tree with zephyrproject-rtos/zephyr#39191 applied

The heap code was invalidating blocks on allocation, but that's the
wrong side of the pipe.  By definition, new heap memory
will/should/must be written before being used (because the memory is
undefined), so any cached contents are irrelevant as they'll be
overwritten.

But when the user is finished with the block and frees it, there may
still be live dirty cache lines in the region on the current CPU.
Those must be invalidated, otherwise they will be evicted from the
cache at some point in the future, on top of the memory region now
being used for different purposes on another CPU.

Remove the invalidate on allocation.  Add it back in free.  Leverage a
new Zephyr sys_heap_usable_size() routine to get the size so we don't
have to store it in an extra header.

Signed-off-by: Andy Ross <andrew.j.ross@intel.com>

#ifdef ENABLE_CACHED_HEAP
z_xtensa_cache_flush_inv(z_soc_cached_ptr(mem),
sys_heap_usable_size(h, mem));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do I understand it correctly, that sys_heap_usable_size() returns the size of an allocated memory area, available to the user, excluding the preceding header, i.e. the same size, that the used has used to allocate that memory? Which means, cache of the header area isn't invalidated here? So, if that area is then reused, it can still be overwritten by a later cache eviction?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lyakh my understanding is that the zephyr allocator would do the header invalidate on incoherent systems ? @andyross ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The heap backend only ever uses the uncached mapping, and by construction it won't live in the same cache lines as a cached heap block (it's fixed here in this file to be an integer number of 64-byte cache lines).

It's true that there's still an opportunity for code somewhere to (1) allocate an uncached heap block (which has a header in the same cache line) and (2) convert it manually to a cached region, polluting cache lines on top of the heap metadata. But we really can't protect against that, it's just an API violation. Code that is using cached data needs to do it in dedicated lines always, by definition.

Copy link
Collaborator

@kv2019i kv2019i left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @andyross ! The current code is broken and won't compile if ENABLE_CACHED_HEAP is actually defined (broken by recent changes to heap sizes). I'll post a follow-up PR and incude Andy your patch in the series. It seems the zephyr-side change was already merged.

Copy link
Contributor

@keyonjie keyonjie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice fix, thanks.

I cook a similar one for XTOS allocator and it does fix bunch of memory corruption issues for me.
#4861

@lgirdwood
Copy link
Member

Closing since #4857 which includes this fix is merged.

@lgirdwood lgirdwood closed this Oct 15, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants