* osal_mem.c
*
* osal driver
*
* Copyright (c) 2020-2021 Huawei Device Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include "osal_mem.h"
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
#include "hdf_log.h"
#include "securec.h"
#define HDF_LOG_TAG osal_mem
#define KMALLOC_SIZE 0x20000
struct mem_hdr {
uint32_t type;
uint32_t offset;
};
struct mem_block {
struct mem_hdr hdr;
uint8_t mem[0];
};
enum {
TYPE_KMALLOC = 0xa5a5a5a1,
TYPE_VMALLOC = 0xa5a5a5a2,
};
static void *osal_mem_alloc(size_t size, uint32_t *type)
{
char *base = NULL;
const uint32_t mng_size = sizeof(struct mem_block);
if (size > (SIZE_MAX - mng_size)) {
HDF_LOGE("%s invalid param %zu", __func__, size);
return NULL;
}
if (size > (KMALLOC_SIZE - mng_size)) {
base = (char *)vmalloc(size + mng_size);
*type = TYPE_VMALLOC;
} else {
base = (char *)kmalloc(size + mng_size, GFP_KERNEL);
*type = TYPE_KMALLOC;
}
return base;
}
void *OsalMemAlloc(size_t size)
{
void *buf = NULL;
char *base = NULL;
struct mem_block *block = NULL;
const uint32_t mng_size = sizeof(*block);
uint32_t type;
if (size == 0) {
HDF_LOGE("%s invalid param", __func__);
return NULL;
}
base = osal_mem_alloc(size, &type);
if (base == NULL) {
HDF_LOGE("%s malloc fail %d", __func__, size);
return NULL;
}
block = (struct mem_block *)base;
block->hdr.type = type;
block->hdr.offset = 0;
buf = (void *)(base + mng_size);
return buf;
}
EXPORT_SYMBOL(OsalMemAlloc);
void *OsalMemCalloc(size_t size)
{
void *buf = NULL;
if (size == 0) {
HDF_LOGE("%s invalid param", __func__);
return NULL;
}
buf = OsalMemAlloc(size);
if (buf != NULL)
(void)memset_s(buf, size, 0, size);
return buf;
}
EXPORT_SYMBOL(OsalMemCalloc);
void *OsalMemAllocAlign(size_t alignment, size_t size)
{
char *base = NULL;
char *buf = NULL;
struct mem_block *block = NULL;
const uint32_t mng_size = sizeof(*block);
uint32_t type;
uint32_t offset;
char *aligned_ptr = NULL;
if (size == 0 || (alignment == 0) || ((alignment & (alignment - 1)) != 0) ||
((alignment % sizeof(void *)) != 0) || size > (SIZE_MAX - alignment)) {
HDF_LOGE("%s invalid param align:%zu,size:%zu", __func__, alignment, size);
return NULL;
}
base = osal_mem_alloc(size + alignment, &type);
if (base == NULL) {
HDF_LOGE("%s malloc fail %d", __func__, size);
return NULL;
}
buf = base + mng_size;
aligned_ptr = (char *)(uintptr_t)(((size_t)(uintptr_t)buf + alignment - 1) & ~(alignment - 1));
offset = aligned_ptr - buf;
block = (struct mem_block *)(base + offset);
block->hdr.type = type;
block->hdr.offset = offset;
return aligned_ptr;
}
EXPORT_SYMBOL(OsalMemAllocAlign);
void OsalMemFree(void *buf)
{
uint32_t type;
char *base = NULL;
struct mem_block *block = NULL;
if (buf == NULL) {
return;
}
block = (struct mem_block *)((char *)buf - (char *)&((struct mem_block *)0)->mem);
type = block->hdr.type;
base = (char *)block - block->hdr.offset;
if (type == TYPE_KMALLOC)
kfree(base);
else if (type == TYPE_VMALLOC)
vfree(base);
else
HDF_LOGE("%s block : type %u fail", __func__, type);
}
EXPORT_SYMBOL(OsalMemFree);