genode/repos/dde_linux/src/include/lx_emul/impl/slab.h

176 lines
3.3 KiB
C

/*
* \brief Implementation of linux/slab.h
* \author Norman Feske
* \date 2015-09-09
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <lx_emul/impl/internal/malloc.h>
void *kmalloc(size_t size, gfp_t flags)
{
if (flags & __GFP_DMA)
PWRN("GFP_DMA memory (below 16 MiB) requested (%p)", __builtin_return_address(0));
if (flags & __GFP_DMA32)
PWRN("GFP_DMA32 memory (below 4 GiB) requested (%p)", __builtin_return_address(0));
void *addr = flags & GFP_LX_DMA ? Lx::Malloc::dma().alloc(size, 12)
: Lx::Malloc::mem().alloc(size);
if ((Genode::addr_t)addr & 0x3)
PERR("unaligned kmalloc %lx", (Genode::addr_t)addr);
if (flags & __GFP_ZERO)
Genode::memset(addr, 0, size);
return addr;
}
void *kzalloc(size_t size, gfp_t flags)
{
return kmalloc(size, flags | __GFP_ZERO);
}
void *kzalloc_node(size_t size, gfp_t flags, int node)
{
return kzalloc(size, 0);
}
void *kcalloc(size_t n, size_t size, gfp_t flags)
{
if (size != 0 && n > (~0UL / size))
return 0;
return kzalloc(n * size, flags);
}
void kfree(void const *p)
{
if (!p) return;
if (Lx::Malloc::mem().inside((Genode::addr_t)p))
Lx::Malloc::mem().free(p);
else if (Lx::Malloc::dma().inside((Genode::addr_t)p))
Lx::Malloc::dma().free(p);
else
PERR("%s: unknown block at %p, called from %p", __func__,
p, __builtin_return_address(0));
}
static size_t _ksize(void *p)
{
size_t size = 0;
if (Lx::Malloc::mem().inside((Genode::addr_t)p))
size = Lx::Malloc::mem().size(p);
else if (Lx::Malloc::dma().inside((Genode::addr_t)p))
size = Lx::Malloc::dma().size(p);
else
PERR("%s: unknown block at %p", __func__, p);
return size;
}
size_t ksize(void *p)
{
return _ksize(p);
}
void kzfree(void const *p)
{
if (!p) return;
size_t len = ksize(const_cast<void*>(p));
Genode::memset((void*)p, 0, len);
kfree(p);
}
void *kmalloc_node_track_caller(size_t size, gfp_t flags, int node)
{
return kmalloc(size, flags);
}
void *krealloc(void *p, size_t size, gfp_t flags)
{
/* XXX handle short-cut where size == old_size */
void *addr = kmalloc(size, flags);
if (addr && p) {
size_t old_size = _ksize(p);
Genode::memcpy(addr, p, old_size);
kfree(p);
}
return addr;
}
void *kmemdup(const void *src, size_t size, gfp_t flags)
{
void *addr = kmalloc(size, flags);
if (addr)
Genode::memcpy(addr, src, size);
return addr;
}
struct kmem_cache : Lx::Slab_alloc
{
kmem_cache(size_t object_size, bool dma)
:
Lx::Slab_alloc(object_size, dma ? Lx::Slab_backend_alloc::dma()
: Lx::Slab_backend_alloc::mem())
{ }
};
struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align,
unsigned long flags, void (*ctor)(void *))
{
if (ctor) {
PERR("%s: ctor not supported", __func__);
return nullptr;
}
/*
* Copied from wifi_drv.
*
* XXX SLAB_LX_DMA is never used anywhere else, remove it?
*/
enum { SLAB_LX_DMA = 0x80000000ul, };
return new (Genode::env()->heap()) kmem_cache(size, flags & SLAB_LX_DMA);
}
void * kmem_cache_alloc(struct kmem_cache *cache, gfp_t flags)
{
return (void *)cache->alloc();
}
void kmem_cache_free(struct kmem_cache *cache, void *objp)
{
cache->free(objp);
}