Index: arch/i386/kernel/ioport.c =================================================================== RCS file: /usr/src/bkcvs/linux-2.5/arch/i386/kernel/ioport.c,v retrieving revision 1.13 diff -u -r1.13 ioport.c --- a/arch/i386/kernel/ioport.c 23 Aug 2004 19:42:10 -0000 1.13 +++ b/arch/i386/kernel/ioport.c 3 Sep 2004 21:05:09 -0000 @@ -105,8 +105,11 @@ t->io_bitmap_max = bytes; - /* Update the TSS: */ - memcpy(tss->io_bitmap, t->io_bitmap_ptr, bytes_updated); + /* + * Sets the lazy trigger so that the next I/O operation will + * reload the correct bitmap. + */ + tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY; put_cpu(); Index: arch/i386/kernel/process.c =================================================================== RCS file: /usr/src/bkcvs/linux-2.5/arch/i386/kernel/process.c,v retrieving revision 1.86 diff -u -r1.86 process.c --- a/arch/i386/kernel/process.c 24 Aug 2004 18:27:55 -0000 1.86 +++ b/arch/i386/kernel/process.c 3 Sep 2004 21:07:56 -0000 @@ -556,20 +556,17 @@ loaddebug(next, 7); } - if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) { - if (next->io_bitmap_ptr) - /* - * Copy the relevant range of the IO bitmap. - * Normally this is 128 bytes or less: - */ - memcpy(tss->io_bitmap, next->io_bitmap_ptr, - max(prev->io_bitmap_max, next->io_bitmap_max)); - else - /* - * Clear any possible leftover bits: - */ - memset(tss->io_bitmap, 0xff, prev->io_bitmap_max); - } + /* + * Lazy TSS's I/O bitmap copy. We set an invalid offset here and + * we let the task to get a GPF in case an I/O instruction is performed. + * The handler of the GPF will verify that the faulting task has a valid + * I/O bitmap and, if true, does the real copy and restart the instruction. + * This will save us for redoundant copies when the currently switched task + * does not perform any I/O during its timeslice. + */ + tss->io_bitmap_base = next->io_bitmap_ptr ? INVALID_IO_BITMAP_OFFSET_LAZY: + INVALID_IO_BITMAP_OFFSET; + return prev_p; } Index: arch/i386/kernel/traps.c =================================================================== RCS file: /usr/src/bkcvs/linux-2.5/arch/i386/kernel/traps.c,v retrieving revision 1.83 diff -u -r1.83 traps.c --- a/arch/i386/kernel/traps.c 31 Aug 2004 17:32:21 -0000 1.83 +++ b/arch/i386/kernel/traps.c 3 Sep 2004 21:05:09 -0000 @@ -479,6 +479,35 @@ asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) { + int cpu = get_cpu(); + struct tss_struct *tss = &per_cpu(init_tss, cpu); + struct thread_struct *tsk_th = ¤t->thread; + + /* + * Perform the lazy TSS's I/O bitmap copy. If the TSS has an + * invalid offset set (the LAZY one) and the faulting thread has + * a valid I/O bitmap pointer, we copy the I/O bitmap in the TSS + * and we set the offset field correctly. Then we let the CPU to + * restart the faulting instruction. + */ + if (tss->io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY && + tsk_th->io_bitmap_ptr) { + memcpy(tss->io_bitmap, tsk_th->io_bitmap_ptr, + tsk_th->io_bitmap_max); + /* + * If the previously set map was extending to higher ports + * than the current one, pad extra space with 0xff (no access). + */ + if (tsk_th->io_bitmap_max < tss->map_size) + memset((char *) tss->io_bitmap + tsk_th->io_bitmap_max, 0xff, + tss->map_size - tsk_th->io_bitmap_max); + tss->map_size = tsk_th->io_bitmap_max; + tss->io_bitmap_base = IO_BITMAP_OFFSET; + put_cpu(); + return; + } + put_cpu(); + if (regs->eflags & VM_MASK) goto gp_in_vm86; Index: include/asm-i386/processor.h =================================================================== RCS file: /usr/src/bkcvs/linux-2.5/include/asm-i386/processor.h,v retrieving revision 1.72 diff -u -r1.72 processor.h --- a/include/asm-i386/processor.h 24 Aug 2004 18:11:50 -0000 1.72 +++ b/include/asm-i386/processor.h 3 Sep 2004 21:05:09 -0000 @@ -307,6 +307,7 @@ #define IO_BITMAP_LONGS (IO_BITMAP_BYTES/sizeof(long)) #define IO_BITMAP_OFFSET offsetof(struct tss_struct,io_bitmap) #define INVALID_IO_BITMAP_OFFSET 0x8000 +#define INVALID_IO_BITMAP_OFFSET_LAZY 0x9000 struct i387_fsave_struct { long cwd; @@ -392,9 +393,13 @@ */ unsigned long io_bitmap[IO_BITMAP_LONGS + 1]; /* + * Effective size of the currently set I/O bitmap. + */ + unsigned long map_size; + /* * pads the TSS to be cacheline-aligned (size is 0x100) */ - unsigned long __cacheline_filler[37]; + unsigned long __cacheline_filler[36]; /* * .. and then another 0x100 bytes for emergency kernel stack */