Why does iret from the page error handler generate interrupt 13 (general protection error) and error code 0x18?

I write the kernel myself, and after the first page interrupt handler, when IRET is executed, it causes interrupt 13 (general protection), and the error code is 0x18. I don’t know what’s wrong, the content stacked on the stack comes from the processor.

Here is the state of the register when the interrupt occurs, and the memory in which the registers are stored. In addition, the IRET is returned from the page error interrupt handler.

I am sure that% ESP is the same until IRET and interrupt.

enter image description here

enter image description here

+6
assembly x86 kernel
source share
2 answers

If the exception belongs to IRET itself, then most likely IRET will not be able to restore one of the saved segment registers, but the value (8 or 0x18, btw?) Is somehow wrong. This may be wrong because you never restarted the registry in protected mode or your handler did not set it to a bad value before doing IRET or something happened to GDT ...

EDIT . It can be seen from the image that the page error handler did not delete the exception code (value 4 at the address in ESP ) before performing IRET . And therefore, IRET interpreted 4 as a new value for EIP , 0x1000018 as a new value for CS and 0x23 as a new value for EFLAGS , whereas for these three registers it should use 0x1000018, 0x23 and 0x3206. Obviously, the data segment selector (which 0x1000018 is interpreted as after truncating to 0x0018) it cannot be loaded into CS , and this calls #GP (0x18).

+7
source share

Extension on Alexey:

When some interrupts (but not others) occur, they automatically push a 4-byte error code onto the stack. Page error is one of them.

This error code contains additional information about the interrupt.

Intel Programming Guide Volume Guide 3 - 325384-056US September 2015 Table 6-1. The column "Corrected and interrupted modes of protected mode" "Error code" tells us which interrupts click the error code and which do not.

38.9.2.2 "Page Error Error Codes" explains what the error means.

So you will need:

 pop %eax /* Do something with %eax */ iret 

Or if you want to ignore the error code:

 add $4, %esp iret 

For a minimal example, see the handler for this page and try to comment on pop .

Compare the above with the exception of the split error , which does not need to call the stack.

Please note that if you just int $14 , the extra byte will not be pressed: this will happen only with the actual exception.

An expert way to handle this is to push error code 0 on the stack for interrupts that don't do this to make things the same. The James Molloy tutorial does just that .

The Linux 4.2 kernel seems to do something similar. In arch / x86 / entry / entry64.S it models interrupts with has_error_code :

 trace_idtentry page_fault do_page_fault has_error_code=1 

and then uses it in the same file as:

 .ifeq \has_error_code pushq $-1 /* ORIG_RAX: no syscall to restart */ .endif 

which makes a click when has_error_code=0 .

A related question: Should I call an error code that has been pushed onto the stack with some exceptions before returning from the interrupt handler?

+2
source share

All Articles