Skip to contentSkip to conversation

Yet another 4GB split patch

PATCH New Kirill Korotaev 1 participant 1 message Sep 10, 2004

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Yet another 4GB split patch

This is another 4GB split patch for kernel 2.4.27. It adds new configuration option called CONFIG_4GB.

It differs from Ingo Molnar patch in many ways and in architecture,
in way how it handles NMI issues, how it maps code, GDT, LDT and so on.
For compatibility issues it splits address space as 3:4, so user space applications do not see any difference in their address spaces. In recent version of this patch I used slightly modified copy_{to/from}_user interface from Ingo, so these patches have something in common.

This patch was used in a lot of production systems with very high loads, so it's tested very thoroughly. Some issues/problems I found in Ingo patch but fixed in my one I'll post here later.

I developed this patch a year ago, but due to copyright issues I was unsure to post it here. Now I'm happy to contribute this code back to Linux community.

Kirill

fs/namei.c renamed from fs/namei.c.4gb +5 -4
@@ -106,11 +106,12 @@ static inline int do_getname(const char 
 	int retval;
 	unsigned long len = PATH_MAX;
 
-	if ((unsigned long) filename >= TASK_SIZE) {
-		if (!segment_eq(get_fs(), KERNEL_DS))
+	if (!segment_eq(get_fs(), KERNEL_DS)) {
+		if ((unsigned long) filename >= TASK_SIZE)
 			return -EFAULT;
-	} else if (TASK_SIZE - (unsigned long) filename < PATH_MAX)
-		len = TASK_SIZE - (unsigned long) filename;
+		if (TASK_SIZE - (unsigned long) filename < PATH_MAX)
+			len = TASK_SIZE - (unsigned long) filename;
+	}
 
 	retval = strncpy_from_user((char *)page, filename, len);
 	if (retval > 0) {
kernel/module.c renamed from kernel/module.c.4gb +7 -0
@@ -436,6 +436,13 @@ sys_init_module(const char *name_user, s
 		printk(KERN_ERR "init_module: mod->cleanup out of bounds.\n");
 		goto err2;
 	}
+#ifdef CONFIG_4GB
+	/* indirect_xxx uaccess functions don't generate exception entries */
+	if (mod->ex_table_start || mod->ex_table_end) {
+		printk(KERN_ERR "init_module: not 4GB kernel module\n");
+		goto err2;
+	}
+#endif
 	if (mod->ex_table_start > mod->ex_table_end
 	    || (mod->ex_table_start &&
 		!((unsigned long)mod->ex_table_start >= ((unsigned long)mod + mod->size_of_struct)
mm/memory.c renamed from mm/memory.c.4gb +11 -1
@@ -402,7 +402,8 @@ void zap_page_range(struct mm_struct *mm
 /*
  * Do a quick page-table lookup for a single page. 
  */
-static struct page * follow_page(struct mm_struct *mm, unsigned long address, int write) 
+struct page * follow_page(struct mm_struct *mm, unsigned long address,
+		int write) 
 {
 	pgd_t *pgd;
 	pmd_t *pmd;
@@ -422,6 +423,15 @@ static struct page * follow_page(struct 
 
 	pte = *ptep;
 	if (pte_present(pte)) {
+#ifdef CONFIG_4GB
+		/*
+		 * this condition enables us to omit access_ok() checks in
+		 * indirect_XXX user access routines. i.e. we check here
+		 * (instead of access_ok()) that we try to access user pages.
+		 */
+		if (unlikely(!pte_user(pte)))
+			return 0;
+#endif
 		if (!write ||
 		    (pte_write(pte) && pte_dirty(pte)))
 			return pte_page(pte);
include/linux/mm.h renamed from include/linux/mm.h.4gb +2 -0
@@ -502,6 +502,8 @@ extern int ptrace_detach(struct task_str
 extern void ptrace_disable(struct task_struct *);
 extern int ptrace_check_attach(struct task_struct *task, int kill);
 
+struct page * follow_page(struct mm_struct *mm, unsigned long address,
+		int write);
 int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
 		int len, int write, int force, struct page **pages, struct vm_area_struct **vmas);
 
include/asm-i386/fixmap.h renamed from include/asm-i386/fixmap.h.4gb +101 -0

120 lines not on this page · raw message

include/asm-i386/hw_irq.h renamed from include/asm-i386/hw_irq.h.4gb +87 -5

146 lines not on this page · raw message

include/asm-i386/kmap_types.h renamed from include/asm-i386/kmap_types.h.4gb +1 -0
@@ -7,6 +7,7 @@ enum km_type {
 	KM_SKB_DATA_SOFTIRQ,
 	KM_USER0,
 	KM_USER1,
+	KM_USER_COPY,
 	KM_BH_IRQ,
 	KM_SOFTIRQ0,
 	KM_SOFTIRQ1,
include/asm-i386/mmu_context.h renamed from include/asm-i386/mmu_context.h.4gb +8 -0
@@ -37,8 +37,12 @@ static inline void switch_mm(struct mm_s
 		cpu_tlbstate[cpu].active_mm = next;
 #endif
 		set_bit(cpu, &next->cpu_vm_mask);
+#ifndef CONFIG_4GB
 		/* Re-load page tables */
 		load_cr3(next->pgd);
+#else
+		/* %cr3 is reloaded on returning to user space, see entry.S */
+#endif
 	 	/* load_LDT, if either the previous or next thread
 		 * has a non-default LDT.
 		 */
@@ -54,7 +58,11 @@ static inline void switch_mm(struct mm_s
 			/* We were in lazy tlb mode and leave_mm disabled 
 			 * tlb flush IPI delivery. We must reload %cr3.
 			 */
+#ifndef CONFIG_4GB
 			load_cr3(next->pgd);
+#else
+			local_flush_tlb();
+#endif
 			load_LDT(&next->context);
 		}
 	}
include/asm-i386/page.h renamed from include/asm-i386/page.h.4gb +6 -1
@@ -78,13 +78,18 @@ typedef struct { unsigned long pgprot; }
  * and CONFIG_HIGHMEM64G options in the kernel configuration.
  */
 
-#define __PAGE_OFFSET		(0xC0000000)
+#include <asm/page_offset.h>
+#define __PAGE_OFFSET          PAGE_OFFSET_RAW
 
 /*
  * This much address space is reserved for vmalloc() and iomap()
  * as well as fixmap mappings.
  */
+#ifndef CONFIG_4GB
 #define __VMALLOC_RESERVE	(128 << 20)
+#else
+#define __VMALLOC_RESERVE	(512 << 20)
+#endif
 
 #ifndef __ASSEMBLY__
 
include/asm-i386/page_offset.h new file +27 -0
@@ -0,0 +1,27 @@
+#ifndef __PAGE_OFFSET_H__
+#define __PAGE_OFFSET_H__
+
+#include <linux/config.h>
+
+#if   defined(CONFIG_1GB)
+#define PAGE_OFFSET_RAW 0xC0000000
+#elif defined(CONFIG_2GB)
+#define PAGE_OFFSET_RAW 0x80000000
+#elif defined(CONFIG_3GB)
+#define PAGE_OFFSET_RAW 0x40000000
+#elif defined(CONFIG_4GB)
+
+/*
+ * PAGE_OFFSET_RAW can be as low as 32Mb
+ * 4 pgds (32 Mb) are required when PAE pgd is initialized
+ */
+#define PAGE_OFFSET_RAW 0x02000000
+/*
+ * default value 0xffc00000 means the highest pgd in non-PAE kernel
+ * and the last pmd-1 in PAE-enabled kernel
+ */
+#define SPLIT_4GB_MAP_START 0xffc00000
+
+#endif
+
+#endif
include/asm-i386/pgtable.h renamed from include/asm-i386/pgtable.h.4gb +19 -4
@@ -158,7 +158,14 @@ extern void pgtable_cache_init(void);
  * area for the same reason. ;)
  */
 #define VMALLOC_OFFSET	(8*1024*1024)
-#define VMALLOC_START	(((unsigned long) high_memory + 2*VMALLOC_OFFSET-1) & \
+#ifdef CONFIG_4GB
+/* vmalloc has to be higher than TASK_SIZE for ldt mappings */
+#define __VMALLOC_START (((unsigned long)high_memory > TASK_SIZE) ? \
+		(unsigned long)high_memory : TASK_SIZE)
+#else
+#define __VMALLOC_START ((unsigned long)high_memory)
+#endif
+#define VMALLOC_START	((__VMALLOC_START + 2*VMALLOC_OFFSET-1) & \
 						~(VMALLOC_OFFSET-1))
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
 #if CONFIG_HIGHMEM
@@ -213,9 +220,9 @@ extern void pgtable_cache_init(void);
 	(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED)
 
 #ifdef CONFIG_X86_PGE
-# define MAKE_GLOBAL(x) __pgprot((x) | _PAGE_GLOBAL)
+# define _MAKE_GLOBAL(x) __pgprot((x) | _PAGE_GLOBAL)
 #else
-# define MAKE_GLOBAL(x)						\
+# define _MAKE_GLOBAL(x)						\
 	({							\
 		pgprot_t __ret;					\
 								\
@@ -227,6 +234,13 @@ extern void pgtable_cache_init(void);
 	})
 #endif
 
+#ifdef CONFIG_4GB
+/* global pages are not allowed when 4Gb kernel/user space split is used */
+#define MAKE_GLOBAL(x) __pgprot(x)
+#else
+#define MAKE_GLOBAL(x) _MAKE_GLOBAL(x)
+#endif
+
 #define PAGE_KERNEL MAKE_GLOBAL(__PAGE_KERNEL)
 #define PAGE_KERNEL_RO MAKE_GLOBAL(__PAGE_KERNEL_RO)
 #define PAGE_KERNEL_NOCACHE MAKE_GLOBAL(__PAGE_KERNEL_NOCACHE)
@@ -279,6 +293,7 @@ extern unsigned long pg0[1024];
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
+static inline int pte_user(pte_t pte)		{ return (pte).pte_low & _PAGE_USER; }
 static inline int pte_read(pte_t pte)		{ return (pte).pte_low & _PAGE_USER; }
 static inline int pte_exec(pte_t pte)		{ return (pte).pte_low & _PAGE_USER; }
 static inline int pte_dirty(pte_t pte)		{ return (pte).pte_low & _PAGE_DIRTY; }
@@ -324,7 +339,7 @@ static inline pte_t pte_modify(pte_t pte
 ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
 
 /* to find an entry in a page-table-directory. */
-#define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
 
 #define __pgd_offset(address) pgd_index(address)
 
include/asm-i386/processor.h renamed from include/asm-i386/processor.h.4gb +24 -0
@@ -259,7 +259,15 @@ extern unsigned int mca_pentium_flag;
 /*
  * User space process size: 3GB (default).
  */
+#ifdef CONFIG_4GB
+/*
+ * For 4gb split we explicitly set task size to 3Gb,
+ * since PAGE_OFFSET means kernel offset here
+ */
+#define TASK_SIZE	(0xC0000000)
+#else
 #define TASK_SIZE	(PAGE_OFFSET)
+#endif
 
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
@@ -363,6 +371,13 @@ struct thread_struct {
 	unsigned long	esp;
 	unsigned long	fs;
 	unsigned long	gs;
+#ifdef CONFIG_4GB
+	unsigned long	utask;		/* U-space task_struct */
+	unsigned long	ktask;		/* kernel mapped task */
+	unsigned long	reloaddbg;	/* db regs should be reloaded on ret
+					   to user? see do_debug(), entry.S */
+	unsigned long	cr3;		/* user space cr3 value */
+#endif
 /* Hardware debugging registers */
 	unsigned long	debugreg[8];  /* %%db0-7 debug registers */
 /* fault info */
@@ -378,9 +393,18 @@ struct thread_struct {
 	unsigned long	io_bitmap[IO_BITMAP_SIZE+1];
 };
 
+#ifdef CONFIG_4GB
+#define INIT_SPLIT_4GB_THREAD_REGS				\
+	0, (unsigned long)&init_task, 0,			\
+	(unsigned long)&swapper_pg_dir - PAGE_OFFSET, /* cr3 */
+#else
+#define INIT_SPLIT_4GB_THREAD_REGS
+#endif
+
 #define INIT_THREAD  {						\
 	0,							\
 	0, 0, 0, 0, 						\
+	INIT_SPLIT_4GB_THREAD_REGS				\
 	{ [0 ... 7] = 0 },	/* debugging registers */	\
 	0, 0, 0,						\
 	{ { 0, }, },		/* 387 state */			\
include/asm-i386/string.h renamed from include/asm-i386/string.h.4gb +28 -0
@@ -62,6 +62,34 @@ __asm__ __volatile__(
 return dest;
 }
 
+/*
+ * This is a more generic variant of strncpy_count() suitable for
+ * implementing string-access routines with all sorts of return
+ * code semantics. It's used by arch/i386/mm/usercopy.c.
+ *
+ * strncpy_count returns num of bytes left = (count-strlen(src)), i.e.
+ * count=0, strlen(src)=#,   res=0
+ * count=n, strlen(src)=m<n, res=n-m (0 is not counted, but copied!)
+ * count=n, strlen(src)=n-1, res=1
+ * count=n, strlen(src)=n,   res=0
+ */
+static inline size_t strncpy_count(char * dest,const char *src,size_t count)
+{
+	__asm__ __volatile__(
+	"1:\tdecl %0\n\t"
+	"js 2f\n\t"
+	"lodsb\n\t"
+	"stosb\n\t"
+	"testb %%al,%%al\n\t"
+	"jne 1b\n\t"
+	"2:"
+	"incl %0"
+	: "=c" (count)
+	:"S" (src),"D" (dest),"0" (count) : "memory");
+
+	return count;
+}
+
 #define __HAVE_ARCH_STRCAT
 static inline char * strcat(char * dest,const char * src)
 {
include/asm-i386/uaccess.h renamed from include/asm-i386/uaccess.h.4gb +130 -15

215 lines not on this page · raw message

include/asm-i386/highmem.h renamed from include/asm-i386/highmem.h.4gb +1 -1
@@ -46,7 +46,7 @@ extern void kmap_init(void) __init;
  * easily, subsequent pte tables have to be allocated in one physical
  * chunk of RAM.
  */
-#define PKMAP_BASE (0xff800000UL)
+#define PKMAP_BASE (0xff400000UL)
 #ifdef CONFIG_X86_PAE
 #define LAST_PKMAP 512
 #else
arch/i386/mm/extable.c renamed from arch/i386/mm/extable.c.4gb +32 -4
@@ -17,13 +17,11 @@ search_one_table(const struct exception_
 {
         while (first <= last) {
 		const struct exception_table_entry *mid;
-		long diff;
 
 		mid = (last - first) / 2 + first;
-		diff = mid->insn - value;
-                if (diff == 0)
+		if (mid->insn == value)
                         return mid->fixup;
-                else if (diff < 0)
+		else if (mid->insn < value)
                         first = mid+1;
                 else
                         last = mid-1;
@@ -60,3 +58,33 @@ search_exception_table(unsigned long add
 	return ret;
 #endif
 }
+
+#ifdef CONFIG_4GB
+void __init extable_init(void)
+{
+	struct exception_table_entry *first =
+		(struct exception_table_entry *)__start___ex_table;
+	struct exception_table_entry *last =
+		(struct exception_table_entry *)__stop___ex_table - 1;
+	struct exception_table_entry *entry;
+	struct exception_table_entry tmp;
+	int chg = 1;
+
+	printk("Sorting kernel __ex_table entries... ");
+
+	/* simple n^2 sort algo */
+	while(chg) {
+		chg = 0;
+		for (entry = first; entry < last; entry++)
+			if (entry->insn > (entry+1)->insn) {
+				/* swap entries */
+				tmp = *entry;
+				*entry = *(entry+1);
+				*(entry+1) = tmp;
+				chg = 1;
+			}
+	}
+
+	printk("done.\n");
+}
+#endif
arch/i386/mm/fault.c renamed from arch/i386/mm/fault.c.4gb +6 -0
@@ -379,7 +379,13 @@ vmalloc_fault:
 		pmd_t *pmd, *pmd_k;
 		pte_t *pte_k;
 
+#ifdef CONFIG_4GB
+		if (!current->mm)
+			goto no_context;
+		pgd = (pgd_t *)__pa(current->mm->pgd);
+#else
 		asm("movl %%cr3,%0":"=r" (pgd));
+#endif
 		pgd = offset + (pgd_t *)__va(pgd);
 		pgd_k = init_mm.pgd + offset;
 
arch/i386/mm/init.c renamed from arch/i386/mm/init.c.4gb +106 -6

183 lines not on this page · raw message

arch/i386/lib/checksum.S renamed from arch/i386/lib/checksum.S.4gb +2 -0
@@ -251,6 +251,7 @@ csum_partial:
 				
 #endif
 
+#ifndef CONFIG_4GB
 /*
 unsigned int csum_partial_copy_generic (const char *src, char *dst,
 				  int len, int sum, int *src_err_ptr, int *dst_err_ptr)
@@ -494,3 +495,4 @@ DST(	movb %dl, (%edi)         )
 #undef ROUND1		
 		
 #endif
+#endif /* !CONFIG_4GB */
arch/i386/lib/getuser.S renamed from arch/i386/lib/getuser.S.4gb +6 -0
@@ -9,6 +9,10 @@
  * return value.
  */
 
+#include <linux/config.h>
+
+#ifndef CONFIG_4GB
+
 /*
  * __get_user_X
  *
@@ -71,3 +75,5 @@ bad_get_user:
 	.long 2b,bad_get_user
 	.long 3b,bad_get_user
 .previous
+
+#endif /* !CONFIG_4GB */
arch/i386/lib/old-checksum.c renamed from arch/i386/lib/old-checksum.c.4gb +36 -0
@@ -2,6 +2,7 @@
  * FIXME: old compatibility stuff, will be removed soon.
  */
 
+#include <linux/config.h>
 #include <net/checksum.h>
 
 unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum)
@@ -16,4 +17,39 @@ unsigned int csum_partial_copy( const ch
 	return sum;
 }
 
+#ifdef CONFIG_4GB
+unsigned int
+csum_partial_copy_generic( const char *src, char *dst, int len, int sum,
+	int *src_err_ptr, int *dst_err_ptr)
+{
+	if ((!src_err_ptr) && (!dst_err_ptr)) {
+		/* csum_partial_copy_nocheck case */
+		sum = csum_partial(src, len, sum);
+		memcpy(dst, src, len);
+		return sum;
+	} else if ((src_err_ptr) && (!dst_err_ptr)) {
+		/* csum_partial_copy_from_user */
+		/* copied from mips code */
+		int missing = copy_from_user(dst, src, len);
+		if (missing) {
+			memset(dst + len - missing, 0, missing);
+			*src_err_ptr = -EFAULT;
+		}
+		return csum_partial(dst, len, sum);
+	} else if ((!src_err_ptr) && (dst_err_ptr)) {
+		/* csum_and_copy_to_user */
+		/* csum_partial_copy_to_user */
+		/* copied from mips code */
+		sum = csum_partial(src, len, sum);
+		if (copy_to_user(dst, src, len))
+			*dst_err_ptr = -EFAULT;
+		return sum;
+	} else {
+		/* csum_partial_copy case */
+		sum = csum_partial(src, len, sum);
+		memcpy(dst, src, len);
+		return sum;
+	}
+}
+#endif /* CONFIG_4GB */
 
arch/i386/lib/usercopy.c renamed from arch/i386/lib/usercopy.c.4gb +237 -5

283 lines not on this page · raw message

arch/i386/kernel/entry.S renamed from arch/i386/kernel/entry.S.4gb +260 -6

351 lines not on this page · raw message

arch/i386/kernel/head.S renamed from arch/i386/kernel/head.S.4gb +7 -0
@@ -323,6 +323,7 @@ ENTRY(stack_start)
 	.long SYMBOL_NAME(init_task_union)+8192
 	.long __KERNEL_DS
 
+#ifndef CONFIG_4GB
 /* This is the default interrupt "handler" :-) */
 int_msg:
 	.asciz "Unknown interrupt\n"
@@ -346,6 +347,7 @@ ignore_int:
 	popl %ecx
 	popl %eax
 	iret
+#endif
 
 /*
  * The interrupt descriptor table has room for 256 idt's,
@@ -421,6 +423,11 @@ ENTRY(_stext)
  */
 .data
 
+#ifdef CONFIG_4GB
+/* align on page boundary to be sure that gdt will fit to one page */
+.section .data.gdt, "aw"
+#endif
+
 ALIGN
 /*
  * This contains typically 140 quadwords, depending on NR_CPUS.
arch/i386/kernel/i386_ksyms.c renamed from arch/i386/kernel/i386_ksyms.c.4gb +13 -5
@@ -92,21 +92,29 @@ EXPORT_SYMBOL(__udelay);
 EXPORT_SYMBOL(__delay);
 EXPORT_SYMBOL(__const_udelay);
 
+#ifndef CONFIG_4GB
 EXPORT_SYMBOL_NOVERS(__get_user_1);
 EXPORT_SYMBOL_NOVERS(__get_user_2);
 EXPORT_SYMBOL_NOVERS(__get_user_4);
+#endif
 
 EXPORT_SYMBOL(strtok);
 EXPORT_SYMBOL(strpbrk);
 EXPORT_SYMBOL(strstr);
 
-EXPORT_SYMBOL(strncpy_from_user);
-EXPORT_SYMBOL(__strncpy_from_user);
-EXPORT_SYMBOL(clear_user);
-EXPORT_SYMBOL(__clear_user);
+EXPORT_SYMBOL(direct_strncpy_from_user);
+EXPORT_SYMBOL(__direct_strncpy_from_user);
+EXPORT_SYMBOL(direct_clear_user);
+EXPORT_SYMBOL(__direct_clear_user);
 EXPORT_SYMBOL(__generic_copy_from_user);
 EXPORT_SYMBOL(__generic_copy_to_user);
-EXPORT_SYMBOL(strnlen_user);
+EXPORT_SYMBOL(direct_strnlen_user);
+
+EXPORT_SYMBOL(indirect_get_user_size);
+EXPORT_SYMBOL(indirect_put_user_size);
+EXPORT_SYMBOL(indirect_clear_user_size);
+EXPORT_SYMBOL(indirect_strncpy_from_user_size);
+EXPORT_SYMBOL(indirect_strnlen_user_size);
 
 EXPORT_SYMBOL(pci_alloc_consistent);
 EXPORT_SYMBOL(pci_free_consistent);
arch/i386/kernel/i387.c renamed from arch/i386/kernel/i387.c.4gb +20 -6
@@ -251,6 +251,7 @@ void set_fpu_mxcsr( struct task_struct *
 static inline int convert_fxsr_to_user( struct _fpstate *buf,
 					struct i387_fxsave_struct *fxsave )
 {
+	struct _fpreg tmp[8];		/* temporary storage */
 	unsigned long env[7];
 	struct _fpreg *to;
 	struct _fpxreg *from;
@@ -267,18 +268,25 @@ static inline int convert_fxsr_to_user( 
 	if ( __copy_to_user( buf, env, 7 * sizeof(unsigned long) ) )
 		return 1;
 
-	to = &buf->_st[0];
+	to = tmp;
 	from = (struct _fpxreg *) &fxsave->st_space[0];
 	for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
-		if ( __copy_to_user( to, from, sizeof(*to) ) )
-			return 1;
+		unsigned long *t = (unsigned long *)to;
+		unsigned long *f = (unsigned long *)from;
+
+		*t = *f;
+		*(t+1) = *(f+1);
+		to->exponent = from->exponent;
 	}
+	if (copy_to_user(buf->_st, tmp, sizeof(tmp)))
+		return 1;
 	return 0;
 }
 
 static inline int convert_fxsr_from_user( struct i387_fxsave_struct *fxsave,
 					  struct _fpstate *buf )
 {
+	struct _fpreg tmp[8];		/* temporary storage */
 	unsigned long env[7];
 	struct _fpxreg *to;
 	struct _fpreg *from;
@@ -286,6 +294,8 @@ static inline int convert_fxsr_from_user
 
 	if ( __copy_from_user( env, buf, 7 * sizeof(long) ) )
 		return 1;
+	if (copy_from_user(tmp, buf->_st, sizeof(struct _fpreg [8])))
+		return 1;
 
 	fxsave->cwd = (unsigned short)(env[0] & 0xffff);
 	fxsave->swd = (unsigned short)(env[1] & 0xffff);
@@ -297,10 +307,14 @@ static inline int convert_fxsr_from_user
 	fxsave->fos = env[6];
 
 	to = (struct _fpxreg *) &fxsave->st_space[0];
-	from = &buf->_st[0];
+	from = tmp;
 	for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
-		if ( __copy_from_user( to, from, sizeof(*from) ) )
-			return 1;
+		unsigned long *t = (unsigned long *)to;
+		unsigned long *f = (unsigned long *)from;
+
+		*t = *f;
+		*(t+1) = *(f+1);
+		to->exponent = from->exponent;
 	}
 	return 0;
 }
arch/i386/kernel/i8259.c renamed from arch/i386/kernel/i8259.c.4gb +1 -0
@@ -22,6 +22,7 @@
 #include <asm/delay.h>
 #include <asm/desc.h>
 #include <asm/apic.h>
+#include <asm/offset.h>
 
 #include <linux/irq.h>
 
arch/i386/kernel/init_task.c renamed from arch/i386/kernel/init_task.c.4gb +7 -1
@@ -29,5 +29,11 @@ union task_union init_task_union 
  * section. Since TSS's are completely CPU-local, we want them
  * on exact cacheline boundaries, to eliminate cacheline ping-pong.
  */ 
-struct tss_struct init_tss[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1] = INIT_TSS };
+struct tss_struct init_tss[NR_CPUS] 
+#ifdef CONFIG_4GB
+	__attribute__((__section__(".data.tss")))
+#else
+	__cacheline_aligned
+#endif
+	= { [0 ... NR_CPUS-1] = INIT_TSS };
 
arch/i386/kernel/ldt.c renamed from arch/i386/kernel/ldt.c.4gb +13 -0
@@ -5,6 +5,7 @@
  * Copyright (C) 1999 Ingo Molnar <[email protected]>
  */
 
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -37,10 +38,14 @@ static int alloc_ldt(mm_context_t *pc, i
 		return 0;
 	oldsize = pc->size;
 	mincount = (mincount+511)&(~511);
+#ifdef CONFIG_4GB
+	newldt = vmalloc(mincount*LDT_ENTRY_SIZE);
+#else
 	if (mincount*LDT_ENTRY_SIZE > PAGE_SIZE)
 		newldt = vmalloc(mincount*LDT_ENTRY_SIZE);
 	else
 		newldt = kmalloc(mincount*LDT_ENTRY_SIZE, GFP_KERNEL);
+#endif
 
 	if (!newldt)
 		return -ENOMEM;
@@ -62,10 +67,14 @@ static int alloc_ldt(mm_context_t *pc, i
 	}
 	wmb();
 	if (oldsize) {
+#ifdef CONFIG_4GB
+		vfree(oldldt);
+#else
 		if (oldsize*LDT_ENTRY_SIZE > PAGE_SIZE)
 			vfree(oldldt);
 		else
 			kfree(oldldt);
+#endif
 	}
 	return 0;
 }
@@ -110,10 +119,14 @@ int init_new_context(struct task_struct 
 void destroy_context(struct mm_struct *mm)
 {
 	if (mm->context.size) {
+#ifdef CONFIG_4GB
+		vfree(mm->context.ldt);
+#else
 		if (mm->context.size*LDT_ENTRY_SIZE > PAGE_SIZE)
 			vfree(mm->context.ldt);
 		else
 			kfree(mm->context.ldt);
+#endif
 		mm->context.size = 0;
 	}
 }
arch/i386/kernel/process.c renamed from arch/i386/kernel/process.c.4gb +78 -0

117 lines not on this page · raw message

arch/i386/kernel/ptrace.c renamed from arch/i386/kernel/ptrace.c.4gb +12 -0
@@ -48,7 +48,13 @@ static inline int get_stack_long(struct 
 {
 	unsigned char *stack;
 
+#ifdef CONFIG_4GB
+	/* esp0 points to U-space mapped stack, stack=addr in K-space */
+	stack = (unsigned char *)task +
+		(task->thread.esp0 - task->thread.utask);
+#else
 	stack = (unsigned char *)task->thread.esp0;
+#endif
 	stack += offset;
 	return (*((int *)stack));
 }
@@ -64,7 +70,13 @@ static inline int put_stack_long(struct 
 {
 	unsigned char * stack;
 
+#ifdef CONFIG_4GB
+	/* esp0 points to U-space mapped stack, stack=addr in K-space */
+	stack = (unsigned char *)task +
+		(task->thread.esp0 - task->thread.utask);
+#else
 	stack = (unsigned char *) task->thread.esp0;
+#endif
 	stack += offset;
 	*(unsigned long *) stack = data;
 	return 0;
arch/i386/kernel/signal.c renamed from arch/i386/kernel/signal.c.4gb +45 -47

143 lines not on this page · raw message

arch/i386/kernel/smpboot.c renamed from arch/i386/kernel/smpboot.c.4gb +1 -0
@@ -46,6 +46,7 @@
 #include <asm/mtrr.h>
 #include <asm/pgalloc.h>
 #include <asm/smpboot.h>
+#include <asm/desc.h>
 
 /* Set if we find a B stepping CPU			*/
 static int smp_b_stepping;
arch/i386/kernel/smp.c renamed from arch/i386/kernel/smp.c.4gb +2 -0
@@ -309,7 +309,9 @@ static void inline leave_mm (unsigned lo
 {
 	BUG_ON(cpu_tlbstate[cpu].state == TLBSTATE_OK);
 	clear_bit(cpu, &cpu_tlbstate[cpu].active_mm->cpu_vm_mask);
+#ifndef CONFIG_4GB
 	load_cr3(swapper_pg_dir);
+#endif
 }
 
 /*
arch/i386/kernel/traps.c renamed from arch/i386/kernel/traps.c.4gb +67 -8

154 lines not on this page · raw message

arch/i386/kernel/vm86.c renamed from arch/i386/kernel/vm86.c.4gb +6 -0
@@ -30,6 +30,7 @@
  *   
  */
 
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -278,7 +279,12 @@ static void do_sys_vm86(struct kernel_vm
 	info->regs32->eax = 0;
 	tsk->thread.saved_esp0 = tsk->thread.esp0;
 	tss = init_tss + smp_processor_id();
+#ifdef CONFIG_4GB
+	tss->esp0 = tsk->thread.esp0 = tsk->thread.utask +
+		((unsigned long)&info->VM86_TSS_ESP0 & (THREAD_SIZE-1));
+#else /* CONFIG_4GB */
 	tss->esp0 = tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0;
+#endif /* CONFIG_4GB */
 
 	tsk->thread.screen_bitmap = info->screen_bitmap;
 	if (info->flags & VM86_SCREEN_BITMAP)
arch/i386/config.in renamed from arch/i386/config.in.4gb +6 -0
@@ -205,6 +205,12 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; the
    tristate 'BIOS Enhanced Disk Drive calls determine boot disk (EXPERIMENTAL)' CONFIG_EDD
 fi
 
+choice 'Kernel space size (user/kernel virtual space split)' \
+	"1GB    CONFIG_1GB \
+	 2GB    CONFIG_2GB \
+	 3GB    CONFIG_3GB \
+	 4GB    CONFIG_4GB" 1GB
+
 choice 'High Memory Support' \
 	"off    CONFIG_NOHIGHMEM \
 	 4GB    CONFIG_HIGHMEM4G \
arch/i386/Makefile renamed from arch/i386/Makefile.4gb +10 -0
@@ -106,6 +106,8 @@ SUBDIRS += arch/i386/math-emu
 DRIVERS += arch/i386/math-emu/math.o
 endif
 
+SUBDIRS := $(addprefix arch/i386/, tools) $(SUBDIRS)
+
 arch/i386/kernel: dummy
 	$(MAKE) linuxsubdirs SUBDIRS=arch/i386/kernel
 
@@ -113,9 +115,14 @@ arch/i386/mm: dummy
 	$(MAKE) linuxsubdirs SUBDIRS=arch/i386/mm
 
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+MAKETOOLS = $(MAKE) -C arch/$(ARCH)/tools
 
 vmlinux: arch/i386/vmlinux.lds
 
+arch/i386/vmlinux.lds: arch/i386/vmlinux.lds.S FORCE
+	$(CPP) -C -P -I$(HPATH) \
+		-Ui386 arch/i386/vmlinux.lds.S >arch/i386/vmlinux.lds
+
 FORCE: ;
 
 .PHONY: zImage bzImage compressed zlilo bzlilo zdisk bzdisk install \
@@ -148,8 +155,11 @@ install: vmlinux
 
 archclean:
 	@$(MAKEBOOT) clean
+	@$(MAKETOOLS) clean
 
 archmrproper:
+	rm -f arch/i386/vmlinux.lds
+	@$(MAKETOOLS) mrproper
 
 archdep:
 	@$(MAKEBOOT) dep
arch/i386/tools/Makefile new file +25 -0
@@ -0,0 +1,25 @@
+# Makefile for i386 kernel build tools.
+#
+TARGET	:= $(TOPDIR)/include/asm-$(ARCH)/offset.h
+
+USE_STANDARD_AS_RULE := true
+
+$(TARGET): offset.h
+	cmp -s $^ $@ || (cp $^ $(TARGET).new && mv $(TARGET).new $(TARGET))
+
+offset.h: offset.o
+	sed -n 's/^@@@//p' $^ | sed 's/\(.*\)\(---\$$\)\(.*\)/\1\3/g' >$@
+
+# it's .s file actually. We use .o extension for using correct .depend rule
+offset.o: offset.c $(TOPDIR)/include/linux/autoconf.h FORCE
+	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -S $< -o $@
+
+clean:
+	rm -f offset.[hs] $(TARGET).new
+
+mrproper: clean
+	rm -f $(TARGET)
+
+FORCE: ;
+
+include $(TOPDIR)/Rules.make
arch/i386/tools/offset.c new file +89 -0

89 lines not on this page · raw message

arch/i386/vmlinux.lds renamed from arch/i386/vmlinux.lds.4gb +0 -82

82 lines not on this page · raw message

arch/i386/vmlinux.lds.S new file +102 -0

102 lines not on this page · raw message