214 lines
4.1 KiB
C
Executable File
214 lines
4.1 KiB
C
Executable File
/*
|
|
* hello-1.c - The simplest kernel module.
|
|
*/
|
|
#include <linux/module.h> /* Needed by all modules */
|
|
#include <linux/kernel.h> /* Needed for KERN_INFO */
|
|
#include <linux/slab.h>
|
|
|
|
#ifdef DBG_MEMORY_LEAK
|
|
#include <asm/atomic.h>
|
|
atomic_t _malloc_cnt = ATOMIC_INIT(0);
|
|
atomic_t _malloc_size = ATOMIC_INIT(0);
|
|
#endif /* DBG_MEMORY_LEAK */
|
|
|
|
void* _rtw_malloc(u32 sz)
|
|
{
|
|
void *pbuf = NULL;
|
|
|
|
pbuf = kmalloc(sz, /*GFP_KERNEL*/GFP_ATOMIC);
|
|
|
|
#ifdef DBG_MEMORY_LEAK
|
|
if (pbuf != NULL) {
|
|
atomic_inc(&_malloc_cnt);
|
|
atomic_add(sz, &_malloc_size);
|
|
}
|
|
#endif
|
|
|
|
return pbuf;
|
|
}
|
|
|
|
void _rtw_mfree(const void *pbuf, u32 sz)
|
|
{
|
|
if (pbuf)
|
|
{
|
|
kfree(pbuf);
|
|
|
|
#ifdef DBG_MEMORY_LEAK
|
|
atomic_dec(&_malloc_cnt);
|
|
atomic_sub(sz, &_malloc_size);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void* _rtw_zmalloc(u32 sz)
|
|
{
|
|
void *pbuf = _rtw_malloc(sz);
|
|
|
|
if (pbuf != NULL) {
|
|
memset(pbuf, 0, sz);
|
|
}
|
|
|
|
return pbuf;
|
|
}
|
|
|
|
#define rtw_malloc(sz) _rtw_malloc((sz))
|
|
#define rtw_zmalloc(sz) _rtw_zmalloc((sz))
|
|
#define rtw_mfree(pbuf, sz) _rtw_mfree((pbuf), (sz))
|
|
|
|
|
|
struct prealloc_node {
|
|
struct list_head entry;
|
|
int type;
|
|
int size;
|
|
void *buf;
|
|
};
|
|
|
|
struct list_head alloc_list;
|
|
struct list_head free_list;
|
|
spinlock_t lock;
|
|
|
|
void *rtw_find_prealloc(int type, size_t size)
|
|
{
|
|
struct list_head *phead, *plist;
|
|
struct prealloc_node *node;
|
|
unsigned long flags;
|
|
void *pbuf = NULL;
|
|
|
|
spin_lock_irqsave(&lock, flags);
|
|
|
|
phead = &free_list;
|
|
plist = phead->next;
|
|
while (plist != phead) {
|
|
node = list_entry(plist, struct prealloc_node, entry);
|
|
plist = plist->next;
|
|
|
|
if (node->type == type) {
|
|
// deletes entry from free_list
|
|
list_del(&node->entry);
|
|
// add a new entry to alloc_list
|
|
list_add_tail(&node->entry, &alloc_list);
|
|
pbuf = node->buf;
|
|
break;
|
|
}
|
|
}
|
|
|
|
spin_unlock_irqrestore(&lock, flags);
|
|
|
|
return pbuf;
|
|
}
|
|
|
|
void *rtw_pre_malloc(int type, size_t size)
|
|
{
|
|
struct prealloc_node *node;
|
|
void *pbuf;
|
|
unsigned long flags;
|
|
|
|
pbuf = rtw_find_prealloc(type, size);
|
|
if (pbuf)
|
|
return pbuf;
|
|
|
|
node = rtw_zmalloc(sizeof(struct prealloc_node));
|
|
if (NULL == node)
|
|
return NULL;
|
|
|
|
node->buf = rtw_zmalloc(size);
|
|
if (NULL == node->buf) {
|
|
rtw_mfree(node, sizeof(struct prealloc_node));
|
|
return NULL;
|
|
}
|
|
node->type = type;
|
|
node->size = size;
|
|
// add a new entry to alloc_list
|
|
spin_lock_irqsave(&lock, flags);
|
|
list_add_tail(&node->entry, &alloc_list);
|
|
spin_unlock_irqrestore(&lock, flags);
|
|
|
|
return node->buf;
|
|
}
|
|
EXPORT_SYMBOL(rtw_pre_malloc);
|
|
|
|
void rtw_pre_free(const void *p)
|
|
{
|
|
struct list_head *phead, *plist;
|
|
struct prealloc_node *node;
|
|
unsigned long flags;
|
|
|
|
spin_lock_irqsave(&lock, flags);
|
|
|
|
phead = &alloc_list;
|
|
plist = phead->next;
|
|
while (plist != phead) {
|
|
node = list_entry(plist, struct prealloc_node, entry);
|
|
plist = plist->next;
|
|
if (node->buf == p) {
|
|
// deletes entry from alloc_list
|
|
list_del(&node->entry);
|
|
// add a new entry to free_list
|
|
list_add_tail(&node->entry, &free_list);
|
|
goto out;
|
|
}
|
|
}
|
|
printk("[%s] invalid address.\n", __func__);
|
|
|
|
out:
|
|
spin_unlock_irqrestore(&lock, flags);
|
|
}
|
|
EXPORT_SYMBOL(rtw_pre_free);
|
|
|
|
void rtw_init(void)
|
|
{
|
|
INIT_LIST_HEAD(&alloc_list);
|
|
INIT_LIST_HEAD(&free_list);
|
|
spin_lock_init(&lock);
|
|
}
|
|
|
|
void rtw_free(void)
|
|
{
|
|
struct list_head *phead, *plist;
|
|
struct prealloc_node *node;
|
|
unsigned long flags;
|
|
|
|
spin_lock_irqsave(&lock, flags);
|
|
|
|
phead = &free_list;
|
|
plist = phead->next;
|
|
while (plist != phead) {
|
|
node = list_entry(plist, struct prealloc_node, entry);
|
|
plist = plist->next;
|
|
|
|
rtw_mfree(node->buf, node->size);
|
|
rtw_mfree(node, sizeof(struct prealloc_node));
|
|
}
|
|
|
|
phead = &alloc_list;
|
|
plist = phead->next;
|
|
while (plist != phead) {
|
|
node = list_entry(plist, struct prealloc_node, entry);
|
|
plist = plist->next;
|
|
|
|
printk("WARNING!! prealloc memory is not freed(type %d size %d).\n",
|
|
node->type, node->size);
|
|
rtw_mfree(node->buf, node->size);
|
|
rtw_mfree(node, sizeof(struct prealloc_node));
|
|
}
|
|
|
|
spin_unlock_irqrestore(&lock, flags);
|
|
}
|
|
|
|
int init_module(void)
|
|
{
|
|
printk(KERN_INFO "Hello world 1.\n");
|
|
rtw_init();
|
|
/*
|
|
* A non 0 return means init_module failed; module can't be loaded.
|
|
*/
|
|
return 0;
|
|
}
|
|
|
|
void cleanup_module(void)
|
|
{
|
|
printk(KERN_INFO "Goodbye world 1.\n");
|
|
rtw_free();
|
|
}
|
|
|