|
205 | 205 | #define CS_FROM_ENTRY_STACK (1 << 31)
|
206 | 206 | #define CS_FROM_USER_CR3 (1 << 30)
|
207 | 207 | #define CS_FROM_KERNEL (1 << 29)
|
| 208 | +#define CS_FROM_ESPFIX (1 << 28) |
208 | 209 |
|
209 | 210 | .macro FIXUP_FRAME
|
210 | 211 | /*
|
|
342 | 343 | .endif
|
343 | 344 | .endm
|
344 | 345 |
|
345 |
| -.macro SAVE_ALL_NMI cr3_reg:req |
346 |
| - SAVE_ALL |
| 346 | +.macro SAVE_ALL_NMI cr3_reg:req unwind_espfix=0 |
| 347 | + SAVE_ALL unwind_espfix=\unwind_espfix |
347 | 348 |
|
348 | 349 | BUG_IF_WRONG_CR3
|
349 | 350 |
|
@@ -1526,6 +1527,10 @@ ENTRY(nmi)
|
1526 | 1527 | ASM_CLAC
|
1527 | 1528 |
|
1528 | 1529 | #ifdef CONFIG_X86_ESPFIX32
|
| 1530 | + /* |
| 1531 | + * ESPFIX_SS is only ever set on the return to user path |
| 1532 | + * after we've switched to the entry stack. |
| 1533 | + */ |
1529 | 1534 | pushl %eax
|
1530 | 1535 | movl %ss, %eax
|
1531 | 1536 | cmpw $__ESPFIX_SS, %ax
|
@@ -1561,30 +1566,54 @@ ENTRY(nmi)
|
1561 | 1566 | movl %ebx, %esp
|
1562 | 1567 |
|
1563 | 1568 | .Lnmi_return:
|
| 1569 | +#ifdef CONFIG_X86_ESPFIX32 |
| 1570 | + testl $CS_FROM_ESPFIX, PT_CS(%esp) |
| 1571 | + jnz .Lnmi_from_espfix |
| 1572 | +#endif |
| 1573 | + |
1564 | 1574 | CHECK_AND_APPLY_ESPFIX
|
1565 | 1575 | RESTORE_ALL_NMI cr3_reg=%edi pop=4
|
1566 | 1576 | jmp .Lirq_return
|
1567 | 1577 |
|
1568 | 1578 | #ifdef CONFIG_X86_ESPFIX32
|
1569 | 1579 | .Lnmi_espfix_stack:
|
1570 | 1580 | /*
|
1571 |
| - * create the pointer to lss back |
| 1581 | + * Create the pointer to LSS back |
1572 | 1582 | */
|
1573 | 1583 | pushl %ss
|
1574 | 1584 | pushl %esp
|
1575 | 1585 | addl $4, (%esp)
|
1576 |
| - /* copy the iret frame of 12 bytes */ |
1577 |
| - .rept 3 |
1578 |
| - pushl 16(%esp) |
1579 |
| - .endr |
1580 |
| - pushl %eax |
1581 |
| - SAVE_ALL_NMI cr3_reg=%edi |
| 1586 | + |
| 1587 | + /* Copy the (short) IRET frame */ |
| 1588 | + pushl 4*4(%esp) # flags |
| 1589 | + pushl 4*4(%esp) # cs |
| 1590 | + pushl 4*4(%esp) # ip |
| 1591 | + |
| 1592 | + pushl %eax # orig_ax |
| 1593 | + |
| 1594 | + SAVE_ALL_NMI cr3_reg=%edi unwind_espfix=1 |
1582 | 1595 | ENCODE_FRAME_POINTER
|
1583 |
| - FIXUP_ESPFIX_STACK # %eax == %esp |
| 1596 | + |
| 1597 | + /* clear CS_FROM_KERNEL, set CS_FROM_ESPFIX */ |
| 1598 | + xorl $(CS_FROM_ESPFIX | CS_FROM_KERNEL), PT_CS(%esp) |
| 1599 | + |
1584 | 1600 | xorl %edx, %edx # zero error code
|
1585 |
| - call do_nmi |
| 1601 | + movl %esp, %eax # pt_regs pointer |
| 1602 | + jmp .Lnmi_from_sysenter_stack |
| 1603 | + |
| 1604 | +.Lnmi_from_espfix: |
1586 | 1605 | RESTORE_ALL_NMI cr3_reg=%edi
|
1587 |
| - lss 12+4(%esp), %esp # back to espfix stack |
| 1606 | + /* |
| 1607 | + * Because we cleared CS_FROM_KERNEL, IRET_FRAME 'forgot' to |
| 1608 | + * fix up the gap and long frame: |
| 1609 | + * |
| 1610 | + * 3 - original frame (exception) |
| 1611 | + * 2 - ESPFIX block (above) |
| 1612 | + * 6 - gap (FIXUP_FRAME) |
| 1613 | + * 5 - long frame (FIXUP_FRAME) |
| 1614 | + * 1 - orig_ax |
| 1615 | + */ |
| 1616 | + lss (1+5+6)*4(%esp), %esp # back to espfix stack |
1588 | 1617 | jmp .Lirq_return
|
1589 | 1618 | #endif
|
1590 | 1619 | END(nmi)
|
|
0 commit comments