summaryrefslogtreecommitdiff
path: root/common/shmalloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/shmalloc.c')
-rw-r--r--common/shmalloc.c393
1 files changed, 0 insertions, 393 deletions
diff --git a/common/shmalloc.c b/common/shmalloc.c
deleted file mode 100644
index b1705b52d1..0000000000
--- a/common/shmalloc.c
+++ /dev/null
@@ -1,393 +0,0 @@
-/*
- * Copyright 2016 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-/* Malloc/free memory module for Chrome EC */
-#include <stdint.h>
-
-#include "common.h"
-#include "hooks.h"
-#include "link_defs.h"
-#include "shared_mem.h"
-#include "system.h"
-#include "task.h"
-#include "util.h"
-
-static struct mutex shmem_lock;
-
-#ifndef TEST_SHMALLOC
-#define set_map_bit(x)
-#define TEST_GLOBAL static
-#else
-#define TEST_GLOBAL
-#endif
-
-/*
- * At the beginning there is a single free memory chunk which includes all
- * memory available in the system. It then gets fragmented/defragmented based
- * on actual allocations/releases.
- */
-TEST_GLOBAL struct shm_buffer *free_buf_chain;
-
-/* At the beginning there is no allocated buffers */
-TEST_GLOBAL struct shm_buffer *allocced_buf_chain;
-
-/* The size of the biggest ever allocated buffer. */
-static int max_allocated_size;
-
-static void shared_mem_init(void)
-{
- /*
- * Use all the RAM we can. The shared memory buffer is the last thing
- * allocated from the start of RAM, so we can use everything up to the
- * jump data at the end of RAM.
- */
- free_buf_chain = (struct shm_buffer *)__shared_mem_buf;
- free_buf_chain->next_buffer = NULL;
- free_buf_chain->prev_buffer = NULL;
- free_buf_chain->buffer_size = system_usable_ram_end() -
- (uintptr_t)__shared_mem_buf;
-}
-DECLARE_HOOK(HOOK_INIT, shared_mem_init, HOOK_PRIO_FIRST);
-
-/* Called with the mutex lock acquired. */
-static void do_release(struct shm_buffer *ptr)
-{
- struct shm_buffer *pfb;
- struct shm_buffer *top;
- size_t released_size;
-
- /* Take the buffer out of the allocated buffers chain. */
- if (ptr == allocced_buf_chain) {
- if (ptr->next_buffer) {
- set_map_bit(BIT(20));
- ptr->next_buffer->prev_buffer = NULL;
- } else {
- set_map_bit(BIT(21));
- }
- allocced_buf_chain = ptr->next_buffer;
- } else {
- /*
- * Saninty check: verify that the buffer is in the allocated
- * buffers chain.
- */
- for (pfb = allocced_buf_chain->next_buffer;
- pfb;
- pfb = pfb->next_buffer)
- if (pfb == ptr)
- break;
- if (!pfb)
- return;
-
- ptr->prev_buffer->next_buffer = ptr->next_buffer;
- if (ptr->next_buffer) {
- set_map_bit(BIT(22));
- ptr->next_buffer->prev_buffer = ptr->prev_buffer;
- } else {
- set_map_bit(BIT(23));
- }
- }
-
- /*
- * Let's bring the released buffer back into the fold. Cache its size
- * for quick reference.
- */
- released_size = ptr->buffer_size;
- if (!free_buf_chain) {
- /*
- * All memory had been allocated - this buffer is going to be
- * the only available free space.
- */
- set_map_bit(BIT(0));
- free_buf_chain = ptr;
- free_buf_chain->buffer_size = released_size;
- free_buf_chain->next_buffer = NULL;
- free_buf_chain->prev_buffer = NULL;
- return;
- }
-
- if (ptr < free_buf_chain) {
- /*
- * Insert this buffer in the beginning of the chain, possibly
- * merging it with the first buffer of the chain.
- */
- pfb = (struct shm_buffer *)((uintptr_t)ptr + released_size);
- if (pfb == free_buf_chain) {
- set_map_bit(BIT(1));
- /* Merge the two buffers. */
- ptr->buffer_size = free_buf_chain->buffer_size +
- released_size;
- ptr->next_buffer =
- free_buf_chain->next_buffer;
- } else {
- set_map_bit(BIT(2));
- ptr->buffer_size = released_size;
- ptr->next_buffer = free_buf_chain;
- free_buf_chain->prev_buffer = ptr;
- }
- if (ptr->next_buffer) {
- set_map_bit(BIT(3));
- ptr->next_buffer->prev_buffer = ptr;
- } else {
- set_map_bit(BIT(4));
- }
- ptr->prev_buffer = NULL;
- free_buf_chain = ptr;
- return;
- }
-
- /*
- * Need to merge the new free buffer into the existing chain. Find a
- * spot for it, it should be above the highest address buffer which is
- * still below the new one.
- */
- pfb = free_buf_chain;
- while (pfb->next_buffer && (pfb->next_buffer < ptr))
- pfb = pfb->next_buffer;
-
- top = (struct shm_buffer *)((uintptr_t)pfb + pfb->buffer_size);
- if (top == ptr) {
- /*
- * The returned buffer is adjacent to an existing free buffer,
- * below it, merge the two buffers.
- */
- pfb->buffer_size += released_size;
-
- /*
- * Is the returned buffer the exact gap between two free
- * buffers?
- */
- top = (struct shm_buffer *)((uintptr_t)ptr + released_size);
- if (top == pfb->next_buffer) {
- /* Yes, it is. */
- pfb->buffer_size += pfb->next_buffer->buffer_size;
- pfb->next_buffer =
- pfb->next_buffer->next_buffer;
- if (pfb->next_buffer) {
- set_map_bit(BIT(5));
- pfb->next_buffer->prev_buffer = pfb;
- } else {
- set_map_bit(BIT(6));
- }
- }
- return;
- }
-
- top = (struct shm_buffer *)((uintptr_t)ptr + released_size);
- if (top == pfb->next_buffer) {
- /* The new buffer is adjacent with the one right above it. */
- set_map_bit(BIT(7));
- ptr->buffer_size = released_size +
- pfb->next_buffer->buffer_size;
- ptr->next_buffer = pfb->next_buffer->next_buffer;
- } else {
- /* Just include the new free buffer into the chain. */
- set_map_bit(BIT(8));
- ptr->next_buffer = pfb->next_buffer;
- ptr->buffer_size = released_size;
- }
- ptr->prev_buffer = pfb;
- pfb->next_buffer = ptr;
- if (ptr->next_buffer) {
- set_map_bit(BIT(9));
- ptr->next_buffer->prev_buffer = ptr;
- } else {
- set_map_bit(BIT(10));
- }
-}
-
-/* Called with the mutex lock acquired. */
-static int do_acquire(int size, struct shm_buffer **dest_ptr)
-{
- int headroom = 0x10000000; /* we'll never have this much. */
- struct shm_buffer *pfb;
- struct shm_buffer *candidate = 0;
-
- /* To keep things simple let's align the size. */
- size = (size + sizeof(int) - 1) & ~(sizeof(int) - 1);
-
- /* And let's allocate room to fit the buffer header. */
- size += sizeof(struct shm_buffer);
-
- pfb = free_buf_chain;
- while (pfb) {
- if ((pfb->buffer_size >= size) &&
- ((pfb->buffer_size - size) < headroom)) {
- /* this is a new candidate. */
- headroom = pfb->buffer_size - size;
- candidate = pfb;
- }
- pfb = pfb->next_buffer;
- }
-
- if (!candidate) {
- set_map_bit(BIT(11));
- return EC_ERROR_BUSY;
- }
-
- *dest_ptr = candidate;
-
- /* Now let's take the candidate out of the free buffer chain. */
- if (headroom <= sizeof(struct shm_buffer)) {
- /*
- * The entire buffer should be allocated, there is no need to
- * re-define its tail as a new free buffer.
- */
- if (candidate == free_buf_chain) {
- /*
- * The next buffer becomes the head of the free buffer
- * chain.
- */
- free_buf_chain = candidate->next_buffer;
- if (free_buf_chain) {
- set_map_bit(BIT(12));
- free_buf_chain->prev_buffer = 0;
- } else {
- set_map_bit(BIT(13));
- }
- } else {
- candidate->prev_buffer->next_buffer =
- candidate->next_buffer;
- if (candidate->next_buffer) {
- set_map_bit(BIT(14));
- candidate->next_buffer->prev_buffer =
- candidate->prev_buffer;
- } else {
- set_map_bit(BIT(15));
- }
- }
- return EC_SUCCESS;
- }
-
- candidate->buffer_size = size;
-
- /* Candidate's tail becomes a new free buffer. */
- pfb = (struct shm_buffer *)((uintptr_t)candidate + size);
- pfb->buffer_size = headroom;
- pfb->next_buffer = candidate->next_buffer;
- pfb->prev_buffer = candidate->prev_buffer;
-
- if (pfb->next_buffer) {
- set_map_bit(BIT(16));
- pfb->next_buffer->prev_buffer = pfb;
- } else {
- set_map_bit(BIT(17));
- }
-
- if (candidate == free_buf_chain) {
- set_map_bit(BIT(18));
- free_buf_chain = pfb;
- } else {
- set_map_bit(BIT(19));
- pfb->prev_buffer->next_buffer = pfb;
- }
- return EC_SUCCESS;
-}
-
-int shared_mem_size(void)
-{
- struct shm_buffer *pfb;
- size_t max_available = 0;
-
- mutex_lock(&shmem_lock);
-
- /* Find the maximum available buffer size. */
- pfb = free_buf_chain;
- while (pfb) {
- if (pfb->buffer_size > max_available)
- max_available = pfb->buffer_size;
- pfb = pfb->next_buffer;
- }
-
- mutex_unlock(&shmem_lock);
- /* Leave room for shmem header */
- max_available -= sizeof(struct shm_buffer);
- return max_available;
-}
-
-int shared_mem_acquire(int size, char **dest_ptr)
-{
- int rv;
- struct shm_buffer *new_buf;
-
- *dest_ptr = NULL;
-
- if (in_interrupt_context())
- return EC_ERROR_INVAL;
-
- if (!free_buf_chain)
- return EC_ERROR_BUSY;
-
- mutex_lock(&shmem_lock);
- rv = do_acquire(size, &new_buf);
- if (rv == EC_SUCCESS) {
- new_buf->next_buffer = allocced_buf_chain;
- new_buf->prev_buffer = NULL;
- if (allocced_buf_chain)
- allocced_buf_chain->prev_buffer = new_buf;
-
- allocced_buf_chain = new_buf;
-
- *dest_ptr = (void *)(new_buf + 1);
-
- if (size > max_allocated_size)
- max_allocated_size = size;
- }
- mutex_unlock(&shmem_lock);
-
- return rv;
-}
-
-void shared_mem_release(void *ptr)
-{
- if (in_interrupt_context())
- return;
-
- mutex_lock(&shmem_lock);
- do_release((struct shm_buffer *)ptr - 1);
- mutex_unlock(&shmem_lock);
-}
-
-#ifdef CONFIG_CMD_SHMEM
-
-static int command_shmem(int argc, char **argv)
-{
- size_t allocated_size;
- size_t free_size;
- size_t max_free;
- struct shm_buffer *buf;
-
- allocated_size = free_size = max_free = 0;
-
- mutex_lock(&shmem_lock);
-
- for (buf = free_buf_chain; buf; buf = buf->next_buffer) {
- size_t buf_room;
-
- buf_room = buf->buffer_size;
-
- free_size += buf_room;
- if (buf_room > max_free)
- max_free = buf_room;
- }
-
- for (buf = allocced_buf_chain; buf;
- buf = buf->next_buffer)
- allocated_size += buf->buffer_size;
-
- mutex_unlock(&shmem_lock);
-
- ccprintf("Total: %6zd\n", allocated_size + free_size);
- ccprintf("Allocated: %6zd\n", allocated_size);
- ccprintf("Free: %6zd\n", free_size);
- ccprintf("Max free buf: %6zd\n", max_free);
- ccprintf("Max allocated: %6d\n", max_allocated_size);
- return EC_SUCCESS;
-}
-DECLARE_SAFE_CONSOLE_COMMAND(shmem, command_shmem,
- NULL,
- "Print shared memory stats");
-
-#endif /* CONFIG_CMD_SHMEM ^^^^^^^ defined */