All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 2/3] kshmem implementation, configuration and makefile
@ 2007-05-06  1:53 Wink Saville
  0 siblings, 0 replies; only message in thread
From: Wink Saville @ 2007-05-06  1:53 UTC (permalink / raw)
  To: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

Signed-off-by: Wink Saville <wink-hKg/bvL8yClBDgjK7y7TUQ@public.gmane.org>
---
  include/asm-x86_64/kshmem.h |   17 +++
  include/linux/kshmem.h      |   47 +++++++
  include/linux/mm.h          |    1 +
  include/linux/vmalloc.h     |    3 +
  mm/Kconfig                  |    8 +
  mm/Makefile                 |    1 +
  mm/kshmem.c                 |  296 +++++++++++++++++++++++++++++++++++++++++++
  mm/vmalloc.c                |   37 +++++-
  8 files changed, 406 insertions(+), 4 deletions(-)
  create mode 100644 include/asm-x86_64/kshmem.h
  create mode 100644 include/linux/kshmem.h
  create mode 100644 mm/kshmem.c

Index: linux-2.6/include/asm-x86_64/kshmem.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/include/asm-x86_64/kshmem.h	2007-04-29 21:52:04.000000000 -0700
@@ -0,0 +1,17 @@
+/** * Copyright (C) 2007 Saville Software, Inc.
+ *
+ * This code may be used for any purpose whatsoever, but
+ * no warranty of any kind is provided.
+ */
+
+#ifndef _ASM_KSHMEM_H
+#define _ASM_KSHMEM_H
+
+#define KSHMEM_AREA_ADDR	0x6f8000000000
+#define KSHMEM_AREA_SIZE	0x008000000000
+#define KSHMEM_AREA_MASK	(~(KSHMEM_AREA_SIZE-1))
+
+#define KSHMEM_USER_DISABLE(x)	__pgd(pgd_val(x) & ~_PAGE_USER)
+#define KSHMEM_USER_ENABLE(x)	__pgd(pgd_val(x) | _PAGE_USER)
+
+#endif
Index: linux-2.6/include/linux/kshmem.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/include/linux/kshmem.h	2007-04-29 21:52:04.000000000 -0700
@@ -0,0 +1,47 @@
+/** * Copyright (C) 2007 Saville Software, Inc.
+ *
+ * This code may be used for any purpose whatsoever, but
+ * no warranty of any kind is provided.
+ */
+
+#ifndef _KSHMEM_H
+#define _KSHMEM_H
+
+#ifdef CONFIG_KSHMEM
+
+#include <asm/kshmem.h>
+
+#ifdef __KERNEL__
+
+extern void		kshmem_init(void);
+extern char *		kshmem_alloc_at(unsigned long location, unsigned long size, pgprot_t page_flags);
+extern void *		kshmem_alloc(unsigned long size, pgprot_t page_flags);
+extern void		kshmem_user_disable(void);
+extern void		kshmem_user_enable(void);
+extern int		kshmem_prepare(struct mm_struct *pNew_mm);
+extern unsigned long 	kshmem_addr_to_kvaddr(unsigned long kshmem_addr);
+
+#endif
+
+#else
+
+#ifdef __KERNEL__
+
+static inline void 	kshmem_init(void)
+				{}
+static inline char *	kshmem_alloc_at(unsigned long location, unsigned long size, pgprot_t page_flags)
+				{ BUG(); return NULL; }
+static inline void *	kshmem_alloc(unsigned long size, pgprot_t page_flags)
+				{ BUG(); return NULL; }
+static inline void 	kshmem_free(void *pAddr)
+				{ BUG(); }
+static inline int 	kshmem_prepare(struct mm_struct *pNew_mm)
+				{ return 0; }
+static inline unsigned long kshmem_addr_to_kvaddr(unsigned long kshmem_addr)
+				{ BUG(); return 0; }
+
+#endif
+
+#endif /* CONFIG_KSHMEM */
+
+#endif /* _KSHMEM_H */
Index: linux-2.6/include/linux/mm.h
===================================================================
--- linux-2.6.orig/include/linux/mm.h	2007-04-29 21:51:39.000000000 -0700
+++ linux-2.6/include/linux/mm.h	2007-04-29 21:52:04.000000000 -0700
@@ -169,6 +169,7 @@
  #define VM_MAPPED_COPY	0x01000000	/* T if mapped copy of data (nommu mmap) */
  #define VM_INSERTPAGE	0x02000000	/* The vma has had "vm_insert_page()" done on it */
  #define VM_ALWAYSDUMP	0x04000000	/* Always include in core dumps */
+#define VM_KSHMEM	0x08000000	/* Kernel shared memory */

  #ifndef VM_STACK_DEFAULT_FLAGS		/* arch can override this */
  #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
Index: linux-2.6/include/linux/vmalloc.h
===================================================================
--- linux-2.6.orig/include/linux/vmalloc.h	2007-04-29 21:51:39.000000000 -0700
+++ linux-2.6/include/linux/vmalloc.h	2007-04-29 21:52:04.000000000 -0700
@@ -42,6 +42,9 @@
  extern void *vmalloc_exec(unsigned long size);
  extern void *vmalloc_32(unsigned long size);
  extern void *vmalloc_32_user(unsigned long size);
+extern void *__vmalloc_at(unsigned long size, unsigned long flags,
+		unsigned long start, unsigned long end,
+	       	gfp_t gfp_mask, pgprot_t prot);
  extern void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot);
  extern void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask,
  				pgprot_t prot);
Index: linux-2.6/mm/Kconfig
===================================================================
--- linux-2.6.orig/mm/Kconfig	2007-04-29 21:51:39.000000000 -0700
+++ linux-2.6/mm/Kconfig	2007-04-29 21:56:30.000000000 -0700
@@ -163,3 +163,11 @@
  	default "0" if !ZONE_DMA
  	default "1"

+config KSHMEM
+	bool "Kernel shared memory"
+	def_bool n
+	help
+	  Allows an area of memory to be shared between the kernel and
+	  user space programs. For instance interrupt service routines
+	  and user space programs may share the same memory.
+
Index: linux-2.6/mm/Makefile
===================================================================
--- linux-2.6.orig/mm/Makefile	2007-04-29 21:51:39.000000000 -0700
+++ linux-2.6/mm/Makefile	2007-04-29 21:52:04.000000000 -0700
@@ -29,3 +29,4 @@
  obj-$(CONFIG_FS_XIP) += filemap_xip.o
  obj-$(CONFIG_MIGRATION) += migrate.o
  obj-$(CONFIG_SMP) += allocpercpu.o
+obj-$(CONFIG_KSHMEM) += kshmem.o
Index: linux-2.6/mm/kshmem.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/mm/kshmem.c	2007-04-29 21:52:04.000000000 -0700
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2007 Saville Software, Inc.
+ *
+ * This code may be used for any purpose whatsoever, but
+ * no warranty of any kind is provided.
+ */
+
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/kshmem.h>
+
+#include <asm/io.h>
+
+
+#define KSHMEM_DEBUG
+#ifdef KSHMEM_DEBUG
+#define DPK(fmt, args...) printk(KERN_ERR "kshmem " fmt, ## args)
+#else
+#define DPK(fmt, args...)
+#endif
+
+MODULE_AUTHOR("Wink Saville");
+MODULE_LICENSE("Dual BSD/GPL");
+
+#undef KSHMEM_FIX_PTL
+#ifdef KSHMEM_FIX_PTL
+
+/*
+ * get the pte pointer for the address
+ */
+static void _get_pti(struct mm_struct *mm,
+	       	    unsigned long addr,
+		    int *pageSize,
+		    pgd_t **pgd_ptr,
+		    pud_t **pud_ptr,
+		    pmd_t **pmd_ptr,
+		    pte_t **pte_ptr)
+{
+	int   page_size = 0;
+	pgd_t *pgd = NULL;
+	pud_t *pud = NULL;
+	pmd_t *pmd = NULL;
+	pte_t *pte = NULL;
+
+	if (mm == NULL) {
+		goto done;
+	}
+	pgd = pgd_offset(mm, addr);
+	if (pgd_none(*pgd)) goto done;
+	pud = pud_offset(pgd, addr);
+	if (pud_none(*pud)) goto done;
+	pmd = pmd_offset(pud, addr);
+	if (pmd_none(*pmd)) goto done;
+
+	if (pmd_large(*pmd))
+	{
+		pte = (pte_t *)pmd;
+		page_size = LARGE_PAGE_SIZE;
+	}
+	else
+	{
+		pte = pte_offset_map(pmd, addr);
+		page_size = PAGE_SIZE;
+	}
+done:
+	if (pageSize) *pageSize = page_size;
+	if (pgd_ptr) *pgd_ptr = pgd;
+	if (pud_ptr) *pud_ptr = pud;
+	if (pmd_ptr) *pmd_ptr = pmd;
+	if (pte_ptr) *pte_ptr = pte;
+}
+
+/*
+ * get the page table lock for the addr
+ */
+static spinlock_t *_get_ptl(struct mm_struct *mm, unsigned long addr)
+{
+       	pmd_t *pmd = NULL;
+
+       	_get_pti(mm, addr, NULL, NULL, NULL, &pmd, NULL);
+	if (pmd) {
+		return pte_lockptr(mm, pmd);
+	} else {
+		return NULL;
+	}
+}
+
+/*
+ * Fix the page table lock
+ */
+static void _fix_ptl(void *addr)
+{
+	spinlock_t 		*pLock;
+	struct mm_struct 	*cur_mm = current->active_mm;
+
+	/*
+	 * For some reason we need to initialize the page table lock (ptl)
+	 */
+	pLock = _get_ptl(cur_mm, (unsigned long)addr);
+	if (pLock) {
+		spin_lock_init(pLock);
+	} else {
+		DPK("_fix_ptl: src_mm=%p addr=%p NO PAGE!!! *********************\n",
+				cur_mm, addr);
+	}
+}
+#endif
+
+/*
+ * For all of the pages:
+ * 	- make sure they are present
+ * 	- get so they won't be deallocated
+ * 	- lock them down so they won't be swapped
+ */
+static void _fixate_range(char *pStart, char *pEnd)
+{
+	char *pAddr;
+
+	make_pages_present((unsigned long)pStart, (unsigned long)pEnd);
+
+	for (pAddr = pStart; pAddr < pEnd; pAddr += PAGE_SIZE) {
+		struct page *pPage = vmalloc_to_page(pAddr);
+
+		get_page(pPage);
+		SetPageLocked(pPage);
+#ifdef KSHMEM_FIX_PTL
+		_fix_ptl(pAddr);
+#endif
+	}
+}
+
+/*
+ * Allocate size number of bytes of kshmem at a specific location,
+ * page_flags should be PAGE_SHARED or PAGE_SHARED_EXEC.
+ *
+ * The resulting pointer will be page aligned and consume at least
+ * on page of memory.
+ */
+char *kshmem_alloc_at(unsigned long location, unsigned long size, pgprot_t page_flags)
+{
+	char *pStart;
+	struct mm_struct *cur_mm;
+
+	DPK("kshmem_alloc_at: current->mm=%p current->active_mm=%p &init_mm=%p\n", current->mm, current->active_mm, &init_mm);
+	/*
+	 * Save the current mm and switch to init_mm where we allocate
+	 * kshmem memory and then share with all other mm's.
+	 */
+	cur_mm	= current->mm;
+	current->mm = &init_mm;
+
+	/*
+	 * cur_mm is NULL when we start, maybe we should use
+	 * active_mm?
+	 */
+
+	/* Do we need to hold the semaphore? */
+	down_write(&init_mm.mmap_sem);
+
+	size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+	pStart = __vmalloc_at(size,
+				  VM_ALLOC | VM_USERMAP | VM_KSHMEM | VM_LOCKED | VM_SHARED,
+				  location, location + size,
+				  GFP_KERNEL | GFP_DMA, page_flags);
+	BUG_ON(pStart != (char *)location);
+	_fixate_range(pStart, pStart + size);
+
+	up_write(&init_mm.mmap_sem);
+
+	/*
+	 * Restore mm
+	 */
+	current->mm = cur_mm;
+
+	return pStart;
+}
+EXPORT_SYMBOL(kshmem_alloc_at);
+
+/*
+ * Allocate size number of bytes of kshmem, page_flags
+ * should be PAGE_SHARED or PAGE_SHARED_EXEC.
+ *
+ * The resulting pointer will be page aligned and consume at least
+ * on page of memory.
+ */
+void *kshmem_alloc(unsigned long size, pgprot_t page_flags)
+{
+	char *pStart;
+	struct mm_struct *cur_mm;
+
+	/*
+	 * Save the current mm and switch to init_mm where we allocate
+	 * kshmem memory and then share with all other mm's.
+	 */
+	cur_mm	= current->mm;
+	current->mm = &init_mm;
+
+	DPK("kshmem_alloc: cur_mm=%p current->mm=%p\n", cur_mm, current->mm);
+
+	/* Do we need to hold the semaphore? */
+	down_write(&init_mm.mmap_sem);
+
+	size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+	pStart = __vmalloc_at(size,
+				  VM_ALLOC | VM_USERMAP | VM_KSHMEM | VM_LOCKED | VM_SHARED,
+				  KSHMEM_AREA_ADDR, KSHMEM_AREA_ADDR + KSHMEM_AREA_SIZE,
+				  GFP_KERNEL | GFP_DMA, page_flags);
+	BUG_ON(NULL == pStart);
+	_fixate_range(pStart, pStart + size);
+
+	up_write(&init_mm.mmap_sem);
+
+	/*
+	 * Restore mm
+	 */
+	current->mm = cur_mm;
+
+	return pStart;
+}
+EXPORT_SYMBOL(kshmem_alloc);
+
+/*
+ * Prepare the kernel shared memory of the new_mm
+ */
+int kshmem_prepare(struct mm_struct *new_mm)
+{
+	/**
+	 * Set the pgd for the KSHMEM_AREA_ADDR and
+	 * point it at the pgd from init_mm.
+	 */
+	down_read(&init_mm.mmap_sem);
+	set_pgd(pgd_offset(new_mm, KSHMEM_AREA_ADDR),
+		       	KSHMEM_USER_DISABLE(*pgd_offset(&init_mm, KSHMEM_AREA_ADDR)));
+		       	//__pgd(pgd_val(*pgd_offset(&init_mm, KSHMEM_AREA_ADDR)) & ~_PAGE_USER));
+	up_read(&init_mm.mmap_sem);
+
+	return 0;
+}
+EXPORT_SYMBOL(kshmem_prepare);
+
+/*
+ * Disable the kshmem for the current mm
+ */
+void kshmem_user_disable(void)
+{
+	down_read(&current->active_mm->mmap_sem);
+	set_pgd(pgd_offset(current->active_mm, KSHMEM_AREA_ADDR),
+		       	KSHMEM_USER_DISABLE(*pgd_offset(&init_mm, KSHMEM_AREA_ADDR)));
+	up_read(&current->active_mm->mmap_sem);
+}
+
+/*
+ * Enable the kshmem for the current mm
+ */
+void kshmem_user_enable(void)
+{
+	down_read(&current->active_mm->mmap_sem);
+	set_pgd(pgd_offset(current->active_mm, KSHMEM_AREA_ADDR),
+		       	KSHMEM_USER_ENABLE(*pgd_offset(&init_mm, KSHMEM_AREA_ADDR)));
+	up_read(&current->active_mm->mmap_sem);
+}
+
+/*
+ * Convert a vmalloced address to a "kernel" virtual address
+ */
+unsigned long kshmem_addr_to_kvaddr(unsigned long kshmem_addr)
+{
+	struct page *p;
+	unsigned long phys;
+	unsigned long addr;
+
+	p = vmalloc_to_page((unsigned char *)kshmem_addr);
+	phys = page_to_phys(p);
+	addr = (unsigned long)phys_to_virt(phys) + offset_in_page(kshmem_addr);
+
+	return addr;
+}
+EXPORT_SYMBOL(kshmem_addr_to_kvaddr);
+
+/*
+ * Initialize
+ */
+void kshmem_init(void)
+{
+	char *p;
+
+	DPK("kshmem_init E:\n");
+
+	p = kshmem_alloc_at(KSHMEM_AREA_ADDR, PAGE_SIZE, PAGE_SHARED);
+	BUG_ON((unsigned long)p != KSHMEM_AREA_ADDR);
+
+	DPK("kshmem_init X: p=%p\n", p);
+}
+
+
Index: linux-2.6/mm/vmalloc.c
===================================================================
--- linux-2.6.orig/mm/vmalloc.c	2007-04-29 21:51:39.000000000 -0700
+++ linux-2.6/mm/vmalloc.c	2007-04-29 21:52:04.000000000 -0700
@@ -469,8 +469,11 @@
  }

  /**
- *	__vmalloc_node  -  allocate virtually contiguous memory
+ *	__vmalloc_node_at  -  allocate virtually contiguous memory
   *	@size:		allocation size
+ *	@flags:		flags for vm area
+ *	@start:		desired starting location
+ *	@end:		desired ending location
   *	@gfp_mask:	flags for the page level allocator
   *	@prot:		protection mask for the allocated pages
   *	@node:		node to use for allocation or -1
@@ -479,8 +482,9 @@
   *	allocator with @gfp_mask flags.  Map them into contiguous
   *	kernel virtual space, using a pagetable protection of @prot.
   */
-static void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot,
-			    int node)
+static void *__vmalloc_node_at(unsigned long size, unsigned long flags,
+				unsigned long start, unsigned long end,
+				gfp_t gfp_mask, pgprot_t prot, int node)
  {
  	struct vm_struct *area;

@@ -488,13 +492,38 @@
  	if (!size || (size >> PAGE_SHIFT) > num_physpages)
  		return NULL;

-	area = get_vm_area_node(size, VM_ALLOC, node, gfp_mask);
+	area = __get_vm_area_node(size, flags, start, end, node, gfp_mask);
  	if (!area)
  		return NULL;

  	return __vmalloc_area_node(area, gfp_mask, prot, node);
  }

+void *__vmalloc_at(unsigned long size, unsigned long flags,
+		unsigned long start, unsigned long end,
+	       	gfp_t gfp_mask, pgprot_t prot)
+{
+	return __vmalloc_node_at(size, flags, start, end, gfp_mask, prot, -1);
+}
+EXPORT_SYMBOL(__vmalloc_at);
+
+/**
+ *	__vmalloc_node  -  allocate virtually contiguous memory
+ *	@size:		allocation size
+ *	@gfp_mask:	flags for the page level allocator
+ *	@prot:		protection mask for the allocated pages
+ *	@node:		node to use for allocation or -1
+ *
+ *	Allocate enough pages to cover @size from the page level
+ *	allocator with @gfp_mask flags.  Map them into contiguous
+ *	kernel virtual space, using a pagetable protection of @prot.
+ */
+static void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot,
+			    int node)
+{
+	return __vmalloc_node_at(size, VM_ALLOC, VMALLOC_START, VMALLOC_END, gfp_mask, prot, node);
+}
+
  void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot)
  {
  	return __vmalloc_node(size, gfp_mask, prot, -1);


-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2007-05-06  1:53 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-05-06  1:53 [PATCH 2/3] kshmem implementation, configuration and makefile Wink Saville

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.