From mboxrd@z Thu Jan 1 00:00:00 1970 From: David Mosberger Date: Tue, 17 Apr 2001 00:29:14 +0000 Subject: [Linux-ia64] IA-32 LDT support patch Message-Id: List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: linux-ia64@vger.kernel.org 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 + * Copyright (C) 2001 Hewlett-Packard Co + * Copyright (C) 2001 David Mosberger-Tang * * 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 @@ -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(¤t->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(¤t->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 + * + * Adapted from arch/i386/kernel/ldt.c + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * 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 + * Copyright (C) 2000 Asit K. Mallick + * Copyright (C) 2001 Hewlett-Packard Co + * Copyright (C) 2001 David Mosberger-Tang + * * 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(¤t->mm->mmap_sem); retval = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, a.offset >> PAGE_SHIFT); up_write(¤t->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(¤t->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(¤t->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