t->io_bitmap_max = bytes;
- /* Update the TSS: */
- memcpy(tss->io_bitmap, t->io_bitmap_ptr, bytes_updated);
- tss->io_bitmap_max = bytes;
- tss->io_bitmap_owner = ¤t->thread;
- tss->io_bitmap_base = IO_BITMAP_OFFSET;
+ /*
+ * 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();
return;
}
/*
- * The IO bitmap in the TSS needs updating: copy the relevant
- * range of the new task's IO bitmap. Normally this is 128 bytes
- * or less:
+ * 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, it true, does the
+ * real copy and restart the instruction. This will save us
+ * redundant copies when the currently switched task does not
+ * perform any I/O during its timeslice.
*/
- memcpy(tss->io_bitmap, next->io_bitmap_ptr,
- max(tss->io_bitmap_max, next->io_bitmap_max));
- tss->io_bitmap_max = next->io_bitmap_max;
- tss->io_bitmap_owner = next;
- tss->io_bitmap_base = IO_BITMAP_OFFSET;
+ tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY;
}
-
/*
* This special macro can be used to load a debugging register
*/
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 *thread = ¤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 &&
+ thread->io_bitmap_ptr) {
+ memcpy(tss->io_bitmap, thread->io_bitmap_ptr,
+ thread->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 (thread->io_bitmap_max < tss->io_bitmap_max)
+ memset((char *) tss->io_bitmap +
+ thread->io_bitmap_max, 0xff,
+ tss->io_bitmap_max - thread->io_bitmap_max);
+ tss->io_bitmap_max = thread->io_bitmap_max;
+ tss->io_bitmap_base = IO_BITMAP_OFFSET;
+ put_cpu();
+ return;
+ }
+ put_cpu();
+
if (regs->eflags & VM_MASK)
goto gp_in_vm86;
#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;