Re: intercepting an exception handler.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 5 Sep 2002 12:10:57 +0530
"Mohit Kalra" <kmohit@in.ibm.com> wrote:


>Now  my question  is :  can't we  skip the  generic handler  part and
>directly write the address of the c handler into the IDT table?  If i
>do this the  user program gives me  an OOPs.  In step 3  above, if we
>save the  low and high offsets  of the C handler,  things should work
>right?

I'll try to show why you obtain an oops.
For doing it I will suppose  an exception raises at some time. Suppose
CPU is  executing an istruction and  so %cs and  %eip identify logical
address of the instruction the current process will execute next.
When  CPU has  to  execute it,  CPU  control unity  checks whether  an
interrupt  or   an  excpetion   has  occurred  while   executing  last
instruction.

If so  there's a  first part  of exception handling  which is  done by
CPU control unit :

1- Determines the vector  which identifies exception (or interrupt) by
reading PIC's pins D0-D7 which are connected to data bus.

2- Reads  IDT i-th entry (through  %idtr register) and  there it finds
Segment Selector  (normally __KERNEL_CS)  from which it's  possible to
identify segment in which handler code will be found.

3-  Now we know  segment and  so we  can access  to the  right segment
through  GDT (register %gdtr).   Obviously Offset  field in  IDT entry
will allow to find handler code.

4-  Some  controls. First  of  all  if CPL  stored  in  the two  least
significant  bitsof  %cs is  lower  than  DPL  stored of  the  Segment
Descriptor  unity  control  raises  a "General  Protection"  exception
(because handler could NOT run with lower privileges than process that
raised  it). For  programmed exceptions  (for example  syscalls) unity
control checks  if CPL with DPL stored  in IDT entry. If  DPL is lower
than  CPL  unity  control  raises  a  "General  Protection"  exception
(because it  means there's an  attemp from User  Mode to access  a IDT
entry with DPL = 0 and so reserved to kernel).

5- If  a change of privilege  level is taking place  it's necessary to
save in  TSS %ss and %esp  and store in these  registers new prilivege
stack address.

6-  If  a  fault  occurred,  save  in %cs  and  %eip  address  of  the
instruction which  raised it so that  it can be  executed again (think
about a Page Fault for example).

7- Save %eflags, %cs and %eip in the stack.

8- If exception carries a hardware error code save it in the stack.

9- Load %cs and %eip with  values found in Segment Selector and Offset
fields in IDT entry thus realizing jump to handler.


Now let's see int3 just as example.

ENTRY(int3)
        pushl $0   <- this is done only if control unit didn'it. For
		      int3,  control unit doesn't do it so it's done
		      through an explicit pushl.(So in the stack you
		      have just one hardware error code)
        pushl $ SYMBOL_NAME(do_int3)
        jmp error_code

pushl  $0 is  pushing hardware  error  code and  then there's  pushing
SYMBOL_NAME(do_int3).

Let's see now error_code which  is used by all exceptions ("Device not
available" not).

error_code:
        pushl %ds
        pushl %eax
        xorl %eax,%eax
        pushl %ebp
        pushl %edi
        pushl %esi
        pushl %edx
        decl %eax # eax = -1
        pushl %ecx
        pushl %ebx 		<- All registers that might be used
				   by  C handler are  saved in the 
				   stack. The reason why  eax = -1 
				   is less clear but it is useful 
				   for system call handling.
        cld 			<- Clearing DF flag in %eflags for 
				   allowing autoincrements on %edi 
				   and %esi registers
        movl %es,%ecx
        movl ORIG_EAX(%esp), %esi # get the error code
			            (which is stored at offset
				     ORIG_EAX = 0x24 from %esp)

        movl ES(%esp), %edi # get the function address
				(which  is stored  at offset
					ES = 0x20 from %esp)
	movl %eax, ORIG_EAX(%esp)
        movl %ecx, ES(%esp)
        movl %esp,%edx
        pushl %esi 		# push the error code
        pushl %edx 		# push the pt_regs pointer
        movl $(__KERNEL_DS),%edx
        movl %edx,%ds
        movl %edx,%es
        GET_CURRENT(%ebx) <- current process descriptor stored in %ebx

        call *%edi <- here handler (whose address is in %esi) is called  
			but  look  at  the stack!
			In the  stack handler finds :
			-return address of the instruction to be
			 executed after C handler
			-error hardware code
			-SYMBOL_NAME
			-registers saved
			-the  stack address  of the saved User Mode
                         registers
			-error hardware code
					<---%esp points here

        addl $8,%esp 		<- the last two objects in stack are popped
        jmp ret_from_exception 	       and the ret_from_exception is called


ret_from_exception:
        movl EFLAGS(%esp),%eax # mix EFLAGS and CS
        movb CS(%esp),%al
        testl  $(VM_MASK | 3),%eax  #return to VM86 mode or non-supervisor?
        jne ret_from_sys_call
        jmp restore_all

        ALIGN

If it's not a system call simply restore all saved registers.

#define RESTORE_ALL \
        popl %ebx; \
        popl %ecx; \
        popl %edx; \
        popl %esi; \
        popl %edi; \
        popl %ebp; \
        popl %eax; \
	1: popl %ds; \
	2: popl %es; \
        addl $4,%esp; \
	3: iret; \

(it was not reported fixup code)

The  last 'function'  called is  iret.  The  first thing  it  makes is
resuming %cs, %eip and %eflags saved by control unit. 
If a error hardware  code was pushed, it has to be popped  before iret 
execution. 

After  this long talking  probably you  would be  able to  know what's
wrong in what you  did. If you put C handler address  in IDT entry the
first part (done by control unit)  will be done and so logical address
of next instruction to be executed is saved....but when you resume it?
If   you   insert   your   C   function   you   will   never   execute
ret_from_exception.  Then probably you could have other problems since
you're destroying hardware process context but you saved nothing....

So if you look well you could have a lot of problems doing as you did!


Regards,

Angelo Dell'Aera 'buffer' 
<buffer@users.sourceforge.net>
--
Kernelnewbies: Help each other learn about the Linux kernel.
Archive:       http://mail.nl.linux.org/kernelnewbies/
FAQ:           http://kernelnewbies.org/faq/


[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux