diff options
author | Jeremy Fitzhardinge <jeremy@goop.org> | 2008-06-25 00:19:28 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-07-08 07:15:52 -0400 |
commit | 2be29982a08009c731307f4a39053b70ac4700da (patch) | |
tree | f01fcf847f36b9da5cd87cefa7ee6c13d193077d /include/asm-x86/paravirt.h | |
parent | c7245da6ae7e5208504ff027c4e0eec69b788651 (diff) |
x86/paravirt: add sysret/sysexit pvops for returning to 32-bit compatibility userspace
In a 64-bit system, we need separate sysret/sysexit operations to
return to a 32-bit userspace.
Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citirx.com>
Cc: xen-devel <xen-devel@lists.xensource.com>
Cc: Stephen Tweedie <sct@redhat.com>
Cc: Eduardo Habkost <ehabkost@redhat.com>
Cc: Mark McLoughlin <markmc@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'include/asm-x86/paravirt.h')
-rw-r--r-- | include/asm-x86/paravirt.h | 56 |
1 files changed, 45 insertions, 11 deletions
diff --git a/include/asm-x86/paravirt.h b/include/asm-x86/paravirt.h index dad5b4186f51..33f72f8fe757 100644 --- a/include/asm-x86/paravirt.h +++ b/include/asm-x86/paravirt.h | |||
@@ -141,9 +141,32 @@ struct pv_cpu_ops { | |||
141 | u64 (*read_pmc)(int counter); | 141 | u64 (*read_pmc)(int counter); |
142 | unsigned long long (*read_tscp)(unsigned int *aux); | 142 | unsigned long long (*read_tscp)(unsigned int *aux); |
143 | 143 | ||
144 | /* These three are jmp to, not actually called. */ | 144 | /* |
145 | * Atomically enable interrupts and return to userspace. This | ||
146 | * is only ever used to return to 32-bit processes; in a | ||
147 | * 64-bit kernel, it's used for 32-on-64 compat processes, but | ||
148 | * never native 64-bit processes. (Jump, not call.) | ||
149 | */ | ||
145 | void (*irq_enable_sysexit)(void); | 150 | void (*irq_enable_sysexit)(void); |
146 | void (*usergs_sysret)(void); | 151 | |
152 | /* | ||
153 | * Switch to usermode gs and return to 64-bit usermode using | ||
154 | * sysret. Only used in 64-bit kernels to return to 64-bit | ||
155 | * processes. Usermode register state, including %rsp, must | ||
156 | * already be restored. | ||
157 | */ | ||
158 | void (*usergs_sysret64)(void); | ||
159 | |||
160 | /* | ||
161 | * Switch to usermode gs and return to 32-bit usermode using | ||
162 | * sysret. Used to return to 32-on-64 compat processes. | ||
163 | * Other usermode register state, including %esp, must already | ||
164 | * be restored. | ||
165 | */ | ||
166 | void (*usergs_sysret32)(void); | ||
167 | |||
168 | /* Normal iret. Jump to this with the standard iret stack | ||
169 | frame set up. */ | ||
147 | void (*iret)(void); | 170 | void (*iret)(void); |
148 | 171 | ||
149 | void (*swapgs)(void); | 172 | void (*swapgs)(void); |
@@ -1481,18 +1504,24 @@ static inline unsigned long __raw_local_irq_save(void) | |||
1481 | call PARA_INDIRECT(pv_irq_ops+PV_IRQ_irq_enable); \ | 1504 | call PARA_INDIRECT(pv_irq_ops+PV_IRQ_irq_enable); \ |
1482 | PV_RESTORE_REGS;) | 1505 | PV_RESTORE_REGS;) |
1483 | 1506 | ||
1484 | #define ENABLE_INTERRUPTS_SYSEXIT \ | 1507 | #define USERGS_SYSRET32 \ |
1485 | PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_irq_enable_sysexit), \ | 1508 | PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_usergs_sysret32), \ |
1486 | CLBR_NONE, \ | 1509 | CLBR_NONE, \ |
1487 | jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_irq_enable_sysexit)) | 1510 | jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_usergs_sysret32)) |
1488 | |||
1489 | 1511 | ||
1490 | #ifdef CONFIG_X86_32 | 1512 | #ifdef CONFIG_X86_32 |
1491 | #define GET_CR0_INTO_EAX \ | 1513 | #define GET_CR0_INTO_EAX \ |
1492 | push %ecx; push %edx; \ | 1514 | push %ecx; push %edx; \ |
1493 | call PARA_INDIRECT(pv_cpu_ops+PV_CPU_read_cr0); \ | 1515 | call PARA_INDIRECT(pv_cpu_ops+PV_CPU_read_cr0); \ |
1494 | pop %edx; pop %ecx | 1516 | pop %edx; pop %ecx |
1495 | #else | 1517 | |
1518 | #define ENABLE_INTERRUPTS_SYSEXIT \ | ||
1519 | PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_irq_enable_sysexit), \ | ||
1520 | CLBR_NONE, \ | ||
1521 | jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_irq_enable_sysexit)) | ||
1522 | |||
1523 | |||
1524 | #else /* !CONFIG_X86_32 */ | ||
1496 | #define SWAPGS \ | 1525 | #define SWAPGS \ |
1497 | PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_swapgs), CLBR_NONE, \ | 1526 | PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_swapgs), CLBR_NONE, \ |
1498 | PV_SAVE_REGS; \ | 1527 | PV_SAVE_REGS; \ |
@@ -1505,11 +1534,16 @@ static inline unsigned long __raw_local_irq_save(void) | |||
1505 | movq %rax, %rcx; \ | 1534 | movq %rax, %rcx; \ |
1506 | xorq %rax, %rax; | 1535 | xorq %rax, %rax; |
1507 | 1536 | ||
1508 | #define USERGS_SYSRET \ | 1537 | #define USERGS_SYSRET64 \ |
1509 | PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_usergs_sysret), \ | 1538 | PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_usergs_sysret64), \ |
1510 | CLBR_NONE, \ | 1539 | CLBR_NONE, \ |
1511 | jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_usergs_sysret)) | 1540 | jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_usergs_sysret64)) |
1512 | #endif | 1541 | |
1542 | #define ENABLE_INTERRUPTS_SYSEXIT32 \ | ||
1543 | PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_irq_enable_sysexit), \ | ||
1544 | CLBR_NONE, \ | ||
1545 | jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_irq_enable_sysexit)) | ||
1546 | #endif /* CONFIG_X86_32 */ | ||
1513 | 1547 | ||
1514 | #endif /* __ASSEMBLY__ */ | 1548 | #endif /* __ASSEMBLY__ */ |
1515 | #endif /* CONFIG_PARAVIRT */ | 1549 | #endif /* CONFIG_PARAVIRT */ |