--- linux-2.4.19-7um-pm/include/asm-um/processor-generic.h.orig Fri Sep 27 13:39:10 2002 +++ linux-2.4.19-7um-pm/include/asm-um/processor-generic.h Fri Sep 27 15:44:01 2002 @@ -19,7 +19,7 @@ struct mm_struct; #define current_text_addr() ((void *) 0) - +#define IO_BITMAP_SIZE 32 #define cpu_relax() do ; while (0) struct thread_struct { @@ -56,6 +56,10 @@ } cb; } u; } request; + + int ioperm; + unsigned long io_bitmap[IO_BITMAP_SIZE+1]; + int iopl; }; #define INIT_THREAD \ --- linux-2.4.19-7um-pm/arch/um/include/kern_util.h.orig Fri Sep 27 13:33:30 2002 +++ linux-2.4.19-7um-pm/arch/um/include/kern_util.h Fri Sep 27 13:05:56 2002 @@ -28,7 +28,8 @@ extern int do_signal(int error); extern int is_stack_fault(unsigned long sp); extern unsigned long segv(unsigned long address, unsigned long ip, - int is_write, int is_user, void *sc_ptr); + int is_write, int is_user, unsigned long fault_type, + void *sc_ptr); extern int set_user_mode(void *task); extern void syscall_ready(void); extern void set_tracing(void *t, int tracing); --- linux-2.4.19-7um-pm/arch/um/kernel/sys_call_table.c.orig Fri Sep 27 13:36:37 2002 +++ linux-2.4.19-7um-pm/arch/um/kernel/sys_call_table.c Fri Sep 27 18:20:42 2002 @@ -219,6 +219,8 @@ extern syscall_handler_t sys_gettid; extern syscall_handler_t sys_readahead; extern syscall_handler_t sys_tkill; +extern syscall_handler_t sys_iopl; +extern syscall_handler_t sys_ioperm; extern syscall_handler_t um_mount; extern syscall_handler_t um_time; @@ -338,7 +340,8 @@ [ __NR_profil ] = sys_ni_syscall, [ __NR_statfs ] = sys_statfs, [ __NR_fstatfs ] = sys_fstatfs, - [ __NR_ioperm ] = sys_ni_syscall, + [ __NR_ioperm ] = sys_ioperm, + [ __NR_iopl ] = sys_iopl, [ __NR_socketcall ] = sys_socketcall, [ __NR_syslog ] = sys_syslog, [ __NR_setitimer ] = sys_setitimer, @@ -347,7 +350,6 @@ [ __NR_lstat ] = sys_newlstat, [ __NR_fstat ] = sys_newfstat, [ __NR_olduname ] = sys_uname, - [ __NR_iopl ] = sys_ni_syscall, [ __NR_vhangup ] = sys_vhangup, [ __NR_idle ] = sys_ni_syscall, [ __NR_wait4 ] = (syscall_handler_t *) sys_wait4, --- linux-2.4.19-7um-pm/arch/um/kernel/ioport_kern.c.orig Fri Sep 27 18:54:20 2002 +++ linux-2.4.19-7um-pm/arch/um/kernel/ioport_kern.c Fri Sep 27 18:28:09 2002 @@ -0,0 +1,138 @@ +/* + * [ioport_kern.c] + * Released under the GPL + * + * Created: Sapan Bhatia 29.8.02 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mem_user.h" + +unsigned long portmem_size; +unsigned char *uml_port_memory = NULL; + +inline int check_perm(unsigned long port) +{ + struct thread_struct *t; + unsigned long *bitmap, *bitmap_base; + unsigned short low_index; + + t = ¤t->thread; + if (!t->ioperm) { + return 0; + } + + bitmap = t->io_bitmap; + bitmap_base = bitmap + (port >> 5); + low_index = port & 0x1f; + + /* 1 means permission is denied, we need to be careful here */ + + return ((!((1<iopl); + +} + +int init_portmem(void) +{ + /* Maybe we don't want the user to know that it's virtual + * printk(KERN_INFO "Virtual port memory, version 0.1\n"); + * */ + + uml_port_memory = (char *) find_iomem("portmem", &portmem_size); + if(portmem_size == 0) { + uml_port_memory = (char *) kmalloc(65536, GFP_KERNEL); + }; + + if (uml_port_memory == NULL) + panic("Could not allocate port memory\n"); + + return(0); +} + +__initcall(init_portmem); + +/* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */ +static void set_bitmap(unsigned long *bitmap, short base, short extent, int new_value) +{ + int mask; + unsigned long *bitmap_base = bitmap + (base >> 5); + unsigned short low_index = base & 0x1f; + int length = low_index + extent; + + if (low_index != 0) { + mask = (~0 << low_index); + if (length < 32) + mask &= ~(~0 << length); + if (new_value) + *bitmap_base++ |= mask; + else + *bitmap_base++ &= ~mask; + length -= 32; + } + + mask = (new_value ? ~0 : 0); + while (length >= 32) { + *bitmap_base++ = mask; + length -= 32; + } + + if (length > 0) { + mask = ~(~0 << length); + if (new_value) + *bitmap_base++ |= mask; + else + *bitmap_base++ &= ~mask; + } +} + +/* + * this changes the io permissions bitmap in the current task. + * taken from arch/i386 + */ +int sys_ioperm(unsigned long from, unsigned long num, int turn_on) +{ + struct thread_struct * t = ¤t->thread; + + if ((from + num <= from) || (from + num > IO_BITMAP_SIZE*32)) + return -EINVAL; + if (turn_on && !capable(CAP_SYS_RAWIO)) + return -EPERM; + if (!t->ioperm) { + memset(t->io_bitmap,0xff,(IO_BITMAP_SIZE+1)*4); + t->ioperm = 1; + } + + set_bitmap(t->io_bitmap, from, num, !turn_on); + + return 0; +} + +int sys_iopl(int level) +{ + struct thread_struct * t = ¤t->thread; + + if (level > 3) + return -EINVAL; + + if (level > t->iopl) { + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + } + + t->ioperm=1; + t->iopl = level; + + return 0; +} --- linux-2.4.19-7um-pm/arch/um/kernel/trap_user.c.orig Fri Sep 27 13:37:31 2002 +++ linux-2.4.19-7um-pm/arch/um/kernel/trap_user.c Fri Sep 27 13:10:40 2002 @@ -436,7 +436,7 @@ segfault_record[index].sp = SC_SP(context); segfault_record[index].is_user = regs->is_user; segv(SC_FAULT_ADDR(context), SC_IP(context), SC_FAULT_WRITE(context), - regs->is_user, context); + regs->is_user, SC_ERR(context), context); } extern int kern_timer_on; --- linux-2.4.19-7um-pm/arch/um/kernel/ioport_user.c.orig Fri Sep 27 18:54:29 2002 +++ linux-2.4.19-7um-pm/arch/um/kernel/ioport_user.c Fri Sep 27 18:08:47 2002 @@ -0,0 +1,38 @@ +/* + * [ioport_user.c] + * Released under the GPL + * + * Created: Sapan Bhatia 29.8.02 + * + */ + +#include + +extern unsigned char *uml_port_memory; + +inline unsigned char uml_inb(int p){ + return(uml_port_memory[p]); +} + +inline unsigned short uml_inw(int p){ + return((unsigned short) uml_port_memory[p]); +} + +inline unsigned int uml_inl(int p) { + return((unsigned long) uml_port_memory[p]); +} + +inline void uml_outb(unsigned char c, int p) { + uml_port_memory[p]=c; + return; +} + +inline void uml_outw(unsigned short w, int p) { + uml_port_memory[p]=w; + return; +} + +inline void uml_outl(unsigned short l, int p) { + uml_port_memory[p]=l; + return; +} --- linux-2.4.19-7um-pm/arch/um/kernel/Makefile.orig Fri Sep 27 13:35:43 2002 +++ linux-2.4.19-7um-pm/arch/um/kernel/Makefile Fri Sep 27 18:20:28 2002 @@ -6,7 +6,7 @@ sigio_user.o sigio_kern.o signal_kern.o signal_user.o smp.o \ syscall_kern.o syscall_user.o sysrq.o sys_call_table.o time.o \ time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o \ - umid.o user_syms.o user_util.o + umid.o user_syms.o user_util.o ioport_kern.o ioport_user.o ifeq ($(CONFIG_BLK_DEV_INITRD), y) obj-y += initrd_kern.o initrd_user.o --- linux-2.4.19-7um-pm/arch/um/kernel/trap_kern.c.orig Fri Sep 27 13:37:16 2002 +++ linux-2.4.19-7um-pm/arch/um/kernel/trap_kern.c Fri Sep 27 18:13:30 2002 @@ -25,7 +25,7 @@ extern int nsyscalls; unsigned long segv(unsigned long address, unsigned long ip, int is_write, - int is_user, void *sc) + int is_user, unsigned long fault_type, void *sc) { struct mm_struct *mm = current->mm; struct vm_area_struct *vma; @@ -36,6 +36,9 @@ pte_t *pte; unsigned long page; + if (fault_type == 0) + goto bad; + if((address >= start_vm) && (address < end_vm)){ flush_tlb_kernel_vm(); return(0); @@ -45,8 +48,9 @@ si.si_code = SEGV_MAPERR; down_read(&mm->mmap_sem); vma = find_vma(mm, address); + if(!vma) goto bad; - else if(vma->vm_start <= address) goto good_area; + else if(vma->vm_start <= address) goto good_area; else if(!(vma->vm_flags & VM_GROWSDOWN)) goto bad; else if(expand_stack(vma, address)) goto bad; @@ -91,9 +95,13 @@ up_read(&mm->mmap_sem); do_longjmp(catcher); } + /* + + cr2 is never NULL after the first fault else if(current->thread.fault_addr != NULL){ panic("fault_addr set but no fault catcher"); } + */ else if(arch_fixup(ip, sc)) return(0); --- linux-2.4.19-7um-pm/arch/um/sys-i386/ioport.c.orig Fri Sep 27 18:56:24 2002 +++ linux-2.4.19-7um-pm/arch/um/sys-i386/ioport.c Fri Sep 27 18:17:37 2002 @@ -0,0 +1,148 @@ +/* + * [arch/um/sysdep-i386/ioport.c] + * + * Created: Sapan Bhatia 02.09.2002 + * Released under the GPL + * + */ + +#include "sysdep/sc.h" +#include "asm/io.h" + +typedef unsigned char u8; + +struct PORTPARMS { + unsigned int op_size : 1; + unsigned int rep : 1; +}; + +extern int check_perm(unsigned long port); + +inline int check_prefix(u8 byte, struct PORTPARMS *parms) +{ + /* Prefixes pertinent here: + * F3H - for the string versions ins etc + * 66H - 32 bit operand + */ + + int ret=0; + if (byte == 0xF3) { + parms->rep = 1; + ret=1; + } + else if (byte == 0x66) { + parms->op_size = 1; + ret=1; + } + return ret; +} + +int launder_instruction(unsigned long pc, void *context) +{ + struct sigcontext *sc = context; + struct PORTPARMS parms; + + u8 *data8=(u8 *) pc; + + if (check_prefix(*data8, &parms)) { + data8++; + if (check_prefix(*data8, &parms)) + { + data8++; + } + } + + switch (*data8) { + case 0xe4: + data8++; /*fix this to touch only AL*/ + if (!check_perm(*data8)) + return 0; + else + { + SC_EAX(sc)&=0xffffff00; + SC_EAX(sc)|= uml_inb(*data8); + } + break; + case 0xe5: + data8++; + if (!check_perm(*data8)) + return 0; + else{ + if (!parms.op_size){ /*ax*/ + SC_EAX(sc)&=0xffff0000; + SC_EAX(sc)|= uml_inw(*data8); + } + else + SC_EAX(sc) = uml_inl(*data8); + } + break; + case 0xec: + data8++;/*al, dx*/ + if (!check_perm(SC_EDX(sc) & 0xffff)) + return 0; + else{ + SC_EAX(sc) &= 0xffffff00; + SC_EAX(sc)|= uml_inb(SC_EDX(sc) & 0xffff); + } + break; + case 0xed: + data8++; + if (!check_perm(SC_EDX(sc) & 0xffff)) + return 0; + else{ + if (!parms.op_size){ /*ax, dx*/ + SC_EAX(sc)&=0xffff0000; + SC_EAX(sc)|= uml_inw(SC_EDX(sc)); + } + else /*eax, dx*/ + SC_EAX(sc) = uml_inl(SC_EDX(sc)); + } + break; + case 0xe6: + data8++;/*al*/ + if (!check_perm(*data8)) + return 0; + else{ + uml_outb(SC_EAX(sc) & 0xff, *data8); /*src, dest*/ + } + break; + case 0xe7: + data8++; + if (!check_perm(*data8)) + return 0; + else{ + if (!parms.op_size){ + /*ax*/ + uml_outw(SC_EAX(sc) & 0xffff, *data8); + } + else + uml_outl(SC_EAX(sc), *data8); + } + break; + case 0xee: + data8++; /*al,dx*/ + if (!check_perm(SC_EDX(sc) & 0xffff)) + return 0; + else + uml_outb(SC_EAX(sc), SC_EDX(sc) & 0xffff); + break; + case 0xef: + data8++; + if (!check_perm(*data8)) + return 0; + else{ + if (!parms.op_size){ + /*ax,dx*/ + uml_outb(SC_EAX(sc) & 0xffff,SC_EDX(sc) & 0xffff); + } + else + /*eax,dx*/ + uml_outb(SC_EAX(sc),SC_EDX(sc) & 0xffff); + } + break; + default: /* Operation not supported */ + return 0; + } + + return((data8 - pc)? (unsigned int) data8 : 0); +} --- linux-2.4.19-7um-pm/arch/um/sys-i386/Makefile.orig Fri Sep 27 13:37:52 2002 +++ linux-2.4.19-7um-pm/arch/um/sys-i386/Makefile Fri Sep 27 16:02:37 2002 @@ -1,7 +1,7 @@ O_TARGET = sys.o obj-y = bugs.o checksum.o extable.o fault.o ksyms.o ldt.o old-checksum.o \ - ptrace.o ptrace_user.o semaphore.o sigcontext.o syscalls.o sysrq.o + ptrace.o ptrace_user.o semaphore.o sigcontext.o syscalls.o sysrq.o ioport.o export-objs = ksyms.o USER_OBJS = bugs.o ptrace_user.o sigcontext.o fault.o --- linux-2.4.19-7um-pm/arch/um/sys-i386/fault.c.orig Fri Sep 27 13:38:17 2002 +++ linux-2.4.19-7um-pm/arch/um/sys-i386/fault.c Fri Sep 27 18:19:25 2002 @@ -14,6 +14,12 @@ struct sigcontext *sc = sc_ptr; unsigned long fixup; + fixup = launder_instruction(address, sc_ptr); + if (fixup != 0){ + sc->eip = fixup; + return(1); + } + fixup = search_exception_table(address); if(fixup != 0){ sc->eip = fixup;