All of lore.kernel.org
 help / color / mirror / Atom feed
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

             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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.