diff -Naru linux-2.6.1.org/arch/ia64/Makefile linux-2.6.1/arch/ia64/Makefile --- linux-2.6.1.org/arch/ia64/Makefile Thu Jan 8 22:59:06 2004 +++ linux-2.6.1/arch/ia64/Makefile Thu Jan 29 07:35:32 2004 @@ -55,6 +55,7 @@ libs-y += arch/ia64/lib/ core-y += arch/ia64/kernel/ arch/ia64/mm/ +core-y += arch/ia64/ilp32/ core-$(CONFIG_IA32_SUPPORT) += arch/ia64/ia32/ core-$(CONFIG_IA64_DIG) += arch/ia64/dig/ core-$(CONFIG_IA64_GENERIC) += arch/ia64/dig/ diff -Naru linux-2.6.1.org/arch/ia64/ilp32/Makefile linux-2.6.1/arch/ia64/ilp32/Makefile --- linux-2.6.1.org/arch/ia64/ilp32/Makefile Wed Dec 31 16:00:00 1969 +++ linux-2.6.1/arch/ia64/ilp32/Makefile Thu Jan 29 07:35:32 2004 @@ -0,0 +1,5 @@ +# +# Makefile for the ipl32 kernel support subsystem. +# + +obj-y := binfmt_ilp32.o diff -Naru linux-2.6.1.org/arch/ia64/ilp32/binfmt_ilp32.c linux-2.6.1/arch/ia64/ilp32/binfmt_ilp32.c --- linux-2.6.1.org/arch/ia64/ilp32/binfmt_ilp32.c Wed Dec 31 16:00:00 1969 +++ linux-2.6.1/arch/ia64/ilp32/binfmt_ilp32.c Thu Jan 29 07:35:32 2004 @@ -0,0 +1,130 @@ +#include +#include +#include +#include +#include + +#include + +/* Override some function names */ +#undef start_thread +#define start_thread ilp32_elf_start_thread +#define elf_format ilp32_elf_format +#define init_elf_binfmt init_ilp32_elf_binfmt +#define exit_elf_binfmt exit_ilp32_elf_binfmt + +extern void put_dirty_page(struct task_struct *tsk, struct page *page, unsigned long address, pgprot_t prot); + +struct linux_binprm; struct elf32_hdr; +static int ilp32_elf_setup_arg_pages (struct linux_binprm *); +static void ilp32_elf_set_personality (struct elf32_hdr *, unsigned char); +void ilp32_init_addr_space(void); + +#undef ELF_PLAT_INIT +#define ELF_PLAT_INIT(_r,d) ilp32_init_addr_space() +#define setup_arg_pages(bprm) ilp32_elf_setup_arg_pages(bprm) +#undef SET_PERSONALITY +#define SET_PERSONALITY(ex, ibcs2) ilp32_elf_set_personality(&(ex), ibcs2) +#undef ELF_CORE_WRITE_EXTRA_DATA +#undef ELF_CORE_WRITE_EXTRA_PHDRS +#undef ARCH_DLINFO +#undef ELF_CORE_EXTRA_PHDRS +#include "../../../fs/binfmt_elf.c" + +static int ilp32_elf_setup_arg_pages (struct linux_binprm *bprm) +{ + unsigned long stack_base; + struct vm_area_struct *mpnt; + struct mm_struct *mm = current->mm; + int i; + + stack_base = ILP32_STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE; + + bprm->p += stack_base; + mm->arg_start = bprm->p; + + if (bprm->loader) + bprm->loader += stack_base; + bprm->exec += stack_base; + + mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (!mpnt) + return -ENOMEM; + + down_write(¤t->mm->mmap_sem); + { + mpnt->vm_mm = current->mm; + mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; + mpnt->vm_end = ILP32_STACK_TOP; + mpnt->vm_page_prot = PAGE_COPY; + mpnt->vm_flags = VM_STACK_FLAGS; + mpnt->vm_ops = NULL; + mpnt->vm_pgoff = 0; + mpnt->vm_file = NULL; + mpnt->vm_private_data = 0; + insert_vm_struct(current->mm, mpnt); + current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; + } + + for (i = 0 ; i < MAX_ARG_PAGES ; i++) { + struct page *page = bprm->page[i]; + if (page) { + bprm->page[i] = NULL; + put_dirty_page(current, page, stack_base, PAGE_COPY); + } + stack_base += PAGE_SIZE; + } + up_write(¤t->mm->mmap_sem); + + return 0; +} + +static void ilp32_elf_set_personality (struct elfhdr *elf_ex, unsigned char exec_stack) +{ + set_personality(PER_LINUX_32BIT); + current->thread.map_base = ILP32_MMAP_BASE; + current->thread.task_size = ILP32_PAGE_OFFSET; + if (elf_ex->e_flags & EF_IA_64_LINUX_EXECUTABLE_STACK) + current->thread.flags |= IA64_THREAD_XSTACK; + else + current->thread.flags &= ~IA64_THREAD_XSTACK; + set_fs(USER_DS); +} + +void ilp32_init_addr_space() +{ + struct vm_area_struct *vma; + + /* + * If we're out of memory and kmem_cache_alloc() returns NULL, we simply ignore + * the problem. When the process attempts to write to the register backing store + * for the first time, it will get a SEGFAULT in this case. + */ + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (vma) { + vma->vm_mm = current->mm; + vma->vm_start = ILP32_RBS_BOT; + vma->vm_end = vma->vm_start + PAGE_SIZE; + vma->vm_page_prot = PAGE_COPY; + vma->vm_flags = VM_READ|VM_WRITE|VM_MAYREAD|VM_MAYWRITE|VM_GROWSUP; + vma->vm_ops = NULL; + vma->vm_pgoff = 0; + vma->vm_file = NULL; + vma->vm_private_data = NULL; + insert_vm_struct(current->mm, vma); + } + + /* map NaT-page at address zero to speed up speculative dereferencing of NULL: */ + if (!(current->personality & MMAP_PAGE_ZERO)) { + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (vma) { + memset(vma, 0, sizeof(*vma)); + vma->vm_mm = current->mm; + vma->vm_end = PAGE_SIZE; + vma->vm_page_prot = __pgprot(pgprot_val(PAGE_READONLY) | _PAGE_MA_NAT); + vma->vm_flags = VM_READ | VM_MAYREAD | VM_IO | VM_RESERVED; + insert_vm_struct(current->mm, vma); + } + } +} + diff -Naru linux-2.6.1.org/arch/ia64/kernel/process.c linux-2.6.1/arch/ia64/kernel/process.c --- linux-2.6.1.org/arch/ia64/kernel/process.c Thu Jan 8 22:59:33 2004 +++ linux-2.6.1/arch/ia64/kernel/process.c Thu Jan 29 07:35:32 2004 @@ -553,15 +553,28 @@ asmlinkage long sys_execve (char *filename, char **argv, char **envp, struct pt_regs *regs) { - int error; + unsigned long old_map_base, old_task_size; + long error; + + /* we may be exec'ing a 64-bit<->32-bit process: reset map base, task-size: */ + old_map_base = current->thread.map_base; + old_task_size = current->thread.task_size; + current->thread.map_base = DEFAULT_MAP_BASE; + current->thread.task_size = DEFAULT_TASK_SIZE; filename = getname(filename); error = PTR_ERR(filename); - if (IS_ERR(filename)) - goto out; + if (!IS_ERR(filename)) { error = do_execve(filename, argv, envp, regs); putname(filename); -out: + } + + if (error < 0) { + /* oops, execve failed, switch back to old values... */ + current->thread.map_base = old_map_base; + current->thread.task_size = old_task_size; + } + return error; } diff -Naru linux-2.6.1.org/include/asm-ia64/elf.h linux-2.6.1/include/asm-ia64/elf.h --- linux-2.6.1.org/include/asm-ia64/elf.h Thu Jan 8 22:59:46 2004 +++ linux-2.6.1/include/asm-ia64/elf.h Thu Jan 29 07:35:32 2004 @@ -16,7 +16,7 @@ /* * This is used to ensure we don't load something for the wrong architecture. */ -#define elf_check_arch(x) ((x)->e_machine == EM_IA_64) +#define elf_check_arch(x) ((x)->e_machine == EM_IA_64 && (x)->e_ident[EI_CLASS] == ELFCLASS64) /* * These are used to set parameters in the core dumps. diff -Naru linux-2.6.1.org/include/asm-ia64/ilp32.h linux-2.6.1/include/asm-ia64/ilp32.h --- linux-2.6.1.org/include/asm-ia64/ilp32.h Wed Dec 31 16:00:00 1969 +++ linux-2.6.1/include/asm-ia64/ilp32.h Thu Jan 29 07:35:32 2004 @@ -0,0 +1,40 @@ +#ifndef _ASM_IA64_ILP32_H +#define _ASM_IA64_ILP32_H + +#include + +/* + * Data types and macros for providing ILP32 support for native IA-64 instruction set. + */ + +#include +#include +#include +#include + +#include +#undef ELF_CLASS +#define ELF_CLASS ELFCLASS32 +#undef elf_check_arch +#define elf_check_arch(x) ((x)->e_machine == EM_IA_64 && (x)->e_ident[EI_CLASS] == ELFCLASS32) +#undef ELF_ET_DYN_BASE +#define ELF_ET_DYN_BASE 0x80000000UL + +#define elf_addr_t u32 +#define elf_caddr_t u32 + +#define ILP32_PAGE_OFFSET 0x100000000UL /* 4G */ +#define ILP32_STACK_TOP (ILP32_PAGE_OFFSET - PAGE_SIZE) +#define ILP32_RBS_BOT 0xF0000000UL /* bottom of reg. backing store */ +#define ILP32_MMAP_BASE 0x40000000UL + +#define ROUND_UP(x,a) ((__typeof__(x))(((unsigned long)(x) + ((a) - 1)) & ~((a) - 1))) +#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) + +static inline void ilp32_elf_start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp) +{ + start_thread(regs,new_ip,new_sp); + regs->ar_bspstore = ILP32_RBS_BOT; +} + +#endif