diff options
author | Stephane Eranian <eranian@hpl.hp.com> | 2006-09-26 04:52:28 -0400 |
---|---|---|
committer | Andi Kleen <andi@basil.nowhere.org> | 2006-09-26 04:52:28 -0400 |
commit | d3a4f48d4866b8623ca9adde8ce4e5fde979c132 (patch) | |
tree | 04413a1f18c6f49688d6008b583b20a287920a0f /arch/x86_64 | |
parent | 2f766d16062d0147edff91be15de4a950667ca42 (diff) |
[PATCH] x86-64 TIF flags for debug regs and io bitmap in ctxsw
Hello,
Following my discussion with Andi. Here is a patch that introduces
two new TIF flags to simplify the context switch code in __switch_to().
The idea is to minimize the number of cache lines accessed in the common
case, i.e., when neither the debug registers nor the I/O bitmap are used.
This patch covers the x86-64 modifications. A patch for i386 follows.
Changelog:
- add TIF_DEBUG to track when debug registers are active
- add TIF_IO_BITMAP to track when I/O bitmap is used
- modify __switch_to() to use the new TIF flags
<signed-off-by>: eranian@hpl.hp.com
Signed-off-by: Andi Kleen <ak@suse.de>
Diffstat (limited to 'arch/x86_64')
-rw-r--r-- | arch/x86_64/ia32/ptrace32.c | 4 | ||||
-rw-r--r-- | arch/x86_64/kernel/ioport.c | 1 | ||||
-rw-r--r-- | arch/x86_64/kernel/process.c | 73 | ||||
-rw-r--r-- | arch/x86_64/kernel/ptrace.c | 8 |
4 files changed, 53 insertions, 33 deletions
diff --git a/arch/x86_64/ia32/ptrace32.c b/arch/x86_64/ia32/ptrace32.c index 659c0722f6b8..72bf92a9d375 100644 --- a/arch/x86_64/ia32/ptrace32.c +++ b/arch/x86_64/ia32/ptrace32.c | |||
@@ -117,6 +117,10 @@ static int putreg32(struct task_struct *child, unsigned regno, u32 val) | |||
117 | if ((0x5454 >> ((val >> (16 + 4*i)) & 0xf)) & 1) | 117 | if ((0x5454 >> ((val >> (16 + 4*i)) & 0xf)) & 1) |
118 | return -EIO; | 118 | return -EIO; |
119 | child->thread.debugreg7 = val; | 119 | child->thread.debugreg7 = val; |
120 | if (val) | ||
121 | set_tsk_thread_flag(child, TIF_DEBUG); | ||
122 | else | ||
123 | clear_tsk_thread_flag(child, TIF_DEBUG); | ||
120 | break; | 124 | break; |
121 | 125 | ||
122 | default: | 126 | default: |
diff --git a/arch/x86_64/kernel/ioport.c b/arch/x86_64/kernel/ioport.c index b81614970ecc..fe063d3cfe42 100644 --- a/arch/x86_64/kernel/ioport.c +++ b/arch/x86_64/kernel/ioport.c | |||
@@ -56,6 +56,7 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) | |||
56 | 56 | ||
57 | memset(bitmap, 0xff, IO_BITMAP_BYTES); | 57 | memset(bitmap, 0xff, IO_BITMAP_BYTES); |
58 | t->io_bitmap_ptr = bitmap; | 58 | t->io_bitmap_ptr = bitmap; |
59 | set_thread_flag(TIF_IO_BITMAP); | ||
59 | } | 60 | } |
60 | 61 | ||
61 | /* | 62 | /* |
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index bb6745d13b8f..6e0527635b4c 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c | |||
@@ -350,6 +350,7 @@ void exit_thread(void) | |||
350 | 350 | ||
351 | kfree(t->io_bitmap_ptr); | 351 | kfree(t->io_bitmap_ptr); |
352 | t->io_bitmap_ptr = NULL; | 352 | t->io_bitmap_ptr = NULL; |
353 | clear_thread_flag(TIF_IO_BITMAP); | ||
353 | /* | 354 | /* |
354 | * Careful, clear this in the TSS too: | 355 | * Careful, clear this in the TSS too: |
355 | */ | 356 | */ |
@@ -369,6 +370,7 @@ void flush_thread(void) | |||
369 | if (t->flags & _TIF_IA32) | 370 | if (t->flags & _TIF_IA32) |
370 | current_thread_info()->status |= TS_COMPAT; | 371 | current_thread_info()->status |= TS_COMPAT; |
371 | } | 372 | } |
373 | t->flags &= ~_TIF_DEBUG; | ||
372 | 374 | ||
373 | tsk->thread.debugreg0 = 0; | 375 | tsk->thread.debugreg0 = 0; |
374 | tsk->thread.debugreg1 = 0; | 376 | tsk->thread.debugreg1 = 0; |
@@ -461,7 +463,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long rsp, | |||
461 | asm("mov %%es,%0" : "=m" (p->thread.es)); | 463 | asm("mov %%es,%0" : "=m" (p->thread.es)); |
462 | asm("mov %%ds,%0" : "=m" (p->thread.ds)); | 464 | asm("mov %%ds,%0" : "=m" (p->thread.ds)); |
463 | 465 | ||
464 | if (unlikely(me->thread.io_bitmap_ptr != NULL)) { | 466 | if (unlikely(test_tsk_thread_flag(me, TIF_IO_BITMAP))) { |
465 | p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL); | 467 | p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL); |
466 | if (!p->thread.io_bitmap_ptr) { | 468 | if (!p->thread.io_bitmap_ptr) { |
467 | p->thread.io_bitmap_max = 0; | 469 | p->thread.io_bitmap_max = 0; |
@@ -469,6 +471,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long rsp, | |||
469 | } | 471 | } |
470 | memcpy(p->thread.io_bitmap_ptr, me->thread.io_bitmap_ptr, | 472 | memcpy(p->thread.io_bitmap_ptr, me->thread.io_bitmap_ptr, |
471 | IO_BITMAP_BYTES); | 473 | IO_BITMAP_BYTES); |
474 | set_tsk_thread_flag(p, TIF_IO_BITMAP); | ||
472 | } | 475 | } |
473 | 476 | ||
474 | /* | 477 | /* |
@@ -498,6 +501,40 @@ out: | |||
498 | */ | 501 | */ |
499 | #define loaddebug(thread,r) set_debugreg(thread->debugreg ## r, r) | 502 | #define loaddebug(thread,r) set_debugreg(thread->debugreg ## r, r) |
500 | 503 | ||
504 | static inline void __switch_to_xtra(struct task_struct *prev_p, | ||
505 | struct task_struct *next_p, | ||
506 | struct tss_struct *tss) | ||
507 | { | ||
508 | struct thread_struct *prev, *next; | ||
509 | |||
510 | prev = &prev_p->thread, | ||
511 | next = &next_p->thread; | ||
512 | |||
513 | if (test_tsk_thread_flag(next_p, TIF_DEBUG)) { | ||
514 | loaddebug(next, 0); | ||
515 | loaddebug(next, 1); | ||
516 | loaddebug(next, 2); | ||
517 | loaddebug(next, 3); | ||
518 | /* no 4 and 5 */ | ||
519 | loaddebug(next, 6); | ||
520 | loaddebug(next, 7); | ||
521 | } | ||
522 | |||
523 | if (test_tsk_thread_flag(next_p, TIF_IO_BITMAP)) { | ||
524 | /* | ||
525 | * Copy the relevant range of the IO bitmap. | ||
526 | * Normally this is 128 bytes or less: | ||
527 | */ | ||
528 | memcpy(tss->io_bitmap, next->io_bitmap_ptr, | ||
529 | max(prev->io_bitmap_max, next->io_bitmap_max)); | ||
530 | } else if (test_tsk_thread_flag(prev_p, TIF_IO_BITMAP)) { | ||
531 | /* | ||
532 | * Clear any possible leftover bits: | ||
533 | */ | ||
534 | memset(tss->io_bitmap, 0xff, prev->io_bitmap_max); | ||
535 | } | ||
536 | } | ||
537 | |||
501 | /* | 538 | /* |
502 | * switch_to(x,y) should switch tasks from x to y. | 539 | * switch_to(x,y) should switch tasks from x to y. |
503 | * | 540 | * |
@@ -586,37 +623,11 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) | |||
586 | task_stack_page(next_p) + THREAD_SIZE - PDA_STACKOFFSET); | 623 | task_stack_page(next_p) + THREAD_SIZE - PDA_STACKOFFSET); |
587 | 624 | ||
588 | /* | 625 | /* |
589 | * Now maybe reload the debug registers | 626 | * Now maybe reload the debug registers and handle I/O bitmaps |
590 | */ | 627 | */ |
591 | if (unlikely(next->debugreg7)) { | 628 | if (unlikely((task_thread_info(next_p)->flags & _TIF_WORK_CTXSW)) |
592 | loaddebug(next, 0); | 629 | || test_tsk_thread_flag(prev_p, TIF_IO_BITMAP)) |
593 | loaddebug(next, 1); | 630 | __switch_to_xtra(prev_p, next_p, tss); |
594 | loaddebug(next, 2); | ||
595 | loaddebug(next, 3); | ||
596 | /* no 4 and 5 */ | ||
597 | loaddebug(next, 6); | ||
598 | loaddebug(next, 7); | ||
599 | } | ||
600 | |||
601 | |||
602 | /* | ||
603 | * Handle the IO bitmap | ||
604 | */ | ||
605 | if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) { | ||
606 | if (next->io_bitmap_ptr) | ||
607 | /* | ||
608 | * Copy the relevant range of the IO bitmap. | ||
609 | * Normally this is 128 bytes or less: | ||
610 | */ | ||
611 | memcpy(tss->io_bitmap, next->io_bitmap_ptr, | ||
612 | max(prev->io_bitmap_max, next->io_bitmap_max)); | ||
613 | else { | ||
614 | /* | ||
615 | * Clear any possible leftover bits: | ||
616 | */ | ||
617 | memset(tss->io_bitmap, 0xff, prev->io_bitmap_max); | ||
618 | } | ||
619 | } | ||
620 | 631 | ||
621 | return prev_p; | 632 | return prev_p; |
622 | } | 633 | } |
diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c index 2d50024c9f30..d35ec1bc696a 100644 --- a/arch/x86_64/kernel/ptrace.c +++ b/arch/x86_64/kernel/ptrace.c | |||
@@ -420,9 +420,13 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
420 | if ((0x5554 >> ((data >> (16 + 4*i)) & 0xf)) & 1) | 420 | if ((0x5554 >> ((data >> (16 + 4*i)) & 0xf)) & 1) |
421 | break; | 421 | break; |
422 | if (i == 4) { | 422 | if (i == 4) { |
423 | child->thread.debugreg7 = data; | 423 | child->thread.debugreg7 = data; |
424 | if (data) | ||
425 | set_tsk_thread_flag(child, TIF_DEBUG); | ||
426 | else | ||
427 | clear_tsk_thread_flag(child, TIF_DEBUG); | ||
424 | ret = 0; | 428 | ret = 0; |
425 | } | 429 | } |
426 | break; | 430 | break; |
427 | } | 431 | } |
428 | break; | 432 | break; |