All of lore.kernel.org
 help / color / mirror / Atom feed
* Handle kernel page faults using task gate
@ 2005-06-28 22:18 eliad lubovsky
  2005-06-29 13:09 ` Ingo Molnar
  0 siblings, 1 reply; 10+ messages in thread
From: eliad lubovsky @ 2005-06-28 22:18 UTC (permalink / raw)
  To: linux-kernel

I am trying to handle page faults exceptions in the kernel using the
task gate mechanism. I succeeded to transfer the execution to my page
fault handler using a new TSS and updates to the GDT and IDT tables
(similar to the double fault mechanism in 2.6). After handling the fault
and allocating the physical page I use the iret instruction to switch
back to the previous task. The problem is that I got a double fault with
the same address that cause the fault (although the physical page is
allocated and mapped). Any clues?

The new page fault TSS:
struct tss_struct pagefault_tss __cacheline_aligned = {
        .esp0           = STACK_START,
        .ss0            = __KERNEL_DS,
        .ldt            = 0,
        .io_bitmap_base = INVALID_IO_BITMAP_OFFSET,
                                                     
        .eip            = (unsigned long) pagefault_fn,
        .eflags         = X86_EFLAGS_SF|0x2,/* 0x2 bit is always set */
        .esp            = STACK_START,
        .es             = __USER_DS,
        .cs             = __KERNEL_CS,
        .ss             = __KERNEL_DS,
        .ds             = __USER_DS,
                                                      
        .__cr3          = __pa(swapper_pg_dir)
};



^ permalink raw reply	[flat|nested] 10+ messages in thread
* Re: Handle kernel page faults using task gate
@ 2005-06-30 16:53 Chuck Ebbert
  0 siblings, 0 replies; 10+ messages in thread
From: Chuck Ebbert @ 2005-06-30 16:53 UTC (permalink / raw)
  To: Ingo Molnar; +Cc: eliad lubovsky, linux-kernel

On Thu, 30 Jun 2005 at 09:11:01 +0200, Ingo Molnar wrote:

> * eliad lubovsky <eliadl@013.net> wrote:
> 
> > How do I clear the 'busy' bit?
> > I set my TSS descriptor with
> > __set_tss_desc(cpu, GDT_ENTRY_PAGE_FAULT_TSS, &pagefault_tss);
> 
> i suspect you have to clear the busy bit in the pagefault handler 
> itself. The CPU marks it as busy upon fault. I guess it would be OK to 
> just do the above __set_tss_desc() for _every_ pagefault, that too will 
> clear the busy bit, but you are probably better off just clearing that 
> bit manually:
> 
>     cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff;


  Tasks are not reentrant.  Clearing the busy bit could let a second
instance of the handler overwrite the stack of the current one.

  Since recursive page faults should never occur, this should be OK.
Each CPU needs its own TSS for concurrent fault handling on SMP, though.


--
Chuck

^ permalink raw reply	[flat|nested] 10+ messages in thread
* Re: Handle kernel page faults using task gate
@ 2005-06-30 16:53 Chuck Ebbert
  0 siblings, 0 replies; 10+ messages in thread
From: Chuck Ebbert @ 2005-06-30 16:53 UTC (permalink / raw)
  To: eliad lubovsky; +Cc: Ingo Molnar, linux-kernel

On Wed, 29 Jun 2005 at 18:43:47 +0300, eliad lubovsky wrote:

> my page fault handler:
> static void pagefault_fn(void)
> {
>   unsigned int address, aligned_page_fault_address;
>   struct vm_struct *area;
> 
>   /* retrieve the page fault address */ 
>   __asm__("movl %%cr2,%0":"=r" (address));
> 
>   aligned_page_fault_address = ((address+PAGE_SIZE)&(~(4096-1)));
> 
>   area = find_vm_area((void*)(aligned_page_fault_address));
> 
>   /* allocate a new physical page, expand the stack size */
>   expend_stack_size(area);
> 
>  // asm ("pushf; orl  $0x00004000, (%esp); popf; iret"); /* sets NT   */
>  // asm ("pushf; andl $0xffffbfff, (%esp); popf; iret"); /* clears NT */
>  asm ("iret");
> }


 That will work exactly once. :(

 On the next fault, control wil be transferred to the instruction after
the iret.  It needs to be like this:

======================

static void pagefault_fn(void) {
        unsigned int address, aligned_page_fault_address;
        struct vm_struct *area;

        /* put one-time initialization code here */

        goto handle_fault;

return_from_fault:
        asm("iret");

handle_fault:
        aligned_page_fault_address = ((address+PAGE_SIZE)&(~(4096-1)));
        area = find_vm_area((void*)(aligned_page_fault_address));

        /* allocate a new physical page, expand the stack size */
        expend_stack_size(area);

        goto return_from_fault;
}

======================

 (You also need a private stack to hold the local vars for each TSS.)

--
Chuck

^ permalink raw reply	[flat|nested] 10+ messages in thread
* Re: Handle kernel page faults using task gate
@ 2005-07-01  4:40 Chuck Ebbert
  0 siblings, 0 replies; 10+ messages in thread
From: Chuck Ebbert @ 2005-07-01  4:40 UTC (permalink / raw)
  To: eliad lubovsky; +Cc: linux-kernel, Ingo Molnar

On Fri, 01 Jul 2005 at 04:23:08 +0300, eliad lubovsky wrote:

> attached a patch, it may be more clear to understand what I have done.

Ouch.

Are you doublefaulting before you reach the handler?


--
Chuck

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2005-07-01  4:44 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-06-28 22:18 Handle kernel page faults using task gate eliad lubovsky
2005-06-29 13:09 ` Ingo Molnar
2005-06-29 15:43   ` eliad lubovsky
2005-06-29 19:27   ` Ingo Molnar
2005-06-30  6:57     ` eliad lubovsky
2005-06-30  7:11       ` Ingo Molnar
2005-07-01  1:23         ` eliad lubovsky
  -- strict thread matches above, loose matches on Subject: below --
2005-06-30 16:53 Chuck Ebbert
2005-06-30 16:53 Chuck Ebbert
2005-07-01  4:40 Chuck Ebbert

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.