public inbox for linux-ia64@vger.kernel.org
 help / color / mirror / Atom feed
* [Linux-ia64] IA-32 LDT support patch
@ 2001-04-17  0:29 David Mosberger
  2001-04-18  7:57 ` Josue Amaro
  0 siblings, 1 reply; 2+ messages in thread
From: David Mosberger @ 2001-04-17  0:29 UTC (permalink / raw)
  To: linux-ia64

Below is a patch that goes on top of the IA-64 Linux version of
v2.4.3.  It adds support for the IA-32 modify_ldt() system call which
is needed to run certain x86 programs (such as programs linked against
recent versions of x86 pthreads).

Thanks to Don Dugger and Asit Mallick for reviewing the patch (all
bugs are mine, of course...).  I really know almost nothing about x86
and I'm trying hard to keep it that way ;-), but the patch should work
OK.  At least "netscape" still works and a simple test program linked
against a version of pthreads that uses modify_ldt() also seems to
work fine.

Enjoy,

	--david

diff -urN lia64/arch/ia64/ia32/Makefile lia64-kdb/arch/ia64/ia32/Makefile
--- lia64/arch/ia64/ia32/Makefile	Wed Jan  3 23:06:42 2001
+++ lia64-kdb/arch/ia64/ia32/Makefile	Fri Apr 13 14:21:30 2001
@@ -11,7 +11,8 @@
 
 O_TARGET := ia32.o
 
-obj-y := ia32_entry.o sys_ia32.o ia32_ioctl.o ia32_signal.o ia32_support.o ia32_traps.o binfmt_elf32.o
+obj-y := ia32_entry.o sys_ia32.o ia32_ioctl.o ia32_signal.o ia32_support.o ia32_traps.o \
+	 binfmt_elf32.o ia32_ldt.o
 
 clean::
 
diff -urN lia64/arch/ia64/ia32/binfmt_elf32.c lia64-kdb/arch/ia64/ia32/binfmt_elf32.c
--- lia64/arch/ia64/ia32/binfmt_elf32.c	Thu Apr  5 09:51:03 2001
+++ lia64-kdb/arch/ia64/ia32/binfmt_elf32.c	Fri Apr 13 19:34:37 2001
@@ -2,8 +2,11 @@
  * IA-32 ELF support.
  *
  * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com>
+ * Copyright (C) 2001 Hewlett-Packard Co
+ * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com>
  *
  * 06/16/00	A. Mallick	initialize csd/ssd/tssd/cflg for ia32_load_state
+ * 04/13/01	D. Mosberger	dropped saving tssd in ar.k1---it's not needed
  */
 #include <linux/config.h>
 
@@ -35,8 +38,8 @@
 #undef CLOCKS_PER_SEC
 #define CLOCKS_PER_SEC	IA32_CLOCKS_PER_SEC
 
-extern void ia64_elf32_init(struct pt_regs *regs);
-extern void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address);
+extern void ia64_elf32_init (struct pt_regs *regs);
+extern void put_dirty_page (struct task_struct * tsk, struct page *page, unsigned long address);
 
 #define ELF_PLAT_INIT(_r)		ia64_elf32_init(_r)
 #define setup_arg_pages(bprm)		ia32_setup_arg_pages(bprm)
@@ -49,7 +52,7 @@
 unsigned long *ia32_gdt_table, *ia32_tss;
 
 struct page *
-put_shared_page(struct task_struct * tsk, struct page *page, unsigned long address)
+put_shared_page (struct task_struct * tsk, struct page *page, unsigned long address)
 {
 	pgd_t * pgd;
 	pmd_t * pmd;
@@ -83,85 +86,87 @@
 	return 0;
 }
 
-void ia64_elf32_init(struct pt_regs *regs)
+void
+ia64_elf32_init (struct pt_regs *regs)
 {
+	struct vm_area_struct *vma;
 	int nr;
 
-	put_shared_page(current, virt_to_page(ia32_gdt_table), IA32_PAGE_OFFSET);
+	/*
+	 * Map GDT and TSS below 4GB, where the processor can find them.  We need to map
+	 * it with privilege level 3 because the IVE uses non-privileged accesses to these
+	 * tables.  IA-32 segmentation is used to protect against IA-32 accesses to them.
+	 */
+	put_shared_page(current, virt_to_page(ia32_gdt_table), IA32_GDT_OFFSET);
 	if (PAGE_SHIFT <= IA32_PAGE_SHIFT)
-		put_shared_page(current, virt_to_page(ia32_tss), IA32_PAGE_OFFSET + PAGE_SIZE);
+		put_shared_page(current, virt_to_page(ia32_tss), IA32_TSS_OFFSET);
 
-	nr = smp_processor_id();
+	/*
+	 * Install LDT as anonymous memory.  This gives us all-zero segment descriptors
+	 * until a task modifies them via modify_ldt().
+	 */
+	vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+	if (vma) {
+		vma->vm_mm = current->mm;
+		vma->vm_start = IA32_LDT_OFFSET;
+		vma->vm_end = vma->vm_start + PAGE_ALIGN(IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE);
+		vma->vm_page_prot = PAGE_SHARED;
+		vma->vm_flags = VM_READ|VM_WRITE|VM_MAYREAD|VM_MAYWRITE;
+		vma->vm_ops = NULL;
+		vma->vm_pgoff = 0;
+		vma->vm_file = NULL;
+		vma->vm_private_data = NULL;
+		insert_vm_struct(current->mm, vma);
+	}
 
-	/* Do all the IA-32 setup here */
+	nr = smp_processor_id();
 
-	current->thread.map_base  = 0x40000000;
-	current->thread.task_size = 0xc0000000;		/* use what Linux/x86 uses... */
+	current->thread.map_base  = IA32_PAGE_OFFSET/3;
+	current->thread.task_size = IA32_PAGE_OFFSET;	/* use what Linux/x86 uses... */
 	set_fs(USER_DS);				/* set addr limit for new TASK_SIZE */
 
-	/* setup ia32 state for ia32_load_state */
+	/* Setup the segment selectors */
+	regs->r16 = (__USER_DS << 16) | __USER_DS; /* ES = DS, GS, FS are zero */
+	regs->r17 = (__USER_DS << 16) | __USER_CS; /* SS, CS; ia32_load_state() sets TSS and LDT */
+
+	/* Setup the segment descriptors */
+	regs->r24 = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_DS >> 3]);	/* ESD */
+	regs->r27 = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_DS >> 3]);	/* DSD */
+	regs->r28 = 0;								/* FSD (null) */
+	regs->r29 = 0;								/* GSD (null) */
+	regs->r30 = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[_LDT(nr)]);		/* LDTD */
 
-	current->thread.eflag = IA32_EFLAG;
-	current->thread.csd = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0xBL, 1L, 3L, 1L, 1L, 1L);
-	current->thread.ssd = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, 3L, 1L, 1L, 1L);
-	current->thread.tssd = IA64_SEG_DESCRIPTOR(IA32_PAGE_OFFSET + PAGE_SIZE, 0x1FFFL, 0xBL,
-						   1L, 3L, 1L, 1L, 1L);
-
-	/* CS descriptor */
-	__asm__("mov ar.csd = %0" : /* no outputs */
-		: "r" IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0xBL, 1L,
-					  3L, 1L, 1L, 1L));
-	/* SS descriptor */
-	__asm__("mov ar.ssd = %0" : /* no outputs */
-		: "r" IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L,
-					  3L, 1L, 1L, 1L));
-	/* EFLAGS */
-	__asm__("mov ar.eflag = %0" : /* no outputs */ : "r" (IA32_EFLAG));
-
-	/* Control registers */
-	__asm__("mov ar.fsr = %0"
-		: /* no outputs */
-		: "r" ((ulong)IA32_FSR_DEFAULT));
-	__asm__("mov ar.fcr = %0"
-		: /* no outputs */
-		: "r" ((ulong)IA32_FCR_DEFAULT));
-	__asm__("mov ar.fir = r0");
-	__asm__("mov ar.fdr = r0");
-	current->thread.old_iob = ia64_get_kr(IA64_KR_IO_BASE);
-	ia64_set_kr(IA64_KR_IO_BASE, IA32_IOBASE);
-
-	/* Get the segment selectors right */
-	regs->r16 = (__USER_DS << 16) |  (__USER_DS); /* ES = DS, GS, FS are zero */
-	regs->r17 = (_TSS(nr) << 48) | (_LDT(nr) << 32)
-		    | (__USER_DS << 16) | __USER_CS;
-
-	/* Setup other segment descriptors - ESD, DSD, FSD, GSD */
-	regs->r24 = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, 3L, 1L, 1L, 1L);
-	regs->r27 = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, 3L, 1L, 1L, 1L);
-	regs->r28 = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, 3L, 1L, 1L, 1L);
-	regs->r29 = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, 3L, 1L, 1L, 1L);
-
-	/* Setup the LDT and GDT */
-	regs->r30 = ia32_gdt_table[_LDT(nr)];
-	regs->r31 = IA64_SEG_DESCRIPTOR(0xc0000000L, 0x400L, 0x3L, 1L, 3L,
-					1L, 1L, 1L);
-
-	/* Clear psr.ac */
-	regs->cr_ipsr &= ~IA64_PSR_AC;
+	/*
+	 * Setup GDTD.  Note: GDTD is the descrambled version of the pseudo-descriptor
+	 * format defined by Figure 3-11 "Pseudo-Descriptor Format" in the IA-32
+	 * architecture manual.
+	 */
+	regs->r31 = IA32_SEG_UNSCRAMBLE(IA32_SEG_DESCRIPTOR(IA32_GDT_OFFSET, IA32_PAGE_SIZE - 1, 0,
+							    0, 0, 0, 0, 0, 0));
 
+	ia64_psr(regs)->ac = 0;		/* turn off alignment checking */
 	regs->loadrs = 0;
-}
 
-#undef STACK_TOP
-#define STACK_TOP ((IA32_PAGE_OFFSET/3) * 2)
+	current->thread.eflag = IA32_EFLAG;
+	current->thread.fsr = IA32_FSR_DEFAULT;
+	current->thread.fcr = IA32_FCR_DEFAULT;
+	current->thread.fir = 0;
+	current->thread.fdr = 0;
+	current->thread.csd = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_CS >> 3]);
+	current->thread.ssd = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_DS >> 3]);
+	current->thread.tssd = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[_TSS(nr)]);
+
+	ia32_load_state(current);
+}
 
-int ia32_setup_arg_pages(struct linux_binprm *bprm)
+int
+ia32_setup_arg_pages (struct linux_binprm *bprm)
 {
 	unsigned long stack_base;
 	struct vm_area_struct *mpnt;
 	int i;
 
-	stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
+	stack_base = IA32_STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
 
 	bprm->p += stack_base;
 	if (bprm->loader)
@@ -175,7 +180,7 @@
 	{
 		mpnt->vm_mm = current->mm;
 		mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
-		mpnt->vm_end = STACK_TOP;
+		mpnt->vm_end = IA32_STACK_TOP;
 		mpnt->vm_page_prot = PAGE_COPY;
 		mpnt->vm_flags = VM_STACK_FLAGS;
 		mpnt->vm_ops = NULL;
@@ -197,15 +202,15 @@
 }
 
 static unsigned long
-ia32_mm_addr(unsigned long addr)
+ia32_mm_addr (unsigned long addr)
 {
 	struct vm_area_struct *vma;
 
 	if ((vma = find_vma(current->mm, addr)) = NULL)
-		return(ELF_PAGESTART(addr));
+		return ELF_PAGESTART(addr);
 	if (vma->vm_start > addr)
-		return(ELF_PAGESTART(addr));
-	return(ELF_PAGEALIGN(addr));
+		return ELF_PAGESTART(addr);
+	return ELF_PAGEALIGN(addr);
 }
 
 /*
@@ -232,22 +237,9 @@
 	 */
 	if (addr = 0)
 		addr += PAGE_SIZE;
-#if 1
 	set_brk(ia32_mm_addr(addr), addr + eppnt->p_memsz);
 	memset((char *) addr + eppnt->p_filesz, 0, eppnt->p_memsz - eppnt->p_filesz);
 	kernel_read(filep, eppnt->p_offset, (char *) addr, eppnt->p_filesz);
 	retval = (unsigned long) addr;
-#else
-	/* doesn't work yet... */
-#	define IA32_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_EXEC_PAGESIZE-1))
-#	define IA32_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1))
-#	define IA32_PAGEALIGN(_v) (((_v) + ELF_EXEC_PAGESIZE - 1) & ~(ELF_EXEC_PAGESIZE - 1))
-
-	down_write(&current->mm->mmap_sem);
-	retval = ia32_do_mmap(filep, IA32_PAGESTART(addr),
-			      eppnt->p_filesz + IA32_PAGEOFFSET(eppnt->p_vaddr), prot, type,
-			      eppnt->p_offset - IA32_PAGEOFFSET(eppnt->p_vaddr));
-	up_write(&current->mm->mmap_sem);
-#endif
 	return retval;
 }
diff -urN lia64/arch/ia64/ia32/ia32_entry.S lia64-kdb/arch/ia64/ia32/ia32_entry.S
--- lia64/arch/ia64/ia32/ia32_entry.S	Wed Mar 28 21:42:44 2001
+++ lia64-kdb/arch/ia64/ia32/ia32_entry.S	Fri Apr 13 14:36:18 2001
@@ -233,7 +233,7 @@
 	data8 sys32_ni_syscall
 	data8 sys_iopl		  /* 110 */
 	data8 sys_vhangup
-	data8 sys32_ni_syscall		// used to be sys_idle
+	data8 sys32_ni_syscall		/* used to be sys_idle */
 	data8 sys32_ni_syscall
 	data8 sys32_wait4
 	data8 sys_swapoff	  /* 115 */
@@ -244,7 +244,7 @@
 	data8 sys_clone		  /* 120 */
 	data8 sys_setdomainname
 	data8 sys32_newuname
-	data8 sys_modify_ldt
+	data8 sys32_modify_ldt
 	data8 sys_adjtimex
 	data8 sys32_mprotect	  /* 125 */
 	data8 sys_sigprocmask
diff -urN lia64/arch/ia64/ia32/ia32_ldt.c lia64-kdb/arch/ia64/ia32/ia32_ldt.c
--- lia64/arch/ia64/ia32/ia32_ldt.c	Wed Dec 31 16:00:00 1969
+++ lia64-kdb/arch/ia64/ia32/ia32_ldt.c	Fri Apr 13 20:23:48 2001
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2001 Hewlett-Packard Co
+ * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ * Adapted from arch/i386/kernel/ldt.c
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/vmalloc.h>
+
+#include <asm/uaccess.h>
+#include <asm/ia32.h>
+
+/*
+ * read_ldt() is not really atomic - this is not a problem since synchronization of reads
+ * and writes done to the LDT has to be assured by user-space anyway. Writes are atomic,
+ * to protect the security checks done on new descriptors.
+ */
+static int
+read_ldt (void *ptr, unsigned long bytecount)
+{
+	char *src, *dst, buf[256];	/* temporary buffer (don't overflow kernel stack!) */
+	unsigned long bytes_left, n;
+
+	if (bytecount > IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE)
+		bytecount = IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE;
+
+	bytes_left = bytecount;
+
+	src = (void *) IA32_LDT_OFFSET;
+	dst = ptr;
+
+	while (bytes_left) {
+		n = sizeof(buf);
+		if (n > bytes_left)
+			n = bytes_left;
+
+		/*
+		 * We know we're reading valid memory, but we still must guard against
+		 * running out of memory.
+		 */
+		if (__copy_from_user(buf, src, n))
+			return -EFAULT;
+
+		if (copy_to_user(dst, buf, n))
+			return -EFAULT;
+
+		src += n;
+		dst += n;
+		bytes_left -= n;
+	}
+	return bytecount;
+}
+
+static int
+write_ldt (void * ptr, unsigned long bytecount, int oldmode)
+{
+	struct ia32_modify_ldt_ldt_s ldt_info;
+	__u64 entry;
+
+	if (bytecount != sizeof(ldt_info))
+		return -EINVAL;
+	if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info)))
+		return -EFAULT;
+
+	if (ldt_info.entry_number >= IA32_LDT_ENTRIES)
+		return -EINVAL;
+	if (ldt_info.contents = 3) {
+		if (oldmode)
+			return -EINVAL;
+		if (ldt_info.seg_not_present = 0)
+			return -EINVAL;
+	}
+
+	if (ldt_info.base_addr = 0 && ldt_info.limit = 0
+	    && (oldmode || (ldt_info.contents = 0 && ldt_info.read_exec_only = 1
+			    && ldt_info.seg_32bit = 0 && ldt_info.limit_in_pages = 0
+			    && ldt_info.seg_not_present = 1 && ldt_info.useable = 0)))
+		/* allow LDTs to be cleared by the user */
+		entry = 0;
+	else
+		/* we must set the "Accessed" bit as IVE doesn't emulate it */
+		entry = IA32_SEG_DESCRIPTOR(ldt_info.base_addr, ldt_info.limit,
+					    (((ldt_info.read_exec_only ^ 1) << 1)
+					     | (ldt_info.contents << 2)) | 1,
+					    1, 3, ldt_info.seg_not_present ^ 1,
+					    (oldmode ? 0 : ldt_info.useable),
+					    ldt_info.seg_32bit,
+					    ldt_info.limit_in_pages);
+	/*
+	 * Install the new entry.  We know we're accessing valid (mapped) user-level
+	 * memory, but we still need to guard against out-of-memory, hence we must use
+	 * put_user().
+	 */
+	return __put_user(entry, (__u64 *) IA32_LDT_OFFSET + ldt_info.entry_number);
+}
+
+asmlinkage int
+sys32_modify_ldt (int func, void *ptr, unsigned int bytecount)
+{
+	int ret = -ENOSYS;
+
+	switch (func) {
+	      case 0:
+		ret = read_ldt(ptr, bytecount);
+		break;
+	      case 1:
+		ret = write_ldt(ptr, bytecount, 1);
+		break;
+	      case 0x11:
+		ret = write_ldt(ptr, bytecount, 0);
+		break;
+	}
+	return ret;
+}
diff -urN lia64/arch/ia64/ia32/ia32_support.c lia64-kdb/arch/ia64/ia32/ia32_support.c
--- lia64/arch/ia64/ia32/ia32_support.c	Wed Feb 21 16:05:28 2001
+++ lia64-kdb/arch/ia64/ia32/ia32_support.c	Fri Apr 13 20:20:49 2001
@@ -1,6 +1,11 @@
 /*
  * IA32 helper functions
  *
+ * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com>
+ * Copyright (C) 2000 Asit K. Mallick <asit.k.mallick@intel.com>
+ * Copyright (C) 2001 Hewlett-Packard Co
+ * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ *
  * 06/16/00	A. Mallick	added csd/ssd/tssd for ia32 thread context
  * 02/19/01	D. Mosberger	dropped tssd; it's not needed
  */
@@ -21,7 +26,7 @@
 extern void die_if_kernel (char *str, struct pt_regs *regs, long err);
 
 void
-ia32_save_state (struct thread_struct *thread)
+ia32_save_state (struct task_struct *t)
 {
 	unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd;
 
@@ -33,28 +38,30 @@
 	     "mov %5=ar.csd;"
 	     "mov %6=ar.ssd;"
 	     : "=r"(eflag), "=r"(fsr), "=r"(fcr), "=r"(fir), "=r"(fdr), "=r"(csd), "=r"(ssd));
-	thread->eflag = eflag;
-	thread->fsr = fsr;
-	thread->fcr = fcr;
-	thread->fir = fir;
-	thread->fdr = fdr;
-	thread->csd = csd;
-	thread->ssd = ssd;
-	asm ("mov ar.k0=%0 ;;" :: "r"(thread->old_iob));
+	t->thread.eflag = eflag;
+	t->thread.fsr = fsr;
+	t->thread.fcr = fcr;
+	t->thread.fir = fir;
+	t->thread.fdr = fdr;
+	t->thread.csd = csd;
+	t->thread.ssd = ssd;
+	ia64_set_kr(IA64_KR_IO_BASE, t->thread.old_iob);
 }
 
 void
-ia32_load_state (struct thread_struct *thread)
+ia32_load_state (struct task_struct *t)
 {
 	unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd;
+	struct pt_regs *regs = ia64_task_regs(t);
+	int nr;
 
-	eflag = thread->eflag;
-	fsr = thread->fsr;
-	fcr = thread->fcr;
-	fir = thread->fir;
-	fdr = thread->fdr;
-	csd = thread->csd;
-	ssd = thread->ssd;
+	eflag = t->thread.eflag;
+	fsr = t->thread.fsr;
+	fcr = t->thread.fcr;
+	fir = t->thread.fir;
+	fdr = t->thread.fdr;
+	csd = t->thread.csd;
+	ssd = t->thread.ssd;
 
 	asm volatile ("mov ar.eflag=%0;"
 		      "mov ar.fsr=%1;"
@@ -64,17 +71,22 @@
 		      "mov ar.csd=%5;"
 		      "mov ar.ssd=%6;"
 		      :: "r"(eflag), "r"(fsr), "r"(fcr), "r"(fir), "r"(fdr), "r"(csd), "r"(ssd));
-	asm ("mov %0=ar.k0 ;;" : "=r"(thread->old_iob));
-	asm ("mov ar.k0=%0 ;;" :: "r"(IA32_IOBASE));
+	current->thread.old_iob = ia64_get_kr(IA64_KR_IO_BASE);
+	ia64_set_kr(IA64_KR_IO_BASE, IA32_IOBASE);
+
+	/* load TSS and LDT while preserving SS and CS: */
+	nr = smp_processor_id();
+	regs->r17 = (_TSS(nr) << 48) | (_LDT(nr) << 32) | (__u32) regs->r17;
 }
 
 /*
- * Setup IA32 GDT and TSS 
+ * Setup IA32 GDT and TSS
  */
 void
-ia32_gdt_init(void)
+ia32_gdt_init (void)
 {
-	unsigned long gdt_and_tss_page;
+	unsigned long gdt_and_tss_page, ldt_size;
+	int nr;
 
 	/* allocate two IA-32 pages of memory: */
 	gdt_and_tss_page = __get_free_pages(GFP_KERNEL,
@@ -86,17 +98,28 @@
 	/* Zero the gdt and tss */
 	memset((void *) gdt_and_tss_page, 0, 2*IA32_PAGE_SIZE);
 
-	/* CS descriptor in IA-32 format */
-	ia32_gdt_table[4] = IA32_SEG_DESCRIPTOR(0L, 0xBFFFFFFFL, 0xBL, 1L,
-						3L, 1L, 1L, 1L, 1L);
-
-	/* DS descriptor in IA-32 format */
-	ia32_gdt_table[5] = IA32_SEG_DESCRIPTOR(0L, 0xBFFFFFFFL, 0x3L, 1L,
-						3L, 1L, 1L, 1L, 1L);
+	/* CS descriptor in IA-32 (scrambled) format */
+	ia32_gdt_table[__USER_CS >> 3] +		IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET - 1) >> IA32_PAGE_SHIFT,
+				    0xb, 1, 3, 1, 1, 1, 1);
+
+	/* DS descriptor in IA-32 (scrambled) format */
+	ia32_gdt_table[__USER_DS >> 3] +		IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET - 1) >> IA32_PAGE_SHIFT,
+				    0x3, 1, 3, 1, 1, 1, 1);
+
+	/* We never change the TSS and LDT descriptors, so we can share them across all CPUs.  */
+	ldt_size = PAGE_ALIGN(IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE);
+	for (nr = 0; nr < NR_CPUS; ++nr) {
+		ia32_gdt_table[_TSS(nr)] = IA32_SEG_DESCRIPTOR(IA32_TSS_OFFSET, 235,
+							       0xb, 0, 3, 1, 1, 1, 0);
+		ia32_gdt_table[_LDT(nr)] = IA32_SEG_DESCRIPTOR(IA32_LDT_OFFSET, ldt_size - 1,
+							       0x2, 0, 3, 1, 1, 1, 0);
+	}
 }
 
 /*
- * Handle bad IA32 interrupt via syscall 
+ * Handle bad IA32 interrupt via syscall
  */
 void
 ia32_bad_interrupt (unsigned long int_num, struct pt_regs *regs)
@@ -106,8 +129,7 @@
 	die_if_kernel("Bad IA-32 interrupt", regs, int_num);
 
 	siginfo.si_signo = SIGTRAP;
-	siginfo.si_errno = int_num;	/* XXX is it legal to abuse si_errno like this? */
+	siginfo.si_errno = int_num;	/* XXX is it OK to abuse si_errno like this? */
 	siginfo.si_code = TRAP_BRKPT;
 	force_sig_info(SIGTRAP, &siginfo, current);
 }
-
diff -urN lia64/arch/ia64/ia32/sys_ia32.c lia64-kdb/arch/ia64/ia32/sys_ia32.c
--- lia64/arch/ia64/ia32/sys_ia32.c	Thu Apr  5 09:51:22 2001
+++ lia64-kdb/arch/ia64/ia32/sys_ia32.c	Fri Apr 13 20:46:41 2001
@@ -334,9 +334,9 @@
 	down_write(&current->mm->mmap_sem);
 	retval = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, a.offset >> PAGE_SHIFT);
 	up_write(&current->mm->mmap_sem);
-#else	// CONFIG_IA64_PAGE_SIZE_4KB
+#else
 	retval = ia32_do_mmap(file, a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
-#endif	// CONFIG_IA64_PAGE_SIZE_4KB
+#endif
 	if (file)
 		fput(file);
 	return retval;
@@ -1886,8 +1886,7 @@
 		break;
 
 	case SHMAT:
-		err = do_sys32_shmat (first, second, third,
-				      version, (void *)AA(ptr));
+		err = do_sys32_shmat (first, second, third, version, (void *)AA(ptr));
 		break;
 	case SHMDT:
 		err = sys_shmdt ((char *)AA(ptr));
@@ -2334,8 +2333,8 @@
  *    the address of `stack' will not be the address of the `pt_regs'.
  */
 asmlinkage long
-sys32_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data,
-	    long arg4, long arg5, long arg6, long arg7, long stack)
+sys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data,
+	      long arg4, long arg5, long arg6, long arg7, long stack)
 {
 	struct pt_regs *regs = (struct pt_regs *) &stack;
 	struct task_struct *child;
@@ -2379,7 +2378,7 @@
 	      case PTRACE_PEEKDATA:	/* read word at location addr */
 		ret = ia32_peek(regs, child, addr, &value);
 		if (ret = 0)
-			ret = put_user(value, (unsigned int *)data);
+			ret = put_user(value, (unsigned int *)A(data));
 		else
 			ret = -EIO;
 		goto out;
@@ -2398,12 +2397,12 @@
 		break;
 
 	      case IA32_PTRACE_GETREGS:
-		if (!access_ok(VERIFY_WRITE, (int *)data, 17*sizeof(int))) {
+		if (!access_ok(VERIFY_WRITE, (int *) A(data), 17*sizeof(int))) {
 			ret = -EIO;
 			break;
 		}
 		for ( i = 0; i < 17*sizeof(int); i += sizeof(int) ) {
-			__put_user(getreg(child, i),(unsigned int *) data);
+			__put_user(getreg(child, i), (unsigned int *) A(data));
 			data += sizeof(int);
 		}
 		ret = 0;
@@ -2412,12 +2411,12 @@
 	      case IA32_PTRACE_SETREGS:
 	      {
 		unsigned int tmp;
-		if (!access_ok(VERIFY_READ, (int *)data, 17*sizeof(int))) {
+		if (!access_ok(VERIFY_READ, (int *) A(data), 17*sizeof(int))) {
 			ret = -EIO;
 			break;
 		}
 		for ( i = 0; i < 17*sizeof(int); i += sizeof(int) ) {
-			__get_user(tmp, (unsigned int *) data);
+			__get_user(tmp, (unsigned int *) A(data));
 			putreg(child, i, tmp);
 			data += sizeof(int);
 		}
@@ -2426,11 +2425,11 @@
 	      }
 
 	      case IA32_PTRACE_GETFPREGS:
-		ret = save_ia32_fpstate(child, (struct _fpstate_ia32 *)data);
+		ret = save_ia32_fpstate(child, (struct _fpstate_ia32 *) A(data));
 		break;
 
 	      case IA32_PTRACE_SETFPREGS:
-		ret = restore_ia32_fpstate(child, (struct _fpstate_ia32 *)data);
+		ret = restore_ia32_fpstate(child, (struct _fpstate_ia32 *) A(data));
 		break;
 
 	      case PTRACE_SYSCALL:	/* continue, stop after next syscall */
@@ -2558,7 +2558,7 @@
 #define IOLEN	((65536 / 4) * 4096)
 
 asmlinkage long
-sys_iopl (int level, long arg1, long arg2, long arg3)
+sys_iopl (int level)
 {
 	extern unsigned long ia64_iobase;
 	int fd;
@@ -2570,7 +2570,7 @@
 	if (level != 3)
 		return(-EINVAL);
 	/* Trying to gain more privileges? */
-	__asm__ __volatile__("mov %0=ar.eflag ;;" : "=r"(old));
+	asm volatile ("mov %0=ar.eflag ;;" : "=r"(old));
 	if (level > ((old >> 12) & 3)) {
 		if (!capable(CAP_SYS_RAWIO))
 			return -EPERM;
@@ -2587,17 +2587,13 @@
 	}
 
 	down_write(&current->mm->mmap_sem);
-	lock_kernel();
-
 	addr = do_mmap_pgoff(file, IA32_IOBASE,
-			IOLEN, PROT_READ|PROT_WRITE, MAP_SHARED,
-			(ia64_iobase & ~PAGE_OFFSET) >> PAGE_SHIFT);
-
-	unlock_kernel();
+			     IOLEN, PROT_READ|PROT_WRITE, MAP_SHARED,
+			     (ia64_iobase & ~PAGE_OFFSET) >> PAGE_SHIFT);
 	up_write(&current->mm->mmap_sem);
 
 	if (addr >= 0) {
-		__asm__ __volatile__("mov ar.k0=%0 ;;" :: "r"(addr));
+		ia64_set_kr(IA64_KR_IO_BASE, addr);
 		old = (old & ~0x3000) | (level << 12);
 		__asm__ __volatile__("mov ar.eflag=%0 ;;" :: "r"(old));
 	}
@@ -2608,7 +2604,7 @@
 }
 
 asmlinkage long
-sys_ioperm (unsigned long from, unsigned long num, int on)
+sys_ioperm (unsigned int from, unsigned int num, int on)
 {
 
 	/*
@@ -2621,7 +2617,7 @@
 	 * XXX proper ioperm() support should be emulated by
 	 *	manipulating the page protections...
 	 */
-	return(sys_iopl(3, 0, 0, 0));
+	return sys_iopl(3);
 }
 
 typedef struct {
diff -urN lia64/arch/ia64/kernel/semaphore.c lia64-kdb/arch/ia64/kernel/semaphore.c
--- lia64/arch/ia64/kernel/semaphore.c	Wed Dec  6 18:36:35 2000
+++ lia64-kdb/arch/ia64/kernel/semaphore.c	Fri Apr 13 20:48:40 2001
@@ -321,13 +321,11 @@
 
 	if (count = 0) {
 		/* wake a writer */
-		if (xchg(&sem->write_bias_granted, 1))
-			BUG();
+		xchg(&sem->write_bias_granted, 1);
 		wq = &sem->write_bias_wait;
 	} else {
 		/* wake reader(s) */
-		if (xchg(&sem->read_bias_granted, 1))
-			BUG();
+		xchg(&sem->read_bias_granted, 1);
 		wq = &sem->wait;
 	}
 	wake_up(wq);	/* wake up everyone on the wait queue */
diff -urN lia64/arch/ia64/kernel/sys_ia64.c lia64-kdb/arch/ia64/kernel/sys_ia64.c
--- lia64/arch/ia64/kernel/sys_ia64.c	Thu Apr  5 09:57:58 2001
+++ lia64-kdb/arch/ia64/kernel/sys_ia64.c	Fri Apr 13 14:23:57 2001
@@ -253,13 +253,6 @@
 	return -ENOSYS;
 }
 
-asmlinkage long
-sys_modify_ldt (long arg0, long arg1, long arg2, long arg3)
-{
-	printk(KERN_ERR "sys_modify_ldt(%lx, %lx, %lx, %lx)!\n", arg0, arg1, arg2, arg3);
-	return -ENOSYS;
-}
-
 asmlinkage unsigned long
 ia64_create_module (const char *name_user, size_t size, long arg2, long arg3,
 		    long arg4, long arg5, long arg6, long arg7, long stack)
diff -urN lia64/arch/ia64/kernel/process.c lia64-kdb/arch/ia64/kernel/process.c
--- lia64/arch/ia64/kernel/process.c	Thu Apr  5 09:55:58 2001
+++ lia64-kdb/arch/ia64/kernel/process.c	Fri Apr 13 12:25:19 2001
@@ -143,7 +143,7 @@
 		pfm_save_regs(task);
 #endif
 	if (IS_IA32_PROCESS(ia64_task_regs(task)))
-		ia32_save_state(&task->thread);
+		ia32_save_state(task);
 }
 
 void
@@ -156,7 +156,7 @@
 		pfm_load_regs(task);
 #endif
 	if (IS_IA32_PROCESS(ia64_task_regs(task)))
-		ia32_load_state(&task->thread);
+		ia32_load_state(task);
 }
 
 /*
diff -urN lia64/include/asm-ia64/ia32.h lia64-kdb/include/asm-ia64/ia32.h
--- lia64/include/asm-ia64/ia32.h	Thu Apr  5 11:51:44 2001
+++ lia64-kdb/include/asm-ia64/ia32.h	Fri Apr 13 20:14:04 2001
@@ -108,7 +108,7 @@
 } sigset32_t;
 
 struct sigaction32 {
-       unsigned int  sa_handler;	/* Really a pointer, but need to deal 
+       unsigned int  sa_handler;	/* Really a pointer, but need to deal
 					     with 32 bits */
        unsigned int sa_flags;
        unsigned int sa_restorer;	/* Another 32 bit pointer */
@@ -118,7 +118,7 @@
 typedef unsigned int old_sigset32_t;	/* at least 32 bits */
 
 struct old_sigaction32 {
-       unsigned int  sa_handler;	/* Really a pointer, but need to deal 
+       unsigned int  sa_handler;	/* Really a pointer, but need to deal
 					     with 32 bits */
        old_sigset32_t sa_mask;		/* A 32 bit mask */
        unsigned int sa_flags;
@@ -133,7 +133,7 @@
 
 struct ucontext_ia32 {
 	unsigned int	  uc_flags;
-	unsigned int 	  uc_link;
+	unsigned int	  uc_link;
 	stack_ia32_t	  uc_stack;
 	struct sigcontext_ia32 uc_mcontext;
 	sigset_t	  uc_sigmask;	/* mask last for extensibility */
@@ -252,6 +252,15 @@
 #define ELF_ARCH	EM_386
 
 #define IA32_PAGE_OFFSET	0xc0000000
+#define IA32_STACK_TOP		((IA32_PAGE_OFFSET/3) * 2)
+
+/*
+ * The system segments (GDT, TSS, LDT) have to be mapped below 4GB so the IA-32 engine can
+ * access them.
+ */
+#define IA32_GDT_OFFSET		(IA32_PAGE_OFFSET)
+#define IA32_TSS_OFFSET		(IA32_PAGE_OFFSET + PAGE_SIZE)
+#define IA32_LDT_OFFSET		(IA32_PAGE_OFFSET + 2*PAGE_SIZE)
 
 #define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE	IA32_PAGE_SIZE
@@ -287,7 +296,7 @@
 
 /* This macro yields a bitmask that programs can use to figure out
    what instruction set this CPU supports.  */
-#define ELF_HWCAP 	0
+#define ELF_HWCAP	0
 
 /* This macro yields a string that ld.so will use to load
    implementation specific libraries for optimization.  Not terribly
@@ -304,58 +313,61 @@
 /*
  * IA-32 ELF specific definitions for IA-64.
  */
- 
+
 #define __USER_CS      0x23
 #define __USER_DS      0x2B
 
-#define SEG_LIM     32
-#define SEG_TYPE    52
-#define SEG_SYS     56
-#define SEG_DPL     57
-#define SEG_P       59
-#define SEG_DB      62
-#define SEG_G       63
-
 #define FIRST_TSS_ENTRY 6
 #define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1)
 #define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))
 #define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3))
 
-#define IA64_SEG_DESCRIPTOR(base, limit, segtype, nonsysseg, dpl, segpresent, segdb, granularity) \
-	       ((base)			       |       \
-		(limit << SEG_LIM)	       |       \
-		(segtype << SEG_TYPE)	       |       \
-		(nonsysseg << SEG_SYS)	       |       \
-		(dpl << SEG_DPL)	       |       \
-		(segpresent << SEG_P)	       |       \
-		(segdb << SEG_DB)	       |       \
-		(granularity << SEG_G))
-
-#define IA32_SEG_BASE 16
-#define IA32_SEG_TYPE 40
-#define IA32_SEG_SYS  44
-#define IA32_SEG_DPL  45
-#define IA32_SEG_P    47
-#define IA32_SEG_HIGH_LIMIT    48
-#define IA32_SEG_AVL   52
-#define IA32_SEG_DB    54
-#define IA32_SEG_G     55
-#define IA32_SEG_HIGH_BASE 56
-
-#define IA32_SEG_DESCRIPTOR(base, limit, segtype, nonsysseg, dpl, segpresent, avl, segdb, granularity) \
-	       ((limit & 0xFFFF)			       |       \
-		 (base & 0xFFFFFF << IA32_SEG_BASE)	       |       \
-		(segtype << IA32_SEG_TYPE)		       |       \
-		(nonsysseg << IA32_SEG_SYS)		       |       \
-		(dpl << IA32_SEG_DPL)			       |       \
-		(segpresent << IA32_SEG_P)		       |       \
-		(((limit >> 16) & 0xF) << IA32_SEG_HIGH_LIMIT) |       \
-		(avl << IA32_SEG_AVL)			       |       \
-		(segdb << IA32_SEG_DB)			       |       \
-		(granularity << IA32_SEG_G)		       |       \
-		(((base >> 24) & 0xFF) << IA32_SEG_HIGH_BASE)) 
+#define IA32_SEG_BASE		16
+#define IA32_SEG_TYPE		40
+#define IA32_SEG_SYS		44
+#define IA32_SEG_DPL		45
+#define IA32_SEG_P		47
+#define IA32_SEG_HIGH_LIMIT	48
+#define IA32_SEG_AVL		52
+#define IA32_SEG_DB		54
+#define IA32_SEG_G		55
+#define IA32_SEG_HIGH_BASE	56
+
+#define IA32_SEG_DESCRIPTOR(base, limit, segtype, nonsysseg, dpl, segpresent, avl, segdb, gran)	\
+	       (((limit) & 0xffff)								\
+		| (((unsigned long) (base) & 0xffffff) << IA32_SEG_BASE)			\
+		| ((unsigned long) (segtype) << IA32_SEG_TYPE)					\
+		| ((unsigned long) (nonsysseg) << IA32_SEG_SYS)					\
+		| ((unsigned long) (dpl) << IA32_SEG_DPL)					\
+		| ((unsigned long) (segpresent) << IA32_SEG_P)					\
+		| ((((unsigned long) (limit) >> 16) & 0xf) << IA32_SEG_HIGH_LIMIT)		\
+		| ((unsigned long) (avl) << IA32_SEG_AVL)					\
+		| ((unsigned long) (segdb) << IA32_SEG_DB)					\
+		| ((unsigned long) (gran) << IA32_SEG_G)					\
+		| ((((unsigned long) (base) >> 24) & 0xff) << IA32_SEG_HIGH_BASE))
+
+#define SEG_LIM		32
+#define SEG_TYPE	52
+#define SEG_SYS		56
+#define SEG_DPL		57
+#define SEG_P		59
+#define SEG_AVL		60
+#define SEG_DB		62
+#define SEG_G		63
+
+/* Unscramble an IA-32 segment descriptor into the IA-64 format.  */
+#define IA32_SEG_UNSCRAMBLE(sd)									 \
+	(   (((sd) >> IA32_SEG_BASE) & 0xffffff) | ((((sd) >> IA32_SEG_HIGH_BASE) & 0xff) << 24) \
+	 | ((((sd) & 0xffff) | ((((sd) >> IA32_SEG_HIGH_LIMIT) & 0xf) << 16)) << SEG_LIM)	 \
+	 | ((((sd) >> IA32_SEG_TYPE) & 0xf) << SEG_TYPE)					 \
+	 | ((((sd) >> IA32_SEG_SYS) & 0x1) << SEG_SYS)						 \
+	 | ((((sd) >> IA32_SEG_DPL) & 0x3) << SEG_DPL)						 \
+	 | ((((sd) >> IA32_SEG_P) & 0x1) << SEG_P)						 \
+	 | ((((sd) >> IA32_SEG_AVL) & 0x1) << SEG_AVL)						 \
+	 | ((((sd) >> IA32_SEG_DB) & 0x1) << SEG_DB)						 \
+	 | ((((sd) >> IA32_SEG_G) & 0x1) << SEG_G))
 
-#define IA32_IOBASE    0x2000000000000000 /* Virtual addres for I/O space */
+#define IA32_IOBASE    0x2000000000000000 /* Virtual address for I/O space */
 
 #define IA32_CR0       0x80000001      /* Enable PG and PE bits */
 #define IA32_CR4       0	       /* No architectural extensions */
@@ -384,6 +396,25 @@
 	regs->r12 = new_sp;							\
 } while (0)
 
+/*
+ * Local Descriptor Table (LDT) related declarations.
+ */
+
+#define IA32_LDT_ENTRIES	8192		/* Maximum number of LDT entries supported. */
+#define IA32_LDT_ENTRY_SIZE	8		/* The size of each LDT entry. */
+
+struct ia32_modify_ldt_ldt_s {
+	unsigned int entry_number;
+	unsigned int base_addr;
+	unsigned int limit;
+	unsigned int seg_32bit:1;
+	unsigned int contents:2;
+	unsigned int read_exec_only:1;
+	unsigned int limit_in_pages:1;
+	unsigned int seg_not_present:1;
+	unsigned int useable:1;
+};
+
 extern void ia32_gdt_init (void);
 extern int ia32_setup_frame1 (int sig, struct k_sigaction *ka, siginfo_t *info,
 			       sigset_t *set, struct pt_regs *regs);
@@ -392,5 +423,5 @@
 extern int ia32_exception (struct pt_regs *regs, unsigned long isr);
 
 #endif /* !CONFIG_IA32_SUPPORT */
- 
+
 #endif /* _ASM_IA64_IA32_H */
diff -urN lia64/include/asm-ia64/processor.h lia64-kdb/include/asm-ia64/processor.h
--- lia64/include/asm-ia64/processor.h	Thu Apr  5 11:51:41 2001
+++ lia64-kdb/include/asm-ia64/processor.h	Fri Apr 13 12:26:16 2001
@@ -417,7 +417,7 @@
 /*
  * Free all resources held by a thread. This is called after the
  * parent of DEAD_TASK has collected the exist status of the task via
- * wait().  This is a no-op on IA-64.
+ * wait().
  */
 #ifdef CONFIG_PERFMON
   extern void release_thread (struct task_struct *task);
@@ -514,8 +514,8 @@
 extern void ia64_load_debug_regs (unsigned long *save_area);
 
 #ifdef CONFIG_IA32_SUPPORT
-extern void ia32_save_state (struct thread_struct *thread);
-extern void ia32_load_state (struct thread_struct *thread);
+extern void ia32_save_state (struct task_struct *task);
+extern void ia32_load_state (struct task_struct *task);
 #endif
 
 #ifdef CONFIG_PERFMON


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [Linux-ia64] IA-32 LDT support patch
  2001-04-17  0:29 [Linux-ia64] IA-32 LDT support patch David Mosberger
@ 2001-04-18  7:57 ` Josue Amaro
  0 siblings, 0 replies; 2+ messages in thread
From: Josue Amaro @ 2001-04-18  7:57 UTC (permalink / raw)
  To: linux-ia64

[-- Attachment #1: Type: text/plain, Size: 41260 bytes --]

David,

I'll test it as soon as I can.

Thanks,

David Mosberger wrote:

> Below is a patch that goes on top of the IA-64 Linux version of
> v2.4.3.  It adds support for the IA-32 modify_ldt() system call which
> is needed to run certain x86 programs (such as programs linked against
> recent versions of x86 pthreads).
>
> Thanks to Don Dugger and Asit Mallick for reviewing the patch (all
> bugs are mine, of course...).  I really know almost nothing about x86
> and I'm trying hard to keep it that way ;-), but the patch should work
> OK.  At least "netscape" still works and a simple test program linked
> against a version of pthreads that uses modify_ldt() also seems to
> work fine.
>
> Enjoy,
>
>         --david
>
> diff -urN lia64/arch/ia64/ia32/Makefile lia64-kdb/arch/ia64/ia32/Makefile
> --- lia64/arch/ia64/ia32/Makefile       Wed Jan  3 23:06:42 2001
> +++ lia64-kdb/arch/ia64/ia32/Makefile   Fri Apr 13 14:21:30 2001
> @@ -11,7 +11,8 @@
>
>  O_TARGET := ia32.o
>
> -obj-y := ia32_entry.o sys_ia32.o ia32_ioctl.o ia32_signal.o ia32_support.o ia32_traps.o binfmt_elf32.o
> +obj-y := ia32_entry.o sys_ia32.o ia32_ioctl.o ia32_signal.o ia32_support.o ia32_traps.o \
> +        binfmt_elf32.o ia32_ldt.o
>
>  clean::
>
> diff -urN lia64/arch/ia64/ia32/binfmt_elf32.c lia64-kdb/arch/ia64/ia32/binfmt_elf32.c
> --- lia64/arch/ia64/ia32/binfmt_elf32.c Thu Apr  5 09:51:03 2001
> +++ lia64-kdb/arch/ia64/ia32/binfmt_elf32.c     Fri Apr 13 19:34:37 2001
> @@ -2,8 +2,11 @@
>   * IA-32 ELF support.
>   *
>   * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com>
> + * Copyright (C) 2001 Hewlett-Packard Co
> + * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com>
>   *
>   * 06/16/00    A. Mallick      initialize csd/ssd/tssd/cflg for ia32_load_state
> + * 04/13/01    D. Mosberger    dropped saving tssd in ar.k1---it's not needed
>   */
>  #include <linux/config.h>
>
> @@ -35,8 +38,8 @@
>  #undef CLOCKS_PER_SEC
>  #define CLOCKS_PER_SEC IA32_CLOCKS_PER_SEC
>
> -extern void ia64_elf32_init(struct pt_regs *regs);
> -extern void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address);
> +extern void ia64_elf32_init (struct pt_regs *regs);
> +extern void put_dirty_page (struct task_struct * tsk, struct page *page, unsigned long address);
>
>  #define ELF_PLAT_INIT(_r)              ia64_elf32_init(_r)
>  #define setup_arg_pages(bprm)          ia32_setup_arg_pages(bprm)
> @@ -49,7 +52,7 @@
>  unsigned long *ia32_gdt_table, *ia32_tss;
>
>  struct page *
> -put_shared_page(struct task_struct * tsk, struct page *page, unsigned long address)
> +put_shared_page (struct task_struct * tsk, struct page *page, unsigned long address)
>  {
>         pgd_t * pgd;
>         pmd_t * pmd;
> @@ -83,85 +86,87 @@
>         return 0;
>  }
>
> -void ia64_elf32_init(struct pt_regs *regs)
> +void
> +ia64_elf32_init (struct pt_regs *regs)
>  {
> +       struct vm_area_struct *vma;
>         int nr;
>
> -       put_shared_page(current, virt_to_page(ia32_gdt_table), IA32_PAGE_OFFSET);
> +       /*
> +        * Map GDT and TSS below 4GB, where the processor can find them.  We need to map
> +        * it with privilege level 3 because the IVE uses non-privileged accesses to these
> +        * tables.  IA-32 segmentation is used to protect against IA-32 accesses to them.
> +        */
> +       put_shared_page(current, virt_to_page(ia32_gdt_table), IA32_GDT_OFFSET);
>         if (PAGE_SHIFT <= IA32_PAGE_SHIFT)
> -               put_shared_page(current, virt_to_page(ia32_tss), IA32_PAGE_OFFSET + PAGE_SIZE);
> +               put_shared_page(current, virt_to_page(ia32_tss), IA32_TSS_OFFSET);
>
> -       nr = smp_processor_id();
> +       /*
> +        * Install LDT as anonymous memory.  This gives us all-zero segment descriptors
> +        * until a task modifies them via modify_ldt().
> +        */
> +       vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
> +       if (vma) {
> +               vma->vm_mm = current->mm;
> +               vma->vm_start = IA32_LDT_OFFSET;
> +               vma->vm_end = vma->vm_start + PAGE_ALIGN(IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE);
> +               vma->vm_page_prot = PAGE_SHARED;
> +               vma->vm_flags = VM_READ|VM_WRITE|VM_MAYREAD|VM_MAYWRITE;
> +               vma->vm_ops = NULL;
> +               vma->vm_pgoff = 0;
> +               vma->vm_file = NULL;
> +               vma->vm_private_data = NULL;
> +               insert_vm_struct(current->mm, vma);
> +       }
>
> -       /* Do all the IA-32 setup here */
> +       nr = smp_processor_id();
>
> -       current->thread.map_base  = 0x40000000;
> -       current->thread.task_size = 0xc0000000;         /* use what Linux/x86 uses... */
> +       current->thread.map_base  = IA32_PAGE_OFFSET/3;
> +       current->thread.task_size = IA32_PAGE_OFFSET;   /* use what Linux/x86 uses... */
>         set_fs(USER_DS);                                /* set addr limit for new TASK_SIZE */
>
> -       /* setup ia32 state for ia32_load_state */
> +       /* Setup the segment selectors */
> +       regs->r16 = (__USER_DS << 16) | __USER_DS; /* ES == DS, GS, FS are zero */
> +       regs->r17 = (__USER_DS << 16) | __USER_CS; /* SS, CS; ia32_load_state() sets TSS and LDT */
> +
> +       /* Setup the segment descriptors */
> +       regs->r24 = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_DS >> 3]);        /* ESD */
> +       regs->r27 = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_DS >> 3]);        /* DSD */
> +       regs->r28 = 0;                                                          /* FSD (null) */
> +       regs->r29 = 0;                                                          /* GSD (null) */
> +       regs->r30 = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[_LDT(nr)]);              /* LDTD */
>
> -       current->thread.eflag = IA32_EFLAG;
> -       current->thread.csd = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0xBL, 1L, 3L, 1L, 1L, 1L);
> -       current->thread.ssd = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, 3L, 1L, 1L, 1L);
> -       current->thread.tssd = IA64_SEG_DESCRIPTOR(IA32_PAGE_OFFSET + PAGE_SIZE, 0x1FFFL, 0xBL,
> -                                                  1L, 3L, 1L, 1L, 1L);
> -
> -       /* CS descriptor */
> -       __asm__("mov ar.csd = %0" : /* no outputs */
> -               : "r" IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0xBL, 1L,
> -                                         3L, 1L, 1L, 1L));
> -       /* SS descriptor */
> -       __asm__("mov ar.ssd = %0" : /* no outputs */
> -               : "r" IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L,
> -                                         3L, 1L, 1L, 1L));
> -       /* EFLAGS */
> -       __asm__("mov ar.eflag = %0" : /* no outputs */ : "r" (IA32_EFLAG));
> -
> -       /* Control registers */
> -       __asm__("mov ar.fsr = %0"
> -               : /* no outputs */
> -               : "r" ((ulong)IA32_FSR_DEFAULT));
> -       __asm__("mov ar.fcr = %0"
> -               : /* no outputs */
> -               : "r" ((ulong)IA32_FCR_DEFAULT));
> -       __asm__("mov ar.fir = r0");
> -       __asm__("mov ar.fdr = r0");
> -       current->thread.old_iob = ia64_get_kr(IA64_KR_IO_BASE);
> -       ia64_set_kr(IA64_KR_IO_BASE, IA32_IOBASE);
> -
> -       /* Get the segment selectors right */
> -       regs->r16 = (__USER_DS << 16) |  (__USER_DS); /* ES == DS, GS, FS are zero */
> -       regs->r17 = (_TSS(nr) << 48) | (_LDT(nr) << 32)
> -                   | (__USER_DS << 16) | __USER_CS;
> -
> -       /* Setup other segment descriptors - ESD, DSD, FSD, GSD */
> -       regs->r24 = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, 3L, 1L, 1L, 1L);
> -       regs->r27 = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, 3L, 1L, 1L, 1L);
> -       regs->r28 = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, 3L, 1L, 1L, 1L);
> -       regs->r29 = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, 3L, 1L, 1L, 1L);
> -
> -       /* Setup the LDT and GDT */
> -       regs->r30 = ia32_gdt_table[_LDT(nr)];
> -       regs->r31 = IA64_SEG_DESCRIPTOR(0xc0000000L, 0x400L, 0x3L, 1L, 3L,
> -                                       1L, 1L, 1L);
> -
> -       /* Clear psr.ac */
> -       regs->cr_ipsr &= ~IA64_PSR_AC;
> +       /*
> +        * Setup GDTD.  Note: GDTD is the descrambled version of the pseudo-descriptor
> +        * format defined by Figure 3-11 "Pseudo-Descriptor Format" in the IA-32
> +        * architecture manual.
> +        */
> +       regs->r31 = IA32_SEG_UNSCRAMBLE(IA32_SEG_DESCRIPTOR(IA32_GDT_OFFSET, IA32_PAGE_SIZE - 1, 0,
> +                                                           0, 0, 0, 0, 0, 0));
>
> +       ia64_psr(regs)->ac = 0;         /* turn off alignment checking */
>         regs->loadrs = 0;
> -}
>
> -#undef STACK_TOP
> -#define STACK_TOP ((IA32_PAGE_OFFSET/3) * 2)
> +       current->thread.eflag = IA32_EFLAG;
> +       current->thread.fsr = IA32_FSR_DEFAULT;
> +       current->thread.fcr = IA32_FCR_DEFAULT;
> +       current->thread.fir = 0;
> +       current->thread.fdr = 0;
> +       current->thread.csd = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_CS >> 3]);
> +       current->thread.ssd = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_DS >> 3]);
> +       current->thread.tssd = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[_TSS(nr)]);
> +
> +       ia32_load_state(current);
> +}
>
> -int ia32_setup_arg_pages(struct linux_binprm *bprm)
> +int
> +ia32_setup_arg_pages (struct linux_binprm *bprm)
>  {
>         unsigned long stack_base;
>         struct vm_area_struct *mpnt;
>         int i;
>
> -       stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
> +       stack_base = IA32_STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
>
>         bprm->p += stack_base;
>         if (bprm->loader)
> @@ -175,7 +180,7 @@
>         {
>                 mpnt->vm_mm = current->mm;
>                 mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
> -               mpnt->vm_end = STACK_TOP;
> +               mpnt->vm_end = IA32_STACK_TOP;
>                 mpnt->vm_page_prot = PAGE_COPY;
>                 mpnt->vm_flags = VM_STACK_FLAGS;
>                 mpnt->vm_ops = NULL;
> @@ -197,15 +202,15 @@
>  }
>
>  static unsigned long
> -ia32_mm_addr(unsigned long addr)
> +ia32_mm_addr (unsigned long addr)
>  {
>         struct vm_area_struct *vma;
>
>         if ((vma = find_vma(current->mm, addr)) == NULL)
> -               return(ELF_PAGESTART(addr));
> +               return ELF_PAGESTART(addr);
>         if (vma->vm_start > addr)
> -               return(ELF_PAGESTART(addr));
> -       return(ELF_PAGEALIGN(addr));
> +               return ELF_PAGESTART(addr);
> +       return ELF_PAGEALIGN(addr);
>  }
>
>  /*
> @@ -232,22 +237,9 @@
>          */
>         if (addr == 0)
>                 addr += PAGE_SIZE;
> -#if 1
>         set_brk(ia32_mm_addr(addr), addr + eppnt->p_memsz);
>         memset((char *) addr + eppnt->p_filesz, 0, eppnt->p_memsz - eppnt->p_filesz);
>         kernel_read(filep, eppnt->p_offset, (char *) addr, eppnt->p_filesz);
>         retval = (unsigned long) addr;
> -#else
> -       /* doesn't work yet... */
> -#      define IA32_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_EXEC_PAGESIZE-1))
> -#      define IA32_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1))
> -#      define IA32_PAGEALIGN(_v) (((_v) + ELF_EXEC_PAGESIZE - 1) & ~(ELF_EXEC_PAGESIZE - 1))
> -
> -       down_write(&current->mm->mmap_sem);
> -       retval = ia32_do_mmap(filep, IA32_PAGESTART(addr),
> -                             eppnt->p_filesz + IA32_PAGEOFFSET(eppnt->p_vaddr), prot, type,
> -                             eppnt->p_offset - IA32_PAGEOFFSET(eppnt->p_vaddr));
> -       up_write(&current->mm->mmap_sem);
> -#endif
>         return retval;
>  }
> diff -urN lia64/arch/ia64/ia32/ia32_entry.S lia64-kdb/arch/ia64/ia32/ia32_entry.S
> --- lia64/arch/ia64/ia32/ia32_entry.S   Wed Mar 28 21:42:44 2001
> +++ lia64-kdb/arch/ia64/ia32/ia32_entry.S       Fri Apr 13 14:36:18 2001
> @@ -233,7 +233,7 @@
>         data8 sys32_ni_syscall
>         data8 sys_iopl            /* 110 */
>         data8 sys_vhangup
> -       data8 sys32_ni_syscall          // used to be sys_idle
> +       data8 sys32_ni_syscall          /* used to be sys_idle */
>         data8 sys32_ni_syscall
>         data8 sys32_wait4
>         data8 sys_swapoff         /* 115 */
> @@ -244,7 +244,7 @@
>         data8 sys_clone           /* 120 */
>         data8 sys_setdomainname
>         data8 sys32_newuname
> -       data8 sys_modify_ldt
> +       data8 sys32_modify_ldt
>         data8 sys_adjtimex
>         data8 sys32_mprotect      /* 125 */
>         data8 sys_sigprocmask
> diff -urN lia64/arch/ia64/ia32/ia32_ldt.c lia64-kdb/arch/ia64/ia32/ia32_ldt.c
> --- lia64/arch/ia64/ia32/ia32_ldt.c     Wed Dec 31 16:00:00 1969
> +++ lia64-kdb/arch/ia64/ia32/ia32_ldt.c Fri Apr 13 20:23:48 2001
> @@ -0,0 +1,120 @@
> +/*
> + * Copyright (C) 2001 Hewlett-Packard Co
> + * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com>
> + *
> + * Adapted from arch/i386/kernel/ldt.c
> + */
> +
> +#include <linux/errno.h>
> +#include <linux/sched.h>
> +#include <linux/string.h>
> +#include <linux/mm.h>
> +#include <linux/smp.h>
> +#include <linux/smp_lock.h>
> +#include <linux/vmalloc.h>
> +
> +#include <asm/uaccess.h>
> +#include <asm/ia32.h>
> +
> +/*
> + * read_ldt() is not really atomic - this is not a problem since synchronization of reads
> + * and writes done to the LDT has to be assured by user-space anyway. Writes are atomic,
> + * to protect the security checks done on new descriptors.
> + */
> +static int
> +read_ldt (void *ptr, unsigned long bytecount)
> +{
> +       char *src, *dst, buf[256];      /* temporary buffer (don't overflow kernel stack!) */
> +       unsigned long bytes_left, n;
> +
> +       if (bytecount > IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE)
> +               bytecount = IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE;
> +
> +       bytes_left = bytecount;
> +
> +       src = (void *) IA32_LDT_OFFSET;
> +       dst = ptr;
> +
> +       while (bytes_left) {
> +               n = sizeof(buf);
> +               if (n > bytes_left)
> +                       n = bytes_left;
> +
> +               /*
> +                * We know we're reading valid memory, but we still must guard against
> +                * running out of memory.
> +                */
> +               if (__copy_from_user(buf, src, n))
> +                       return -EFAULT;
> +
> +               if (copy_to_user(dst, buf, n))
> +                       return -EFAULT;
> +
> +               src += n;
> +               dst += n;
> +               bytes_left -= n;
> +       }
> +       return bytecount;
> +}
> +
> +static int
> +write_ldt (void * ptr, unsigned long bytecount, int oldmode)
> +{
> +       struct ia32_modify_ldt_ldt_s ldt_info;
> +       __u64 entry;
> +
> +       if (bytecount != sizeof(ldt_info))
> +               return -EINVAL;
> +       if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info)))
> +               return -EFAULT;
> +
> +       if (ldt_info.entry_number >= IA32_LDT_ENTRIES)
> +               return -EINVAL;
> +       if (ldt_info.contents == 3) {
> +               if (oldmode)
> +                       return -EINVAL;
> +               if (ldt_info.seg_not_present == 0)
> +                       return -EINVAL;
> +       }
> +
> +       if (ldt_info.base_addr == 0 && ldt_info.limit == 0
> +           && (oldmode || (ldt_info.contents == 0 && ldt_info.read_exec_only == 1
> +                           && ldt_info.seg_32bit == 0 && ldt_info.limit_in_pages == 0
> +                           && ldt_info.seg_not_present == 1 && ldt_info.useable == 0)))
> +               /* allow LDTs to be cleared by the user */
> +               entry = 0;
> +       else
> +               /* we must set the "Accessed" bit as IVE doesn't emulate it */
> +               entry = IA32_SEG_DESCRIPTOR(ldt_info.base_addr, ldt_info.limit,
> +                                           (((ldt_info.read_exec_only ^ 1) << 1)
> +                                            | (ldt_info.contents << 2)) | 1,
> +                                           1, 3, ldt_info.seg_not_present ^ 1,
> +                                           (oldmode ? 0 : ldt_info.useable),
> +                                           ldt_info.seg_32bit,
> +                                           ldt_info.limit_in_pages);
> +       /*
> +        * Install the new entry.  We know we're accessing valid (mapped) user-level
> +        * memory, but we still need to guard against out-of-memory, hence we must use
> +        * put_user().
> +        */
> +       return __put_user(entry, (__u64 *) IA32_LDT_OFFSET + ldt_info.entry_number);
> +}
> +
> +asmlinkage int
> +sys32_modify_ldt (int func, void *ptr, unsigned int bytecount)
> +{
> +       int ret = -ENOSYS;
> +
> +       switch (func) {
> +             case 0:
> +               ret = read_ldt(ptr, bytecount);
> +               break;
> +             case 1:
> +               ret = write_ldt(ptr, bytecount, 1);
> +               break;
> +             case 0x11:
> +               ret = write_ldt(ptr, bytecount, 0);
> +               break;
> +       }
> +       return ret;
> +}
> diff -urN lia64/arch/ia64/ia32/ia32_support.c lia64-kdb/arch/ia64/ia32/ia32_support.c
> --- lia64/arch/ia64/ia32/ia32_support.c Wed Feb 21 16:05:28 2001
> +++ lia64-kdb/arch/ia64/ia32/ia32_support.c     Fri Apr 13 20:20:49 2001
> @@ -1,6 +1,11 @@
>  /*
>   * IA32 helper functions
>   *
> + * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com>
> + * Copyright (C) 2000 Asit K. Mallick <asit.k.mallick@intel.com>
> + * Copyright (C) 2001 Hewlett-Packard Co
> + * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com>
> + *
>   * 06/16/00    A. Mallick      added csd/ssd/tssd for ia32 thread context
>   * 02/19/01    D. Mosberger    dropped tssd; it's not needed
>   */
> @@ -21,7 +26,7 @@
>  extern void die_if_kernel (char *str, struct pt_regs *regs, long err);
>
>  void
> -ia32_save_state (struct thread_struct *thread)
> +ia32_save_state (struct task_struct *t)
>  {
>         unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd;
>
> @@ -33,28 +38,30 @@
>              "mov %5=ar.csd;"
>              "mov %6=ar.ssd;"
>              : "=r"(eflag), "=r"(fsr), "=r"(fcr), "=r"(fir), "=r"(fdr), "=r"(csd), "=r"(ssd));
> -       thread->eflag = eflag;
> -       thread->fsr = fsr;
> -       thread->fcr = fcr;
> -       thread->fir = fir;
> -       thread->fdr = fdr;
> -       thread->csd = csd;
> -       thread->ssd = ssd;
> -       asm ("mov ar.k0=%0 ;;" :: "r"(thread->old_iob));
> +       t->thread.eflag = eflag;
> +       t->thread.fsr = fsr;
> +       t->thread.fcr = fcr;
> +       t->thread.fir = fir;
> +       t->thread.fdr = fdr;
> +       t->thread.csd = csd;
> +       t->thread.ssd = ssd;
> +       ia64_set_kr(IA64_KR_IO_BASE, t->thread.old_iob);
>  }
>
>  void
> -ia32_load_state (struct thread_struct *thread)
> +ia32_load_state (struct task_struct *t)
>  {
>         unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd;
> +       struct pt_regs *regs = ia64_task_regs(t);
> +       int nr;
>
> -       eflag = thread->eflag;
> -       fsr = thread->fsr;
> -       fcr = thread->fcr;
> -       fir = thread->fir;
> -       fdr = thread->fdr;
> -       csd = thread->csd;
> -       ssd = thread->ssd;
> +       eflag = t->thread.eflag;
> +       fsr = t->thread.fsr;
> +       fcr = t->thread.fcr;
> +       fir = t->thread.fir;
> +       fdr = t->thread.fdr;
> +       csd = t->thread.csd;
> +       ssd = t->thread.ssd;
>
>         asm volatile ("mov ar.eflag=%0;"
>                       "mov ar.fsr=%1;"
> @@ -64,17 +71,22 @@
>                       "mov ar.csd=%5;"
>                       "mov ar.ssd=%6;"
>                       :: "r"(eflag), "r"(fsr), "r"(fcr), "r"(fir), "r"(fdr), "r"(csd), "r"(ssd));
> -       asm ("mov %0=ar.k0 ;;" : "=r"(thread->old_iob));
> -       asm ("mov ar.k0=%0 ;;" :: "r"(IA32_IOBASE));
> +       current->thread.old_iob = ia64_get_kr(IA64_KR_IO_BASE);
> +       ia64_set_kr(IA64_KR_IO_BASE, IA32_IOBASE);
> +
> +       /* load TSS and LDT while preserving SS and CS: */
> +       nr = smp_processor_id();
> +       regs->r17 = (_TSS(nr) << 48) | (_LDT(nr) << 32) | (__u32) regs->r17;
>  }
>
>  /*
> - * Setup IA32 GDT and TSS
> + * Setup IA32 GDT and TSS
>   */
>  void
> -ia32_gdt_init(void)
> +ia32_gdt_init (void)
>  {
> -       unsigned long gdt_and_tss_page;
> +       unsigned long gdt_and_tss_page, ldt_size;
> +       int nr;
>
>         /* allocate two IA-32 pages of memory: */
>         gdt_and_tss_page = __get_free_pages(GFP_KERNEL,
> @@ -86,17 +98,28 @@
>         /* Zero the gdt and tss */
>         memset((void *) gdt_and_tss_page, 0, 2*IA32_PAGE_SIZE);
>
> -       /* CS descriptor in IA-32 format */
> -       ia32_gdt_table[4] = IA32_SEG_DESCRIPTOR(0L, 0xBFFFFFFFL, 0xBL, 1L,
> -                                               3L, 1L, 1L, 1L, 1L);
> -
> -       /* DS descriptor in IA-32 format */
> -       ia32_gdt_table[5] = IA32_SEG_DESCRIPTOR(0L, 0xBFFFFFFFL, 0x3L, 1L,
> -                                               3L, 1L, 1L, 1L, 1L);
> +       /* CS descriptor in IA-32 (scrambled) format */
> +       ia32_gdt_table[__USER_CS >> 3] =
> +               IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET - 1) >> IA32_PAGE_SHIFT,
> +                                   0xb, 1, 3, 1, 1, 1, 1);
> +
> +       /* DS descriptor in IA-32 (scrambled) format */
> +       ia32_gdt_table[__USER_DS >> 3] =
> +               IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET - 1) >> IA32_PAGE_SHIFT,
> +                                   0x3, 1, 3, 1, 1, 1, 1);
> +
> +       /* We never change the TSS and LDT descriptors, so we can share them across all CPUs.  */
> +       ldt_size = PAGE_ALIGN(IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE);
> +       for (nr = 0; nr < NR_CPUS; ++nr) {
> +               ia32_gdt_table[_TSS(nr)] = IA32_SEG_DESCRIPTOR(IA32_TSS_OFFSET, 235,
> +                                                              0xb, 0, 3, 1, 1, 1, 0);
> +               ia32_gdt_table[_LDT(nr)] = IA32_SEG_DESCRIPTOR(IA32_LDT_OFFSET, ldt_size - 1,
> +                                                              0x2, 0, 3, 1, 1, 1, 0);
> +       }
>  }
>
>  /*
> - * Handle bad IA32 interrupt via syscall
> + * Handle bad IA32 interrupt via syscall
>   */
>  void
>  ia32_bad_interrupt (unsigned long int_num, struct pt_regs *regs)
> @@ -106,8 +129,7 @@
>         die_if_kernel("Bad IA-32 interrupt", regs, int_num);
>
>         siginfo.si_signo = SIGTRAP;
> -       siginfo.si_errno = int_num;     /* XXX is it legal to abuse si_errno like this? */
> +       siginfo.si_errno = int_num;     /* XXX is it OK to abuse si_errno like this? */
>         siginfo.si_code = TRAP_BRKPT;
>         force_sig_info(SIGTRAP, &siginfo, current);
>  }
> -
> diff -urN lia64/arch/ia64/ia32/sys_ia32.c lia64-kdb/arch/ia64/ia32/sys_ia32.c
> --- lia64/arch/ia64/ia32/sys_ia32.c     Thu Apr  5 09:51:22 2001
> +++ lia64-kdb/arch/ia64/ia32/sys_ia32.c Fri Apr 13 20:46:41 2001
> @@ -334,9 +334,9 @@
>         down_write(&current->mm->mmap_sem);
>         retval = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, a.offset >> PAGE_SHIFT);
>         up_write(&current->mm->mmap_sem);
> -#else  // CONFIG_IA64_PAGE_SIZE_4KB
> +#else
>         retval = ia32_do_mmap(file, a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
> -#endif // CONFIG_IA64_PAGE_SIZE_4KB
> +#endif
>         if (file)
>                 fput(file);
>         return retval;
> @@ -1886,8 +1886,7 @@
>                 break;
>
>         case SHMAT:
> -               err = do_sys32_shmat (first, second, third,
> -                                     version, (void *)AA(ptr));
> +               err = do_sys32_shmat (first, second, third, version, (void *)AA(ptr));
>                 break;
>         case SHMDT:
>                 err = sys_shmdt ((char *)AA(ptr));
> @@ -2334,8 +2333,8 @@
>   *    the address of `stack' will not be the address of the `pt_regs'.
>   */
>  asmlinkage long
> -sys32_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data,
> -           long arg4, long arg5, long arg6, long arg7, long stack)
> +sys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data,
> +             long arg4, long arg5, long arg6, long arg7, long stack)
>  {
>         struct pt_regs *regs = (struct pt_regs *) &stack;
>         struct task_struct *child;
> @@ -2379,7 +2378,7 @@
>               case PTRACE_PEEKDATA:     /* read word at location addr */
>                 ret = ia32_peek(regs, child, addr, &value);
>                 if (ret == 0)
> -                       ret = put_user(value, (unsigned int *)data);
> +                       ret = put_user(value, (unsigned int *)A(data));
>                 else
>                         ret = -EIO;
>                 goto out;
> @@ -2398,12 +2397,12 @@
>                 break;
>
>               case IA32_PTRACE_GETREGS:
> -               if (!access_ok(VERIFY_WRITE, (int *)data, 17*sizeof(int))) {
> +               if (!access_ok(VERIFY_WRITE, (int *) A(data), 17*sizeof(int))) {
>                         ret = -EIO;
>                         break;
>                 }
>                 for ( i = 0; i < 17*sizeof(int); i += sizeof(int) ) {
> -                       __put_user(getreg(child, i),(unsigned int *) data);
> +                       __put_user(getreg(child, i), (unsigned int *) A(data));
>                         data += sizeof(int);
>                 }
>                 ret = 0;
> @@ -2412,12 +2411,12 @@
>               case IA32_PTRACE_SETREGS:
>               {
>                 unsigned int tmp;
> -               if (!access_ok(VERIFY_READ, (int *)data, 17*sizeof(int))) {
> +               if (!access_ok(VERIFY_READ, (int *) A(data), 17*sizeof(int))) {
>                         ret = -EIO;
>                         break;
>                 }
>                 for ( i = 0; i < 17*sizeof(int); i += sizeof(int) ) {
> -                       __get_user(tmp, (unsigned int *) data);
> +                       __get_user(tmp, (unsigned int *) A(data));
>                         putreg(child, i, tmp);
>                         data += sizeof(int);
>                 }
> @@ -2426,11 +2425,11 @@
>               }
>
>               case IA32_PTRACE_GETFPREGS:
> -               ret = save_ia32_fpstate(child, (struct _fpstate_ia32 *)data);
> +               ret = save_ia32_fpstate(child, (struct _fpstate_ia32 *) A(data));
>                 break;
>
>               case IA32_PTRACE_SETFPREGS:
> -               ret = restore_ia32_fpstate(child, (struct _fpstate_ia32 *)data);
> +               ret = restore_ia32_fpstate(child, (struct _fpstate_ia32 *) A(data));
>                 break;
>
>               case PTRACE_SYSCALL:      /* continue, stop after next syscall */
> @@ -2558,7 +2558,7 @@
>  #define IOLEN  ((65536 / 4) * 4096)
>
>  asmlinkage long
> -sys_iopl (int level, long arg1, long arg2, long arg3)
> +sys_iopl (int level)
>  {
>         extern unsigned long ia64_iobase;
>         int fd;
> @@ -2570,7 +2570,7 @@
>         if (level != 3)
>                 return(-EINVAL);
>         /* Trying to gain more privileges? */
> -       __asm__ __volatile__("mov %0=ar.eflag ;;" : "=r"(old));
> +       asm volatile ("mov %0=ar.eflag ;;" : "=r"(old));
>         if (level > ((old >> 12) & 3)) {
>                 if (!capable(CAP_SYS_RAWIO))
>                         return -EPERM;
> @@ -2587,17 +2587,13 @@
>         }
>
>         down_write(&current->mm->mmap_sem);
> -       lock_kernel();
> -
>         addr = do_mmap_pgoff(file, IA32_IOBASE,
> -                       IOLEN, PROT_READ|PROT_WRITE, MAP_SHARED,
> -                       (ia64_iobase & ~PAGE_OFFSET) >> PAGE_SHIFT);
> -
> -       unlock_kernel();
> +                            IOLEN, PROT_READ|PROT_WRITE, MAP_SHARED,
> +                            (ia64_iobase & ~PAGE_OFFSET) >> PAGE_SHIFT);
>         up_write(&current->mm->mmap_sem);
>
>         if (addr >= 0) {
> -               __asm__ __volatile__("mov ar.k0=%0 ;;" :: "r"(addr));
> +               ia64_set_kr(IA64_KR_IO_BASE, addr);
>                 old = (old & ~0x3000) | (level << 12);
>                 __asm__ __volatile__("mov ar.eflag=%0 ;;" :: "r"(old));
>         }
> @@ -2608,7 +2604,7 @@
>  }
>
>  asmlinkage long
> -sys_ioperm (unsigned long from, unsigned long num, int on)
> +sys_ioperm (unsigned int from, unsigned int num, int on)
>  {
>
>         /*
> @@ -2621,7 +2617,7 @@
>          * XXX proper ioperm() support should be emulated by
>          *      manipulating the page protections...
>          */
> -       return(sys_iopl(3, 0, 0, 0));
> +       return sys_iopl(3);
>  }
>
>  typedef struct {
> diff -urN lia64/arch/ia64/kernel/semaphore.c lia64-kdb/arch/ia64/kernel/semaphore.c
> --- lia64/arch/ia64/kernel/semaphore.c  Wed Dec  6 18:36:35 2000
> +++ lia64-kdb/arch/ia64/kernel/semaphore.c      Fri Apr 13 20:48:40 2001
> @@ -321,13 +321,11 @@
>
>         if (count == 0) {
>                 /* wake a writer */
> -               if (xchg(&sem->write_bias_granted, 1))
> -                       BUG();
> +               xchg(&sem->write_bias_granted, 1);
>                 wq = &sem->write_bias_wait;
>         } else {
>                 /* wake reader(s) */
> -               if (xchg(&sem->read_bias_granted, 1))
> -                       BUG();
> +               xchg(&sem->read_bias_granted, 1);
>                 wq = &sem->wait;
>         }
>         wake_up(wq);    /* wake up everyone on the wait queue */
> diff -urN lia64/arch/ia64/kernel/sys_ia64.c lia64-kdb/arch/ia64/kernel/sys_ia64.c
> --- lia64/arch/ia64/kernel/sys_ia64.c   Thu Apr  5 09:57:58 2001
> +++ lia64-kdb/arch/ia64/kernel/sys_ia64.c       Fri Apr 13 14:23:57 2001
> @@ -253,13 +253,6 @@
>         return -ENOSYS;
>  }
>
> -asmlinkage long
> -sys_modify_ldt (long arg0, long arg1, long arg2, long arg3)
> -{
> -       printk(KERN_ERR "sys_modify_ldt(%lx, %lx, %lx, %lx)!\n", arg0, arg1, arg2, arg3);
> -       return -ENOSYS;
> -}
> -
>  asmlinkage unsigned long
>  ia64_create_module (const char *name_user, size_t size, long arg2, long arg3,
>                     long arg4, long arg5, long arg6, long arg7, long stack)
> diff -urN lia64/arch/ia64/kernel/process.c lia64-kdb/arch/ia64/kernel/process.c
> --- lia64/arch/ia64/kernel/process.c    Thu Apr  5 09:55:58 2001
> +++ lia64-kdb/arch/ia64/kernel/process.c        Fri Apr 13 12:25:19 2001
> @@ -143,7 +143,7 @@
>                 pfm_save_regs(task);
>  #endif
>         if (IS_IA32_PROCESS(ia64_task_regs(task)))
> -               ia32_save_state(&task->thread);
> +               ia32_save_state(task);
>  }
>
>  void
> @@ -156,7 +156,7 @@
>                 pfm_load_regs(task);
>  #endif
>         if (IS_IA32_PROCESS(ia64_task_regs(task)))
> -               ia32_load_state(&task->thread);
> +               ia32_load_state(task);
>  }
>
>  /*
> diff -urN lia64/include/asm-ia64/ia32.h lia64-kdb/include/asm-ia64/ia32.h
> --- lia64/include/asm-ia64/ia32.h       Thu Apr  5 11:51:44 2001
> +++ lia64-kdb/include/asm-ia64/ia32.h   Fri Apr 13 20:14:04 2001
> @@ -108,7 +108,7 @@
>  } sigset32_t;
>
>  struct sigaction32 {
> -       unsigned int  sa_handler;       /* Really a pointer, but need to deal
> +       unsigned int  sa_handler;       /* Really a pointer, but need to deal
>                                              with 32 bits */
>         unsigned int sa_flags;
>         unsigned int sa_restorer;       /* Another 32 bit pointer */
> @@ -118,7 +118,7 @@
>  typedef unsigned int old_sigset32_t;   /* at least 32 bits */
>
>  struct old_sigaction32 {
> -       unsigned int  sa_handler;       /* Really a pointer, but need to deal
> +       unsigned int  sa_handler;       /* Really a pointer, but need to deal
>                                              with 32 bits */
>         old_sigset32_t sa_mask;         /* A 32 bit mask */
>         unsigned int sa_flags;
> @@ -133,7 +133,7 @@
>
>  struct ucontext_ia32 {
>         unsigned int      uc_flags;
> -       unsigned int      uc_link;
> +       unsigned int      uc_link;
>         stack_ia32_t      uc_stack;
>         struct sigcontext_ia32 uc_mcontext;
>         sigset_t          uc_sigmask;   /* mask last for extensibility */
> @@ -252,6 +252,15 @@
>  #define ELF_ARCH       EM_386
>
>  #define IA32_PAGE_OFFSET       0xc0000000
> +#define IA32_STACK_TOP         ((IA32_PAGE_OFFSET/3) * 2)
> +
> +/*
> + * The system segments (GDT, TSS, LDT) have to be mapped below 4GB so the IA-32 engine can
> + * access them.
> + */
> +#define IA32_GDT_OFFSET                (IA32_PAGE_OFFSET)
> +#define IA32_TSS_OFFSET                (IA32_PAGE_OFFSET + PAGE_SIZE)
> +#define IA32_LDT_OFFSET                (IA32_PAGE_OFFSET + 2*PAGE_SIZE)
>
>  #define USE_ELF_CORE_DUMP
>  #define ELF_EXEC_PAGESIZE      IA32_PAGE_SIZE
> @@ -287,7 +296,7 @@
>
>  /* This macro yields a bitmask that programs can use to figure out
>     what instruction set this CPU supports.  */
> -#define ELF_HWCAP      0
> +#define ELF_HWCAP      0
>
>  /* This macro yields a string that ld.so will use to load
>     implementation specific libraries for optimization.  Not terribly
> @@ -304,58 +313,61 @@
>  /*
>   * IA-32 ELF specific definitions for IA-64.
>   */
> -
> +
>  #define __USER_CS      0x23
>  #define __USER_DS      0x2B
>
> -#define SEG_LIM     32
> -#define SEG_TYPE    52
> -#define SEG_SYS     56
> -#define SEG_DPL     57
> -#define SEG_P       59
> -#define SEG_DB      62
> -#define SEG_G       63
> -
>  #define FIRST_TSS_ENTRY 6
>  #define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1)
>  #define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))
>  #define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3))
>
> -#define IA64_SEG_DESCRIPTOR(base, limit, segtype, nonsysseg, dpl, segpresent, segdb, granularity) \
> -              ((base)                         |       \
> -               (limit << SEG_LIM)             |       \
> -               (segtype << SEG_TYPE)          |       \
> -               (nonsysseg << SEG_SYS)         |       \
> -               (dpl << SEG_DPL)               |       \
> -               (segpresent << SEG_P)          |       \
> -               (segdb << SEG_DB)              |       \
> -               (granularity << SEG_G))
> -
> -#define IA32_SEG_BASE 16
> -#define IA32_SEG_TYPE 40
> -#define IA32_SEG_SYS  44
> -#define IA32_SEG_DPL  45
> -#define IA32_SEG_P    47
> -#define IA32_SEG_HIGH_LIMIT    48
> -#define IA32_SEG_AVL   52
> -#define IA32_SEG_DB    54
> -#define IA32_SEG_G     55
> -#define IA32_SEG_HIGH_BASE 56
> -
> -#define IA32_SEG_DESCRIPTOR(base, limit, segtype, nonsysseg, dpl, segpresent, avl, segdb, granularity) \
> -              ((limit & 0xFFFF)                               |       \
> -                (base & 0xFFFFFF << IA32_SEG_BASE)            |       \
> -               (segtype << IA32_SEG_TYPE)                     |       \
> -               (nonsysseg << IA32_SEG_SYS)                    |       \
> -               (dpl << IA32_SEG_DPL)                          |       \
> -               (segpresent << IA32_SEG_P)                     |       \
> -               (((limit >> 16) & 0xF) << IA32_SEG_HIGH_LIMIT) |       \
> -               (avl << IA32_SEG_AVL)                          |       \
> -               (segdb << IA32_SEG_DB)                         |       \
> -               (granularity << IA32_SEG_G)                    |       \
> -               (((base >> 24) & 0xFF) << IA32_SEG_HIGH_BASE))
> +#define IA32_SEG_BASE          16
> +#define IA32_SEG_TYPE          40
> +#define IA32_SEG_SYS           44
> +#define IA32_SEG_DPL           45
> +#define IA32_SEG_P             47
> +#define IA32_SEG_HIGH_LIMIT    48
> +#define IA32_SEG_AVL           52
> +#define IA32_SEG_DB            54
> +#define IA32_SEG_G             55
> +#define IA32_SEG_HIGH_BASE     56
> +
> +#define IA32_SEG_DESCRIPTOR(base, limit, segtype, nonsysseg, dpl, segpresent, avl, segdb, gran)        \
> +              (((limit) & 0xffff)                                                              \
> +               | (((unsigned long) (base) & 0xffffff) << IA32_SEG_BASE)                        \
> +               | ((unsigned long) (segtype) << IA32_SEG_TYPE)                                  \
> +               | ((unsigned long) (nonsysseg) << IA32_SEG_SYS)                                 \
> +               | ((unsigned long) (dpl) << IA32_SEG_DPL)                                       \
> +               | ((unsigned long) (segpresent) << IA32_SEG_P)                                  \
> +               | ((((unsigned long) (limit) >> 16) & 0xf) << IA32_SEG_HIGH_LIMIT)              \
> +               | ((unsigned long) (avl) << IA32_SEG_AVL)                                       \
> +               | ((unsigned long) (segdb) << IA32_SEG_DB)                                      \
> +               | ((unsigned long) (gran) << IA32_SEG_G)                                        \
> +               | ((((unsigned long) (base) >> 24) & 0xff) << IA32_SEG_HIGH_BASE))
> +
> +#define SEG_LIM                32
> +#define SEG_TYPE       52
> +#define SEG_SYS                56
> +#define SEG_DPL                57
> +#define SEG_P          59
> +#define SEG_AVL                60
> +#define SEG_DB         62
> +#define SEG_G          63
> +
> +/* Unscramble an IA-32 segment descriptor into the IA-64 format.  */
> +#define IA32_SEG_UNSCRAMBLE(sd)                                                                         \
> +       (   (((sd) >> IA32_SEG_BASE) & 0xffffff) | ((((sd) >> IA32_SEG_HIGH_BASE) & 0xff) << 24) \
> +        | ((((sd) & 0xffff) | ((((sd) >> IA32_SEG_HIGH_LIMIT) & 0xf) << 16)) << SEG_LIM)        \
> +        | ((((sd) >> IA32_SEG_TYPE) & 0xf) << SEG_TYPE)                                         \
> +        | ((((sd) >> IA32_SEG_SYS) & 0x1) << SEG_SYS)                                           \
> +        | ((((sd) >> IA32_SEG_DPL) & 0x3) << SEG_DPL)                                           \
> +        | ((((sd) >> IA32_SEG_P) & 0x1) << SEG_P)                                               \
> +        | ((((sd) >> IA32_SEG_AVL) & 0x1) << SEG_AVL)                                           \
> +        | ((((sd) >> IA32_SEG_DB) & 0x1) << SEG_DB)                                             \
> +        | ((((sd) >> IA32_SEG_G) & 0x1) << SEG_G))
>
> -#define IA32_IOBASE    0x2000000000000000 /* Virtual addres for I/O space */
> +#define IA32_IOBASE    0x2000000000000000 /* Virtual address for I/O space */
>
>  #define IA32_CR0       0x80000001      /* Enable PG and PE bits */
>  #define IA32_CR4       0              /* No architectural extensions */
> @@ -384,6 +396,25 @@
>         regs->r12 = new_sp;                                                     \
>  } while (0)
>
> +/*
> + * Local Descriptor Table (LDT) related declarations.
> + */
> +
> +#define IA32_LDT_ENTRIES       8192            /* Maximum number of LDT entries supported. */
> +#define IA32_LDT_ENTRY_SIZE    8               /* The size of each LDT entry. */
> +
> +struct ia32_modify_ldt_ldt_s {
> +       unsigned int entry_number;
> +       unsigned int base_addr;
> +       unsigned int limit;
> +       unsigned int seg_32bit:1;
> +       unsigned int contents:2;
> +       unsigned int read_exec_only:1;
> +       unsigned int limit_in_pages:1;
> +       unsigned int seg_not_present:1;
> +       unsigned int useable:1;
> +};
> +
>  extern void ia32_gdt_init (void);
>  extern int ia32_setup_frame1 (int sig, struct k_sigaction *ka, siginfo_t *info,
>                                sigset_t *set, struct pt_regs *regs);
> @@ -392,5 +423,5 @@
>  extern int ia32_exception (struct pt_regs *regs, unsigned long isr);
>
>  #endif /* !CONFIG_IA32_SUPPORT */
> -
> +
>  #endif /* _ASM_IA64_IA32_H */
> diff -urN lia64/include/asm-ia64/processor.h lia64-kdb/include/asm-ia64/processor.h
> --- lia64/include/asm-ia64/processor.h  Thu Apr  5 11:51:41 2001
> +++ lia64-kdb/include/asm-ia64/processor.h      Fri Apr 13 12:26:16 2001
> @@ -417,7 +417,7 @@
>  /*
>   * Free all resources held by a thread. This is called after the
>   * parent of DEAD_TASK has collected the exist status of the task via
> - * wait().  This is a no-op on IA-64.
> + * wait().
>   */
>  #ifdef CONFIG_PERFMON
>    extern void release_thread (struct task_struct *task);
> @@ -514,8 +514,8 @@
>  extern void ia64_load_debug_regs (unsigned long *save_area);
>
>  #ifdef CONFIG_IA32_SUPPORT
> -extern void ia32_save_state (struct thread_struct *thread);
> -extern void ia32_load_state (struct thread_struct *thread);
> +extern void ia32_save_state (struct task_struct *task);
> +extern void ia32_load_state (struct task_struct *task);
>  #endif
>
>  #ifdef CONFIG_PERFMON
>
> _______________________________________________
> Linux-IA64 mailing list
> Linux-IA64@linuxia64.org
> http://lists.linuxia64.org/lists/listinfo/linux-ia64

--
"When you see the correct course, act; do not wait for orders."
The Art of War

=======================================================================
  Josue Emmanuel Amaro                         Josue.Amaro@oracle.com
  Linux Products Manager                       Phone:   650.506.1239
  Intel and Linux Technologies Group           Fax:     650.413.0167
=======================================================================


[-- Attachment #2: Card for Josue Amaro --]
[-- Type: text/x-vcard, Size: 334 bytes --]

begin:vcard 
n:Amaro;Josue
tel;fax:650 413 0167
tel;work:650 506 1239
x-mozilla-html:FALSE
url:www.oracle.com
org:Oracle Corporation
version:2.1
email;internet:josue.amaro@oracle.com
title:Linux Products Manager
adr;quoted-printable:;;500 Oracle Parkway=0D=0AMS 401 ip 4;Redwood Shores;CA;94065;United States
fn:Josue Amaro
end:vcard

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2001-04-18  7:57 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2001-04-17  0:29 [Linux-ia64] IA-32 LDT support patch David Mosberger
2001-04-18  7:57 ` Josue Amaro

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox