[uClinux-dev] [PATCH 1/3] MPU support

2010-08-22 Thread Steve Longerbeam

This is a patch that adds Memory Protection Unit support for no-MMU ARM.

The default MPU configuration on most ARM7-based cores only allows MPU 
control of the first 1MB of address space. However this can be easily 
changed, and on our core the MPU controls the first 1GB of address 
space, and the space above that is accessible only in privileged kernel 
mode. With this the MPU actually becomes a useful means of restricting 
userland access to kernel space in uClinux.


This is the first in a set of three patches that provide a way to 
completely isolate userland from read/write access to kernel memory space.


This first patch provides the base MPU framework.

The platform-level code must implement a 'struct mpu' object that 
describes the MPU configuration of the core, and how to enable and 
disable MPU regions in the core. An example working implementation of 
'struct mpu' is provided in arch/arm/mm/sc100.c.


A process keeps track of its MPU regions with a 'struct mpu_region' 
object attached to its VMA's. During a context switch, the old processes 
mpu_regions are disabled, and the new processes mpu_regions are enabled, 
similar to how process page tables are switched. See switch_mm() for the 
no-MMU case.


The next patch will implement a private user memory pool that processes 
allocate from, instead of allocating from kernel memory with kmalloc. It 
uses the general purpose allocator library (genalloc.c). In combination 
with the MPU support, userland by default has access only to this 
private pool of memory.


The platform-level code will normally initialize two background MPU 
regions that are always active. The first gives kernel read/write access 
to all of memory space. The second gives user-level read/write access to 
the user memory pool.


MPU regions that are attached to process VMA's are due to mmap() 
requests for XIP private file mappings. Note that non-XIP file mappings 
allocate memory for the mapping from the user memory pool, so with the 
user memory background MPU region there is no need to create a new 
mpu-region for the mapping.


This patch is against the uclinux-888 release kernel.

Steve

diff -Nuar -X /home/stevel/dontdiff linux-2.6.x.orig/arch/arm/mm/Makefile linux-2.6.x/arch/arm/mm/Makefile
--- linux-2.6.x.orig/arch/arm/mm/Makefile	2010-08-22 15:22:54.391149924 -0700
+++ linux-2.6.x/arch/arm/mm/Makefile	2010-08-22 15:43:33.761212277 -0700
@@ -9,6 +9,7 @@
 
 ifneq ($(CONFIG_MMU),y)
 obj-y+= nommu.o consistent-nommu.o
+obj-$(CONFIG_CPU_CP15_MPU)	+= mpu.o
 endif
 
 obj-$(CONFIG_MODULES)		+= proc-syms.o
diff -Nuar -X /home/stevel/dontdiff linux-2.6.x.orig/arch/arm/mm/mpu.c linux-2.6.x/arch/arm/mm/mpu.c
--- linux-2.6.x.orig/arch/arm/mm/mpu.c	1969-12-31 16:00:00.0 -0800
+++ linux-2.6.x/arch/arm/mm/mpu.c	2010-08-22 15:29:28.916058187 -0700
@@ -0,0 +1,197 @@
+/*
+ *  linux/arch/arm/mm/mpu.c
+ *
+ *  Support for no-MMU processors that contain a Memory Protection Unit (MPU).
+ *
+ *  Copyright (C) 2009 Netspectrum Communication Systems, Inc.
+ *  Copyright (C) 2009 Silicon Storage Technology, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#include linux/types.h
+#include linux/kernel.h
+#include linux/init.h
+#include linux/init_task.h
+#include linux/mm.h
+#include asm/mpu.h
+
+static struct mpu * mpu = NULL;
+
+static const char * access_str[]  = {
+	[MPU_ACCESS_NONE] = no access,
+	[MPU_ACCESS_RO]   = r/o,
+	[MPU_ACCESS_RW]   = r/w,
+};
+
+/*
+ * Static background regions are allocated from lowest priority. The
+ * first user region requested will fix highest_bg_prio, and no more
+ * background region requests will be allowed after that.
+ */
+static int highest_bg_prio = 0;
+static int bg_prio_fixed = 0;
+
+static inline int find_free_prio(struct mm_struct * mm)
+{
+	struct vm_list_struct *vml;
+	int prio, inuse;
+	int ret = -ENOSPC;
+
+	for (prio = highest_bg_prio; prio  mpu-num_prio; prio++) {
+		inuse = 0;
+		for (vml = mm-context.vmlist; vml; vml = vml-next) {
+			if (!vml-vma || !vml-vma-vm_mpu)
+continue;
+			if (prio == vml-vma-vm_mpu-prio) {
+inuse = 1;
+break;
+			}
+		}
+		if (!inuse) {
+			ret = prio;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static inline int alloc_prio(struct mm_struct * mm)
+{
+	int prio;
+	
+	if (!mm) {
+		if (bg_prio_fixed)
+			return -EINVAL;
+		if (highest_bg_prio = mpu-num_prio - 1)
+			return -ENOSPC;
+		prio = highest_bg_prio++;
+	} else {
+		bg_prio_fixed = 1;
+		prio = find_free_prio(mm);
+	}
+
+	return prio;
+}
+
+/*
+ * The mm-mmap_sem should be held atleast for read when mm != NULL.
+ */
+int mpu_add_region(struct mm_struct * mm, struct mpu_region * region)
+{
+	int ret;
+	
+	if (!mpu || !mpu-add_region)
+		return -ENODEV;
+	if (!region ||
+	region-base  mpu-max_addr ||
+	region-limit  mpu-max_addr ||
+	region-base  region-limit)
+		return 

Re: [uClinux-dev] [PATCH 1/3] MPU support

2010-08-22 Thread Mike Frysinger
as it stands, this breaks all non-arm NOMMU ports.  the patch will need to be 
broken up into arm-specific and arm-independent parts.

the common code changes will need justification as to why they exist at all.  
we're doing MPU on Blackfin/nommu today without any of these.  we support 
pretty much all the same features of a MMU system short of virtual memory -- 
4k pages, RWX granularity, process to process protection, process to kernel 
protection (include kernel modules), kernel XIP, and userspace XIP.

further, why did you go with CONFIG_CPU_CP15_MPU ?  there is already a 
CONFIG_MPU option that is used in common nommu code.
-mike


signature.asc
Description: This is a digitally signed message part.
___
uClinux-dev mailing list
uClinux-dev@uclinux.org
http://mailman.uclinux.org/mailman/listinfo/uclinux-dev
This message was resent by uclinux-dev@uclinux.org
To unsubscribe see:
http://mailman.uclinux.org/mailman/options/uclinux-dev