/*by Breno S. Pinto*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/unistd.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/highmem.h>
#include <linux/string.h>
#include <asm/uaccess.h>
#include <asm/errno.h>
#include <asm/mman.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
#include <asm/processor.h>


#define NUM_mysyscallmem       230

extern void *sys_call_table[];
 

asmlinkage unsigned long (*original_call) (int numero,unsigned long address);
asmlinkage unsigned long my_syscallmem(int numero,unsigned long address);



struct page *my_teste_page_alloc_mem(struct vm_area_struct *vma,unsigned long address,int unused)
{
   struct page *page;

              page = alloc_page(GFP_USER);
               
	      if(!page) { 
                 printk("<2>Can not alloc new page\n");
                 return NOPAGE_OOM;
		 }



 return page;
}

struct vm_operations_struct my_vm_operation = {
nopage:    my_teste_page_alloc_mem,
};



asmlinkage unsigned long my_syscallmem(int numero,unsigned long address)
{
 unsigned long end;
 unsigned long len;
 unsigned int flags;
 unsigned int vmflags;
 struct vm_area_struct *vma;
 struct mm_struct *mm = current->mm;

 flags = MAP_ANON;
 
 len = PAGE_ALIGN(numero);
 
 down_write(&current->mm->mmap_sem);
 
 address = get_unmapped_area(NULL,address,len,0,flags);

 if(!address)
  {
   printk("<2>Can not define start address\n");
   return -ENOMEM;
   }
 
 end = address + len;
   
 if(end > TASK_SIZE)
  {
   printk("<2>No memory\n");
   return -ENOMEM;
   }
   
  vma = kmem_cache_alloc(vm_area_cachep,SLAB_KERNEL);
  if(!vma)
  return -ENOMEM;
  
 vmflags = mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_WRITE | VM_READ;
  
  vma->vm_mm = mm;
  vma->vm_start = address;  /*Start address*/
  vma->vm_end = end; /*Final address*/
  vma->vm_ops = &my_vm_operation; 
  vma->vm_flags = vmflags;
  vma->vm_pgoff = 0;
  vma->vm_file = NULL; /*MAP_NON*/
  vma->vm_private_data = NULL;
  vma->vm_raend = 0;
  vma->vm_page_prot = protection_map[vmflags & 0x0f];
 

 insert_vm_struct(mm,vma);


 up_write(&current->mm->mmap_sem);

 return address;
}

int init_module()
 { 
  original_call = sys_call_table[NUM_mysyscallmem];
  sys_call_table[NUM_mysyscallmem] = my_syscallmem;
  return 0;
}

int cleanup_module()
{
 sys_call_table[NUM_mysyscallmem] = original_call;
 return 0;
}


