From: Constantine Gavrilov <const-g@optibase.com>
To: middelink@polyware.nl
Cc: linux Kernel <linux-kernel@vger.kernel.org>
Subject: Use kernel module instead Big Physical Area patch
Date: Sun, 05 Aug 2001 13:51:37 +0300 [thread overview]
Message-ID: <3B6D2539.3060906@optibase.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 1685 bytes --]
Hi,
I wrote a small kernel module that defines and exports bfree() and
bmalloc() functions. The idea is to use this kernel module as a
replacement for big physcial area kernel patch.
For example, zoran kernel driver relies on the big physical area API for
v4l (used for video-in-a-window) to work. While the driver will compile
and load with a non-patched kernel, v4l will not work reliably without
big physical area support since the chip needs about 2megs of contiguous
memory to display in a window. This means one really has to use a
patched kernel.
This module removes this requirement and allows v4l to work reliably
with a non-patched kernel. The idea is to load the module from initrd or
right after boot. I have used __get_free_pages() and mem_map_reserve()
to pre-allocate the memory.
I have left the user-mode code that I used to debug allocation and
garbage collection. Compiled into a user-space program, the code will
allocate/free random chunks from a pre-allocated space and print out the
used list.
Comments?
Questions:
1) On a 256 MB machine, I was able to pre-allocate 512 pages using
__get_free_pages(...,get_order(size)). It is enough for one card, but
not for more. Any ideas on how to pre-allocate more?
2) __get_free_pages(...,get_order(size)) can be used to pre-allocate 2^n
contiguous pages (2,4,16,...512, ...., 1024). Can I use something else
from a kernel module to request a number that is not 2^n (say 750)?
--
----------------------------------------
Constantine Gavrilov
Linux Leader
Optibase Ltd
7 Shenkar St, Herzliya 46120, Israel
Phone: (972-9)-970-9140
Fax: (972-9)-958-6099
----------------------------------------
[-- Attachment #2: memreserve.c --]
[-- Type: text/plain, Size: 8411 bytes --]
/***************************************************************************
memreserve.c - description
-------------------
begin : Tue Jul 31 2001
copyright : (C) 2001 by Optibase Ltd
email : linux@optibase.com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef __KERNEL__
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
/* module stuff */
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
#define EXPORT_SYMBOL(x)
#define MODULE_PARM(x,y)
#define GFP_USER
#define GFP_DMA
/* memory management stuff */
#define kmalloc(x,y) (malloc(x))
#define kfree(x) (free(x))
#define __get_free_pages(x,y) (malloc(y))
#define free_pages(x, y) (free((void *)x))
#define mem_map_reserve(x) (printf("reserve print: 0x%08lx\n",x))
#define mem_map_unreserve(x) (printf("unreserve print: 0x%08lx\n",x))
#define virt_to_page(x) (x)
#define phys_to_virt(x) (x)
#define get_order(x) (x)
/* from asm/page.h */
#define PAGE_SHIFT 12
#define PAGE_SIZE (1UL << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE-1))
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
/* lock stuff */
#define write_lock(x) (pthread_mutex_lock(x))
#define write_unlock(x) (pthread_mutex_unlock(x))
#define RW_LOCK_UNLOCKED PTHREAD_MUTEX_INITIALIZER
#define rwlock_t pthread_mutex_t
/* printk stuff */
#define printk printf
#define KERN_WARNING
#define KERN_INFO
#define KERN_ERR
#define KERN_DEBUG
#else
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <asm/page.h>
#include <asm/io.h>
#include <linux/mm.h>
#include <linux/wrapper.h>
#endif
void bfree(void*, unsigned long);
void* bmalloc(unsigned long);
EXPORT_SYMBOL(bfree);
EXPORT_SYMBOL(bmalloc);
int reserve;
static unsigned long reserve_start;
MODULE_PARM(reserve, "i");
struct reserve_list {
unsigned long mem;
unsigned long size;
struct reserve_list *next;
};
struct reserve_list *used_list=NULL;
static rwlock_t alloc_ops=RW_LOCK_UNLOCKED;
#ifdef __KERNEL__
int init_module(void)
{
unsigned long adr;
unsigned long size;
#else
int init_module(int x)
{
unsigned long adr;
unsigned long size;
reserve=x;
#endif
if (!reserve) {
printk(KERN_ERR "memreserve: Supply a positive reserve param\n");
return -EINVAL;
}
size=reserve*PAGE_SIZE;
reserve_start = (unsigned long)__get_free_pages(GFP_USER|GFP_DMA,get_order(size));
if (reserve_start) {
adr = reserve_start;
while (size > 0) {
mem_map_reserve(virt_to_page(phys_to_virt(adr)));
adr += PAGE_SIZE;
size -= PAGE_SIZE;
}
}
else {
printk(KERN_ERR "memreserve: Cannot allocate contiguous memory of %lu bytes\n", size);
return -EINVAL;
}
printk(KERN_INFO "memreserve: Allocated contiguous memory of %lu bytes\n", reserve*PAGE_SIZE);
return 0;
}
void cleanup_module(void)
{
unsigned long adr;
unsigned long size;
if(used_list != NULL) {
printk(KERN_ERR "memreserve: Memory leak somewhere -- more than zero member in the used list\n");
printk(KERN_ERR "memreserve: Check your usage count\n");
printk(KERN_ERR "memreserve: Will not free memory\n");
return;
}
if (reserve_start) {
adr = reserve_start;
size = reserve * PAGE_SIZE;
while (size > 0) {
mem_map_unreserve(virt_to_page(phys_to_virt(adr)));
adr += PAGE_SIZE;
size -= PAGE_SIZE;
}
free_pages(reserve_start,get_order(reserve * PAGE_SIZE));
}
}
void* bmalloc(unsigned long req_size)
{
/*we need a lock here against simultaneous entry*/
struct reserve_list *list, *newmember, *prevmember;
unsigned long prevaddr, size;
write_lock(&alloc_ops);
size=PAGE_ALIGN(req_size);
prevaddr=reserve_start;
prevmember=NULL;
printk(KERN_DEBUG "memreserve: Rounded requested size %lu (0x%08lx) to 0x%08lx (%lu pages)\n", req_size, req_size,size, size/PAGE_SIZE);
for(list=used_list; list != NULL; list=list->next)
{
if( (list->mem - prevaddr) >= size) {
newmember=(struct reserve_list *)kmalloc(sizeof(struct reserve_list), GFP_USER);
if (!newmember) {
printk(KERN_ERR "memreserve: Out of memory\n");
write_unlock(&alloc_ops);
return NULL;
}
newmember->next=list;
newmember->mem=prevaddr;
newmember->size=size;
if(prevmember != NULL)
prevmember->next=newmember;
else
used_list=newmember;
MOD_INC_USE_COUNT;
write_unlock(&alloc_ops);
return (void *)prevaddr; /* we got our address */
}
prevmember=list;
prevaddr=list->mem+list->size;
}
/* list is NULL here; this code both works for both first and the last list member */
if(size <= reserve_start + (PAGE_SIZE * reserve) - prevaddr) {
newmember=(struct reserve_list *)kmalloc(sizeof(struct reserve_list), GFP_USER);
if (!newmember) {
printk(KERN_ERR "memreserve: Out of memory\n");
write_unlock(&alloc_ops);
return NULL;
}
newmember->mem=prevaddr;
newmember->size=size;
if(prevmember == NULL) /* this is the first member */
used_list=newmember;
else /* this is the last member */
prevmember->next=newmember;
newmember->next=NULL;
MOD_INC_USE_COUNT;
write_unlock(&alloc_ops);
return (void *)prevaddr; /* we got our address */
}
else
printk(KERN_WARNING "memreserve: Could not find big enough region in the free list\n");
write_unlock(&alloc_ops);
return NULL;
}
void bfree(void *mem, unsigned long req_size)
{
/*we need a lock here against simultaneous entry*/
struct reserve_list *list, *prevaddr;
unsigned long size;
write_lock(&alloc_ops);
size=PAGE_ALIGN(req_size);
prevaddr=NULL;
for(list=used_list; list != NULL; list=list->next) {
if(list->mem == (unsigned long)mem && list->size == size) {
if(prevaddr == NULL)
used_list=list->next;
else
prevaddr->next=list->next;
kfree(list);
MOD_DEC_USE_COUNT;
write_unlock(&alloc_ops);
return;
}
prevaddr=list;
}
printk(KERN_WARNING "memreserve: Someone requested illegal deallocation\n");
write_unlock(&alloc_ops);
}
void print_used_list(void)
{
/*we need a lock here against simultaneous entry*/
struct reserve_list *list;
write_lock(&alloc_ops);
printk(KERN_INFO "Reserve start is 0x%08lx, reserve size is 0x%08lx\n", reserve_start, reserve*PAGE_SIZE);
for(list=used_list; list != NULL; list=list->next) {
printk(KERN_INFO "memreserve: Address is 0x%08lx (%lu pages), size is 0x%08lx (%lu pages)\n", list->mem, list->mem/PAGE_SIZE, list->size, list->size/PAGE_SIZE);
}
write_unlock(&alloc_ops);
}
#ifndef __KERNEL__
int main()
{
int n=0;
int i=0;
int k;
struct reserve_list *list;
unsigned long choose_size(unsigned long);
int choose_index(int);
int choose_bool(void);
#define MAX_ALLOC 100
if(init_module(MAX_ALLOC) != 0) {
printf("Could not get memory\n");
exit(1);
}
while(n>=0) {
if(n<=3) {
if (bmalloc(choose_size(MAX_ALLOC)/10) != NULL)
n++;
}
else {
if(choose_bool() == 0) {
if (bmalloc(choose_size(MAX_ALLOC)/10) != NULL)
n++;
}
else {
i=choose_index(n);
list=used_list;
for(k=0;k<(i-1);k++)
list=list->next;
printf("Free index %d\n", i);
bfree((void *)list->mem, list->size);
n--;
}
}
print_used_list(); getchar();
}
cleanup_module();
return 0;
}
unsigned long choose_size(unsigned long MAX_SIZE)
{
double pos;
pos=((double)MAX_SIZE*(double)PAGE_SIZE*(double)random())/(double)(RAND_MAX+1.0);
return 1+(unsigned long) pos;
}
int choose_index(int MAX_INDEX)
{
double pos;
pos=((double)MAX_INDEX*(double)random())/(double)(RAND_MAX+1.0);
return 1+(int) pos;
}
int choose_bool(void)
{
long pos;
pos=random();
if(pos <= (RAND_MAX/2))
return 0;
else
return 1;
}
#endif
next reply other threads:[~2001-08-05 10:51 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2001-08-05 10:51 Constantine Gavrilov [this message]
2001-08-05 11:04 ` Use kernel module instead Big Physical Area patch Pauline Middelink
2001-08-05 12:42 ` Constantine Gavrilov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=3B6D2539.3060906@optibase.com \
--to=const-g@optibase.com \
--cc=linux-kernel@vger.kernel.org \
--cc=middelink@polyware.nl \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox