Exceptions: Difference between revisions

m
Discovered this the hard way
[unchecked revision][unchecked revision]
No edit summary
m (Discovered this the hard way)
 
(38 intermediate revisions by 25 users not shown)
Line 3:
|}
 
'''Exceptions''', as described in this article, are a type of [[interrupt]] generated by the CPU when an 'error' occurs. Some exceptions are not really errors in most cases, such as [[#Page Fault|page faults]].
 
Exceptions are classified as:
Line 9:
* '''Traps''': Traps are reported immediately after the execution of the trapping instruction.
* '''Aborts''': Some severe unrecoverable error.
 
Some exceptions will push a 32-bit "error code" on to the top of the stack, which provides additional information about the error. This value must be pulled from the stack before returning control back to the currently running program (i.e. before calling IRET). In [[Long Mode]], the error code is padded with zeros to form a 64-bit push, so that it can be popped like any other value.
 
{| {{wikitable}}
Line 17 ⟶ 19:
! Error code?
|-
! [[#Divide-by-zeroDivision Error|Divide-by-zeroDivision Error]]
| 0 (0x0)
| Fault
| #DE
Line 24 ⟶ 26:
|-
! [[#Debug|Debug]]
| 1 (0x1)
| Fault/Trap
| #DB
| No
|-
! [[#Non-maskable Maskable Interrupt|Non-maskable Interrupt]]
| 2 (0x2)
| Interrupt
| #NMI-
| No
|-
! [[#Breakpoint|Breakpoint]]
| 3 (0x3)
| Trap
| #BP
Line 42 ⟶ 44:
|-
! [[#Overflow|Overflow]]
| 4 (0x4)
| Trap
| #OF
Line 48 ⟶ 50:
|-
! [[#Bound Range Exceeded|Bound Range Exceeded]]
| 5 (0x5)
| Fault
| #BR
Line 54 ⟶ 56:
|-
! [[#Invalid Opcode|Invalid Opcode]]
| 6 (0x6)
| Fault
| #UD
Line 60 ⟶ 62:
|-
! [[#Device Not Available|Device Not Available]]
| 7 (0x7)
| Fault
| #NM
Line 66 ⟶ 68:
|-
! [[#Double Fault|Double Fault]]
| 8 (0x8)
| Abort
| #NMDF
| Yes (Zero)
|-
! <strike>[[#Coprocessor Segment Overrun|Coprocessor Segment Overrun]]</strike>
| 9 (0x9)
| Fault
| -
Line 78 ⟶ 80:
|-
! [[#Invalid TSS|Invalid TSS]]
| 10 (0xA)
| Fault
| #TS
Line 84 ⟶ 86:
|-
! [[#Segment Not Present|Segment Not Present]]
| 11 (0xB)
| Fault
| #NP
Line 90 ⟶ 92:
|-
! [[#Stack-Segment Fault|Stack-Segment Fault]]
| 12 (0xC)
| Fault
| #SS
Line 96 ⟶ 98:
|-
! [[#General Protection Fault|General Protection Fault]]
| 13 (0xD)
| Fault
| #SSGP
| Yes
|-
! [[#Page Fault|Page Fault]]
| 14 (0xE)
| Fault
| #SSPF
| Yes
|-
! Reserved
| 15 (0xF)
| -
| -
Line 114 ⟶ 116:
|-
! [[#x87 Floating-Point Exception|x87 Floating-Point Exception]]
| 16 (0x10)
| Fault
| #MF
Line 120 ⟶ 122:
|-
! [[#Alignment Check|Alignment Check]]
| 17 (0x11)
| Fault
| #AC
Line 126 ⟶ 128:
|-
! [[#Machine Check|Machine Check]]
| 18 (0x12)
| Abort
| #MC
Line 132 ⟶ 134:
|-
! [[#SIMD Floating-Point Exception|SIMD Floating-Point Exception]]
| 19 (0x13)
| Fault
| #XM/#XF
| No
|-
! [[#Virtualization Exception| Virtualization Exception]]
| 20 (0x14)
| Fault
| #VE
| No
|-
! [[#Control Protection Exception|Control Protection Exception]]
| 21 (0x15)
| Fault
| #CP
| Yes
|-
! Reserved
| 22-27 (0x16-0x1B)
| 20-29
| -
| -
| No
|-
! [[#Hypervisor Injection Exception|Hypervisor Injection Exception]]
| 28 (0x1C)
| Fault
| #HV
| No
|-
! [[#VMM Communication Exception|VMM Communication Exception]]
| 29 (0x1D)
| Fault
| #VC
| Yes
|-
! [[#Security Exception|Security Exception]]
| 30 (0x1E)
| -Fault
| #SX
| NoYes
|-
! Reserved
| 31 (0x1F)
| -
| -
Line 159 ⟶ 185:
| -
| -
| No
|-
! <strike>[[#FPU Error Interrupt|FPU Error Interrupt]]</strike>
| IRQ 13
| Interrupt
| #FERR
| No
|}
Line 166 ⟶ 198:
=== Faults ===
 
==== Divide-by-zeroDivision Error ====
The '''Divide-by-zeroDivision Error''' occurs when dividing any number by 0 using the DIV or IDIV instruction., Manyor OSwhen developersthe usedivision thisresult exceptionis totoo testlarge whetherto theirbe exceptionrepresented handlingin codethe worksdestination. ThisSince exceptiona mayfaulting alsoDIV occuror whenIDIV the resultinstruction is toovery largeeasy to beinsert representedanywhere in the destinationcode, many OS developers use this exception to test whether their exception handling code works.
 
The saved instruction pointer points to the DIV or IDIV instruction which caused the exception.
Line 177 ⟶ 209:
 
==== Invalid Opcode ====
The Invalid Opcode exception occurs when the processor tries to execute an invalid or undefined opcode, or an instruction with invalid prefixes. It also occurs in other cases, such as:
* The instruction length exceeds 15 bytes, but this only occurs with redundant prefixes.
* The instruction tries to access a non-existent control register (for example, <code>mov cr6, eax</code>).
* The UD instruction is executed.
 
The saved instruction pointer points to the instruction which caused the exception.
 
==== Device Not Available ====
The Device Not Available exception occurs when an FPU instruction is attempted but there is no FPU. This is not likely, as modern processors have built-in FPUs. However, there are flags in the CR0 register that disable the FPU/MMX/SSE instructions, causing this exception when they are attempted. This feature is useful because the operating system can detect when a user program uses the FPU or XMM registers and then save/restore them appropriately when multitasking.
The Device Not Available exception mainly occurs when working with x87 instructions.
 
The saved instruction pointer points to the instruction that caused the exception.
 
==== Invalid TSS ====
An Invalid TSS exception occurs when an invalid segment selector is referenced as part of a task whichswitch, or as a result of a control transfer through a gate descriptor, which results in an invalid stack-segment reference using an SS selector in the TSS.
 
When the exception occurred before loading the segment selectors from the TSS, the saved instruction pointer points to the instruction which caused the exception. Otherwise, and this is more common, it points to the first instruction in the new task.
 
'''Error code:''' The Invalid TSS exception sets an error code, which is a [[#Selector Error Code|selector index]].
===== Error code =====
The Invalid TSS exception sets an error code, which is either a TSS selector index, LDT selector index or segment selector index.
 
==== Segment Not Present ====
The Segment Not Present exception occurs when trying to load a segment or gate which has it'sits `Present-` bit set to 0.
However wenwhen loading a stack-segment selector which references a descriptor which is not present, a [[#Stack-Segment Fault|Stack-Segment Fault]] occurs.
 
If the exception happens during a hardware task switch, the segment values should not be relied upon by the handler. That is, the handler should check them before trying to resume the new task. There are three ways to do this, according to the Intel documentation.
 
The saved instruction pointer points to the instruction which caused the exception.
 
'''Error code:''' The Segment Not Present exception sets an error code, which is the [[#Selector Error Code|segment selector index]] of the segment descriptor which caused the exception.
===== Error code =====
The Segment Not Present exception sets an error code, which is the segment selector index of the segment descriptor which caused the exception.
 
==== Stack-Segment Fault ====
Line 209 ⟶ 244:
* When the stack-limit check fails.
 
If the exception happens during a hardware task switch, the segment values should not be relied upon by the handler. That is, the handler should check them before trying to resume the new task. There are three ways to do this, according to the Intel documentation.
The saved instruction pointer points to the instruction which caused the exception.
 
The saved instruction pointer points to the instruction which caused the exception, unless the fault occurred because of loading a non-present stack segment during a hardware task switch, in which case it points to the next instruction of the new task.
===== Error code =====
 
The Stack-Segment Fault sets an error code, which is stack segment selector index when a non-present segment descriptor was referenced. Otherwise, 0.
'''Error code:''' The Stack-Segment Fault sets an error code, which is the stack [[#Selector Error Code|segment selector index]] when a non-present segment descriptor was referenced or a limit check failed during a hardware task switch. Otherwise (for present segments and already in use), the error code is 0.
 
==== General Protection Fault ====
Line 218 ⟶ 254:
* Segment error (privilege, type, limit, read/write rights).
* Executing a privileged instruction while CPL != 0.
* Writing a 1 in a reserved register field or writing invalid value combinations (e.g. CR0 with PE=0 and PG=1).
* Referencing or accessing a null-descriptor.
* Accessing a memory address with bits 48-63 not matching bit 47 (e.g. 0x_0000_8000_0000_0000 instead of 0x_ffff_8000_0000_0000) in 64 bit mode.
 
The saved instruction pointer points to the instruction which caused the exception.
 
'''Error code:''' The General Protection Fault sets an error code, which is the [[#Selector Error Code|segment selector index]] when the exception is segment related. Otherwise, 0.
===== Error code =====
The General Protection Fault sets an error code, which is stack segment selector index when the exception is segment related. Otherwise, 0.
 
==== Page Fault ====
{{main|Page fault}}
A Page Fault occurs when:
* A [[Paging|page directory or table]] entry is not present in physical memory.
Line 240 ⟶ 275:
 
<pre>
31 15 4 0
+---+-- --+---+-----+---+-- --+---+----+----+---+---+---+---+---+
| Reserved | SGX | Reserved | SS | PK | I | R | U | W | P |
+---+-- --+---+-----+---+-- --+---+----+----+---+---+---+---+---+
</pre>
 
Line 251 ⟶ 286:
! Name
! Description
|-valign="top"
|-
!align="left"| P
! P
| 1 bit
| Present
| When set, the page fault was caused by a page-protection violation. When not set, it was caused by a non-present page.
|-valign="top"
|-
!align="left"| W
! W
| 1 bit
| Write
| When set, the page fault was caused by a page write access. When not set, it was caused by a page read access.
|-valign="top"
|-
!align="left"| U
! U
| 1 bit
| User
| When set, the page fault was caused while CPL = 3. This does not necessarily mean that the page fault was a privilege violation.
|-valign="top"
|-
!align="left"| R
! R
| 1 bit
| Reserved write
| When set, one or more page directory entries contain reserved bits which are set to 1. This only applies when the PSE or PAE flags in CR4 are set to 1.
| When set, the page fault was caused by reading a 1 in a reserved field.
|-valign="top"
|-
!align="left"| I
! I
| 1 bit
| Instruction Fetch
| When set, the page fault was caused by an instruction fetch. This only applies when the No-Execute bit is supported and enabled.
|-valign="top"
!align="left"| PK
| 1 bit
| Protection key
| When set, the page fault was caused by a protection-key violation. The PKRU register (for user-mode accesses) or PKRS MSR (for supervisor-mode accesses) specifies the protection key rights.
|-valign="top"
!align="left"| SS
| 1 bit
| Shadow stack
| When set, the page fault was caused by a shadow stack access.
|-valign="top"
!align="left | SGX
| 1 bit
| Software Guard Extensions
| When set, the fault was due to an [https://en.wikipedia.org/wiki/Software_Guard_Extensions SGX violation]. The fault is unrelated to ordinary paging.
|}
 
Line 287 ⟶ 337:
The saved instruction pointer points to the instruction which is about to be executed when the exception occurred. The x87 instruction pointer register contains the address of the last instruction which caused the exception.
 
'''Error Code:''' The exception does not push an error code. However, exception information is available in the x87 status word register.
===== Error Code ====
The exception does not set an error code. However, exception information is available in the x87 status word register.
 
==== Alignment Check ====
Line 298 ⟶ 347:
 
==== SIMD Floating-Point Exception ====
The SIMD Floating-Point Exception occurs when an unmasked 128-bit media floating-point exception occurs and the [[CR4|CR4.OSXMMEXCPT]] bit is set to 1. If the OSXMMEXCPT flag is not set, then SIMD floating-point exceptions will cause an Undefined Opcode exception instead of this.
 
The saved instruction pointer points to the instruction which caused the exception.
 
'''Error Code:''' The exception does not push an error code. However, exception information is available in the MXCSR register.
===== Error Code ====
The exception does not set an error code. However, exception information is available in the MXCSR register.
 
=== Traps ===
Line 318 ⟶ 366:
When the exception is a fault, the saved instruction pointer points to the instruction which caused the exception. When the exception is a trap, the saved instruction pointer points to the instruction after the instruction which caused the exception.
 
'''Error code:''' The Debug exception does not set an error code. However, exception information is provided in the debug registers ([[CPU_Registers_x86#Debug_Registers]]).
===== Error code =====
The Debug exception does not set an error code. However, exception information is provided in the debug registers.
 
==== Breakpoint ====
Line 327 ⟶ 374:
 
==== Overflow ====
An Overflow exception is raised when the INTO instruction is executed while the overflow bit in [[RFLAGS]] is set to 1.
 
The saved instruction pointer points to the instruction after the INTO instruction.
Line 333 ⟶ 380:
=== Aborts ===
==== Double Fault ====
The most common reason aA Double Fault occurs, is when an exception is unhandled or when an exception occurs withinwhile the CPU is trying to call an exception handler. Normally, two exception at the same time are handled one after another, but in some cases that is not possible. For example, if a page fault occurs, but the exception handler is located in a not-present page, two page faults would occur and neither can be handled. A double fault would occur.
 
A double fault will always generate an error code with a value of zero.
The saved instruction pointer is undefined.
 
The saved instruction pointer is undefined. A double fault cannot be recovered. The faulting process must be terminated.
 
In several starting hobby OSes, a double fault is also quite often a [[I_Cant_Get_Interrupts_Working|misdiagnosed IRQ0]] in the cases where the [[PIC]] hasn't been reprogrammed yet.
 
==== Machine Check ====
The Machine Check exception is model specific and processor implementations are not required to support it. It uses [[Model Specific Registers|model-specific registers]] to provide error information. It is disabled by default. To enable it, set the [[CR4|CR4.MCE]] bit to 1.
 
Machine check exceptions occur when the processor detects internal errors, such as bad memory, bus errors, cache errors, etc.
 
The value of the saved instruction pointer depends on the implementation and the exception.
Line 344 ⟶ 397:
==== Triple Fault ====
{{main|Triple Fault}}
The Triple Fault is not really an exception, because it does not have an associated vector number. Nonetheless, a triple fault occurs when an exception is generated when attempt to call the double fault exception handler. It results in the processor resetting. See the main article for more information about possible causes and how to avoid them.
{{stub}}
 
== Selector Error Code ==
<pre>
31 16 15 3 2 1 0
+---+-- --+---+---+-- --+---+---+---+---+
| Reserved | Index | Tbl | E |
+---+-- --+---+---+-- --+---+---+---+---+
</pre>
 
{| {{wikitable}}
!
! Length
! Name
! Description
|-valign="top"
!align="left"| E
| 1 bit
| External
| When set, the exception originated externally to the processor.
|-valign="top"
!align="left"| Tbl
| 2 bits
| IDT/GDT/LDT table
| This is one of the following values:
{| {{wikitable}}
! Value
! Description
|-
! 0b00
| The Selector Index references a descriptor in the GDT.
|-
! 0b01
| The Selector Index references a descriptor in the IDT.
|-
! 0b10
| The Selector Index references a descriptor in the LDT.
|-
! 0b11
| The Selector Index references a descriptor in the IDT.
|}
 
|-valign="top"
!align="left"| Index
| 13 bits
| Selector Index
| The index in the GDT, IDT or LDT.
|}
 
=== Legacy ===
The following exceptions happen on outdated technology, but are no longer used or should be avoided. They apply mostly to the intel 386 and earlier, and might include CPUs from other manufacturers around the same time.
 
====FPU Error Interrupt====
In the old days, the floating point unit was a dedicated chip that could be attached to the processor. It lacked direct wiring of FPU errors to the processor, so instead it used [[PIC|IRQ 13]], allowing the CPU to deal with errors at its own leasure. When the 486 was developed and multiprocessor support was added, the [[FPU]] was embedded on die and a global interrupt for FPUs became undesirable, instead getting an option for direct error handling. By default, this method is not enabled at boot for backwards compatibility, but an OS should update the settings accordingly.
 
====Coprocessor Segment Overrun====
When the FPU was still external to the processor, it had separate segment checking in protected mode. Since the 486 this is handled by a [[#General Protection Fault|GPF]] instead like it already did with non-FPU memory accesses.
 
== See Also ==
 
=== External Links ===
* [http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-manual-325462.pdf Intel® 64 and IA-32 Architectures Software Developer's Manual], Volume 3 (System Programming Guide), Chapter 6 (Interrupt and exception handling)
 
[[Category:X86]]
=== Misc ===
[[Category:Interrupts]]
==== Non-maskable Interrupt ====
[[de:Exception]]
{{stub}}
Anonymous user