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/