debuggers.hg

annotate xen/arch/x86/x86_32/entry.S @ 3127:50eaaedc0d3c

bitkeeper revision 1.1159.187.3 (41a3bdde1DKDiUc_Vvg6h5QrnkHvJg)

Big rewrite of Xen->guest transition code. If we fault during the transition
then we roll back and reenable interrupts before properly handling the
fault. This means, for example, that shadow code always executes with
interrupts enabled.
author kaf24@scramble.cl.cam.ac.uk
date Tue Nov 23 22:46:54 2004 +0000 (2004-11-23)
parents 81e74f5bf690
children f068615fc588 e0351a3744a5 a805584b4c8d
rev   line source
kaf24@1710 1 /*
kaf24@1710 2 * Hypercall and fault low-level handling routines.
kaf24@1710 3 *
kaf24@1710 4 * Copyright (c) 2002-2004, K A Fraser
kaf24@1710 5 * Copyright (c) 1991, 1992 Linus Torvalds
kaf24@3127 6 *
kaf24@3127 7 * Calling back to a guest OS:
kaf24@3127 8 * ===========================
kaf24@3127 9 *
kaf24@1710 10 * First, we require that all callbacks (either via a supplied
kaf24@1710 11 * interrupt-descriptor-table, or via the special event or failsafe callbacks
kaf24@1710 12 * in the shared-info-structure) are to ring 1. This just makes life easier,
kaf24@1710 13 * in that it means we don't have to do messy GDT/LDT lookups to find
kaf24@1710 14 * out which the privilege-level of the return code-selector. That code
kaf24@1710 15 * would just be a hassle to write, and would need to account for running
kaf24@1710 16 * off the end of the GDT/LDT, for example. For all callbacks we check
kaf24@3127 17 * that the provided return CS is not == __HYPERVISOR_{CS,DS}. Apart from that
kaf24@3127 18 * we're safe as don't allow a guest OS to install ring-0 privileges into the
kaf24@3127 19 * GDT/LDT. It's up to the guest OS to ensure all returns via the IDT are to
kaf24@3127 20 * ring 1. If not, we load incorrect SS/ESP values from the TSS (for ring 1
kaf24@3127 21 * rather than the correct ring) and bad things are bound to ensue -- IRET is
kaf24@1710 22 * likely to fault, and we may end up killing the domain (no harm can
kaf24@1710 23 * come to Xen, though).
kaf24@1710 24 *
kaf24@1710 25 * When doing a callback, we check if the return CS is in ring 0. If so,
kaf24@1710 26 * callback is delayed until next return to ring != 0.
kaf24@1710 27 * If return CS is in ring 1, then we create a callback frame
kaf24@1710 28 * starting at return SS/ESP. The base of the frame does an intra-privilege
kaf24@1710 29 * interrupt-return.
kaf24@1710 30 * If return CS is in ring > 1, we create a callback frame starting
kaf24@1710 31 * at SS/ESP taken from appropriate section of the current TSS. The base
kaf24@1710 32 * of the frame does an inter-privilege interrupt-return.
kaf24@1710 33 *
kaf24@1710 34 * Note that the "failsafe callback" uses a special stackframe:
kaf24@1710 35 * { return_DS, return_ES, return_FS, return_GS, return_EIP,
kaf24@1710 36 * return_CS, return_EFLAGS[, return_ESP, return_SS] }
kaf24@1710 37 * That is, original values for DS/ES/FS/GS are placed on stack rather than
kaf24@1710 38 * in DS/ES/FS/GS themselves. Why? It saves us loading them, only to have them
kaf24@1710 39 * saved/restored in guest OS. Furthermore, if we load them we may cause
kaf24@1710 40 * a fault if they are invalid, which is a hassle to deal with. We avoid
kaf24@1710 41 * that problem if we don't load them :-) This property allows us to use
kaf24@1710 42 * the failsafe callback as a fallback: if we ever fault on loading DS/ES/FS/GS
kaf24@1710 43 * on return to ring != 0, we can simply package it up as a return via
kaf24@1710 44 * the failsafe callback, and let the guest OS sort it out (perhaps by
kaf24@1710 45 * killing an application process). Note that we also do this for any
kaf24@1710 46 * faulting IRET -- just let the guest OS handle it via the event
kaf24@1710 47 * callback.
kaf24@1710 48 *
kaf24@1710 49 * We terminate a domain in the following cases:
kaf24@1710 50 * - creating a callback stack frame (due to bad ring-1 stack).
kaf24@1710 51 * - faulting IRET on entry to failsafe callback handler.
kaf24@1710 52 * So, each domain must keep its ring-1 %ss/%esp and failsafe callback
kaf24@1710 53 * handler in good order (absolutely no faults allowed!).
kaf24@1710 54 */
kaf24@1710 55
kaf24@1710 56 #include <xen/config.h>
kaf24@1710 57 #include <xen/errno.h>
kaf24@2085 58 #include <xen/softirq.h>
kaf24@2954 59 #include <asm/x86_32/asm_defns.h>
kaf24@2827 60 #include <public/xen.h>
kaf24@1710 61
kaf24@1710 62 #define GET_CURRENT(reg) \
kaf24@3010 63 movl $8192-4, reg; \
kaf24@1710 64 orl %esp, reg; \
kaf24@1710 65 andl $~3,reg; \
kaf24@1710 66 movl (reg),reg;
kaf24@1710 67
kaf24@1710 68 ENTRY(continue_nonidle_task)
kaf24@1710 69 GET_CURRENT(%ebx)
kaf24@1710 70 jmp test_all_events
kaf24@1710 71
kaf24@1710 72 ALIGN
kaf24@1710 73 /*
kaf24@1710 74 * HYPERVISOR_multicall(call_list, nr_calls)
kaf24@1710 75 * Execute a list of 'nr_calls' hypercalls, pointed at by 'call_list'.
kaf24@1710 76 * This is fairly easy except that:
kaf24@1710 77 * 1. We may fault reading the call list, and must patch that up; and
kaf24@1710 78 * 2. We cannot recursively call HYPERVISOR_multicall, or a malicious
kaf24@1710 79 * caller could cause our stack to blow up.
kaf24@1710 80 */
kaf24@2446 81 #define MULTICALL_ENTRY_ORDER 5
kaf24@1710 82 do_multicall:
kaf24@1710 83 popl %eax
kaf24@1710 84 cmpl $SYMBOL_NAME(multicall_return_from_call),%eax
kaf24@1710 85 je multicall_return_from_call
kaf24@1710 86 pushl %ebx
kaf24@1710 87 movl 4(%esp),%ebx /* EBX == call_list */
kaf24@1710 88 movl 8(%esp),%ecx /* ECX == nr_calls */
kaf24@2446 89 /* Ensure the entire multicall list is below HYPERVISOR_VIRT_START. */
kaf24@2446 90 movl %ecx,%eax
kaf24@2446 91 shll $MULTICALL_ENTRY_ORDER,%eax
kaf24@2446 92 addl %ebx,%eax /* EAX == end of multicall list */
kaf24@2446 93 jc bad_multicall_address
kaf24@2446 94 cmpl $__HYPERVISOR_VIRT_START,%eax
kaf24@2446 95 jnc bad_multicall_address
kaf24@1710 96 multicall_loop:
kaf24@1710 97 pushl %ecx
kaf24@1710 98 multicall_fault1:
kaf24@1710 99 pushl 20(%ebx) # args[4]
kaf24@1710 100 multicall_fault2:
kaf24@1710 101 pushl 16(%ebx) # args[3]
kaf24@1710 102 multicall_fault3:
kaf24@1710 103 pushl 12(%ebx) # args[2]
kaf24@1710 104 multicall_fault4:
kaf24@1710 105 pushl 8(%ebx) # args[1]
kaf24@1710 106 multicall_fault5:
kaf24@1710 107 pushl 4(%ebx) # args[0]
kaf24@1710 108 multicall_fault6:
kaf24@1710 109 movl (%ebx),%eax # op
kaf24@1710 110 andl $(NR_hypercalls-1),%eax
kaf24@1710 111 call *SYMBOL_NAME(hypercall_table)(,%eax,4)
kaf24@1710 112 multicall_return_from_call:
kaf24@1710 113 multicall_fault7:
kaf24@1710 114 movl %eax,24(%ebx) # args[5] == result
kaf24@1710 115 addl $20,%esp
kaf24@1710 116 popl %ecx
kaf24@2446 117 addl $(1<<MULTICALL_ENTRY_ORDER),%ebx
kaf24@1710 118 loop multicall_loop
kaf24@1710 119 popl %ebx
kaf24@1710 120 xorl %eax,%eax
kaf24@1710 121 jmp ret_from_hypercall
kaf24@1710 122
kaf24@2446 123 bad_multicall_address:
kaf24@2446 124 popl %ebx
kaf24@2446 125 movl $-EFAULT,%eax
kaf24@2446 126 jmp ret_from_hypercall
kaf24@2446 127
kaf24@1710 128 .section __ex_table,"a"
kaf24@1710 129 .align 4
kaf24@1710 130 .long multicall_fault1, multicall_fixup1
kaf24@1710 131 .long multicall_fault2, multicall_fixup2
kaf24@1710 132 .long multicall_fault3, multicall_fixup3
kaf24@1710 133 .long multicall_fault4, multicall_fixup4
kaf24@1710 134 .long multicall_fault5, multicall_fixup5
kaf24@1710 135 .long multicall_fault6, multicall_fixup6
cl349@2570 136 .long multicall_fault7, multicall_fixup6
kaf24@1710 137 .previous
kaf24@1710 138
kaf24@1710 139 .section .fixup,"ax"
kaf24@1710 140 multicall_fixup6:
kaf24@1710 141 addl $4,%esp
kaf24@1710 142 multicall_fixup5:
kaf24@1710 143 addl $4,%esp
kaf24@1710 144 multicall_fixup4:
kaf24@1710 145 addl $4,%esp
kaf24@1710 146 multicall_fixup3:
kaf24@1710 147 addl $4,%esp
kaf24@1710 148 multicall_fixup2:
kaf24@1710 149 addl $4,%esp
kaf24@1710 150 multicall_fixup1:
kaf24@1710 151 addl $4,%esp
kaf24@1710 152 popl %ebx
kaf24@1710 153 movl $-EFAULT,%eax
kaf24@1710 154 jmp ret_from_hypercall
kaf24@1710 155 .previous
kaf24@1710 156
kaf24@1710 157 ALIGN
kaf24@1710 158 restore_all_guest:
kaf24@3127 159 testb $TF_failsafe_return,DOMAIN_thread_flags(%ebx)
kaf24@3127 160 jnz failsafe_callback
kaf24@3127 161 FLT1: movl XREGS_ds(%esp),%ds
kaf24@3127 162 FLT2: movl XREGS_es(%esp),%es
kaf24@3127 163 FLT3: movl XREGS_fs(%esp),%fs
kaf24@3127 164 FLT4: movl XREGS_gs(%esp),%gs
kaf24@1710 165 popl %ebx
kaf24@1710 166 popl %ecx
kaf24@1710 167 popl %edx
kaf24@1710 168 popl %esi
kaf24@1710 169 popl %edi
kaf24@1710 170 popl %ebp
kaf24@1710 171 popl %eax
kaf24@2954 172 addl $4,%esp
kaf24@3127 173 FLT5: iret
kaf24@3127 174 .section .fixup,"ax"
kaf24@3127 175 FIX5: subl $28,%esp
kaf24@3127 176 pushl 28(%esp) # error_code/entry_vector
kaf24@3127 177 movl %eax,XREGS_eax+4(%esp)
kaf24@3127 178 movl %ebp,XREGS_ebp+4(%esp)
kaf24@3127 179 movl %edi,XREGS_edi+4(%esp)
kaf24@3127 180 movl %esi,XREGS_esi+4(%esp)
kaf24@3127 181 movl %edx,XREGS_edx+4(%esp)
kaf24@3127 182 movl %ecx,XREGS_ecx+4(%esp)
kaf24@3127 183 movl %ebx,XREGS_ebx+4(%esp)
kaf24@3127 184 FIX1: SET_XEN_SEGMENTS(a)
kaf24@3127 185 movl %eax,%fs
kaf24@3127 186 movl %eax,%gs
kaf24@3127 187 sti
kaf24@3127 188 popl %esi
kaf24@3127 189 pushfl # EFLAGS
kaf24@3127 190 movl $__HYPERVISOR_CS,%eax
kaf24@3127 191 pushl %eax # CS
kaf24@3127 192 movl $DBLFLT1,%eax
kaf24@3127 193 pushl %eax # EIP
kaf24@3127 194 pushl %esi # error_code/entry_vector
kaf24@3127 195 jmp error_code
kaf24@3127 196 DBLFLT1:GET_CURRENT(%ebx)
kaf24@3127 197 jmp test_all_events
kaf24@3127 198 DBLFIX1:GET_CURRENT(%ebx)
kaf24@3127 199 testb $TF_failsafe_return,DOMAIN_thread_flags(%ebx)
kaf24@3127 200 jnz domain_crash # cannot reenter failsafe code
kaf24@3127 201 orb $TF_failsafe_return,DOMAIN_thread_flags(%ebx)
kaf24@3127 202 jmp test_all_events # will return via failsafe code
kaf24@3127 203 .previous
kaf24@3127 204 .section __pre_ex_table,"a"
kaf24@3127 205 .long FLT1,FIX1
kaf24@3127 206 .long FLT2,FIX1
kaf24@3127 207 .long FLT3,FIX1
kaf24@3127 208 .long FLT4,FIX1
kaf24@3127 209 .long FLT5,FIX5
kaf24@3127 210 .previous
kaf24@3127 211 .section __ex_table,"a"
kaf24@3127 212 .long DBLFLT1,DBLFIX1
kaf24@3127 213 .previous
kaf24@3127 214
kaf24@3127 215 /* No special register assumptions */
kaf24@3127 216 failsafe_callback:
kaf24@3127 217 GET_CURRENT(%ebx)
kaf24@3127 218 andb $~TF_failsafe_return,DOMAIN_thread_flags(%ebx)
kaf24@3127 219 leal DOMAIN_trap_bounce(%ebx),%edx
kaf24@3127 220 movl DOMAIN_failsafe_addr(%ebx),%eax
kaf24@3127 221 movl %eax,TRAPBOUNCE_eip(%edx)
kaf24@3127 222 movl DOMAIN_failsafe_sel(%ebx),%eax
kaf24@3127 223 movw %ax,TRAPBOUNCE_cs(%edx)
kaf24@3127 224 movw $TBF_FAILSAFE,TRAPBOUNCE_flags(%edx)
kaf24@3127 225 call create_bounce_frame
kaf24@3127 226 popl %ebx
kaf24@3127 227 popl %ecx
kaf24@3127 228 popl %edx
kaf24@3127 229 popl %esi
kaf24@3127 230 popl %edi
kaf24@3127 231 popl %ebp
kaf24@3127 232 popl %eax
kaf24@3127 233 addl $4,%esp
kaf24@3127 234 FLT6: iret
kaf24@3127 235 .section .fixup,"ax"
kaf24@3127 236 FIX6: pushl %ebx
kaf24@3127 237 GET_CURRENT(%ebx)
kaf24@3127 238 orb $TF_failsafe_return,DOMAIN_thread_flags(%ebx)
kaf24@3127 239 pop %ebx
kaf24@3127 240 jmp FIX5
kaf24@3127 241 .section __pre_ex_table,"a"
kaf24@3127 242 .long FLT6,FIX6
kaf24@3127 243 .previous
kaf24@1710 244
kaf24@1710 245 ALIGN
kaf24@1710 246 restore_all_xen:
kaf24@1710 247 popl %ebx
kaf24@1710 248 popl %ecx
kaf24@1710 249 popl %edx
kaf24@1710 250 popl %esi
kaf24@1710 251 popl %edi
kaf24@1710 252 popl %ebp
kaf24@1710 253 popl %eax
kaf24@1710 254 addl $4,%esp
kaf24@1710 255 iret
kaf24@1710 256
kaf24@1710 257 ALIGN
kaf24@1710 258 ENTRY(hypercall)
kaf24@3127 259 subl $4,%esp
kaf24@2955 260 SAVE_ALL(b)
kaf24@2954 261 sti
kaf24@2954 262 GET_CURRENT(%ebx)
kaf24@1710 263 andl $(NR_hypercalls-1),%eax
kaf24@1710 264 call *SYMBOL_NAME(hypercall_table)(,%eax,4)
kaf24@1710 265
kaf24@1710 266 ret_from_hypercall:
kaf24@3127 267 movl %eax,XREGS_eax(%esp) # save the return value
kaf24@1710 268
kaf24@1710 269 test_all_events:
kaf24@1710 270 xorl %ecx,%ecx
kaf24@1710 271 notl %ecx
kaf24@1710 272 cli # tests must not race interrupts
kaf24@1710 273 /*test_softirqs:*/
kaf24@2954 274 movl DOMAIN_processor(%ebx),%eax
kaf24@1710 275 shl $6,%eax # sizeof(irq_cpustat) == 64
kaf24@1710 276 test %ecx,SYMBOL_NAME(irq_stat)(%eax,1)
kaf24@1710 277 jnz process_softirqs
kaf24@1710 278 /*test_guest_events:*/
kaf24@2954 279 movl DOMAIN_shared_info(%ebx),%eax
kaf24@2954 280 testb $0xFF,SHINFO_upcall_mask(%eax)
kaf24@1710 281 jnz restore_all_guest
kaf24@2954 282 testb $0xFF,SHINFO_upcall_pending(%eax)
kaf24@1710 283 jz restore_all_guest
kaf24@1710 284 /*process_guest_events:*/
kaf24@3081 285 leal DOMAIN_trap_bounce(%ebx),%edx
kaf24@2954 286 movl DOMAIN_event_addr(%ebx),%eax
kaf24@3081 287 movl %eax,TRAPBOUNCE_eip(%edx)
kaf24@2954 288 movl DOMAIN_event_sel(%ebx),%eax
kaf24@3081 289 movw %ax,TRAPBOUNCE_cs(%edx)
kaf24@3127 290 movw $TBF_INTERRUPT,TRAPBOUNCE_flags(%edx)
kaf24@1710 291 call create_bounce_frame
kaf24@3127 292 movl DOMAIN_shared_info(%ebx),%eax
kaf24@3127 293 movb $1,SHINFO_upcall_mask(%eax) # Upcalls are masked during delivery
kaf24@1710 294 jmp restore_all_guest
kaf24@1710 295
kaf24@1710 296 ALIGN
kaf24@1710 297 process_softirqs:
kaf24@1710 298 sti
kaf24@1710 299 call SYMBOL_NAME(do_softirq)
kaf24@1710 300 jmp test_all_events
kaf24@1710 301
kaf24@2954 302 /* CREATE A BASIC EXCEPTION FRAME ON GUEST OS (RING-1) STACK: */
kaf24@2954 303 /* {EIP, CS, EFLAGS, [ESP, SS]} */
kaf24@3081 304 /* %edx == trap_bounce, %ebx == task_struct */
kaf24@2954 305 /* %eax,%ecx are clobbered. %gs:%esi contain new XREGS_ss/XREGS_esp. */
kaf24@1710 306 create_bounce_frame:
kaf24@3127 307 movb XREGS_cs+4(%esp),%cl
kaf24@3127 308 testb $2,%cl
kaf24@1710 309 jz 1f /* jump if returning to an existing ring-1 activation */
kaf24@1710 310 /* obtain ss/esp from TSS -- no current ring-1 activations */
kaf24@2954 311 movl DOMAIN_processor(%ebx),%eax
kaf24@1710 312 /* next 4 lines multiply %eax by 8320, which is sizeof(tss_struct) */
kaf24@1710 313 movl %eax, %ecx
kaf24@1710 314 shll $7, %ecx
kaf24@1710 315 shll $13, %eax
kaf24@1710 316 addl %ecx,%eax
kaf24@1710 317 addl $init_tss + 12,%eax
kaf24@1710 318 movl (%eax),%esi /* tss->esp1 */
kaf24@3127 319 FLT7: movl 4(%eax),%gs /* tss->ss1 */
kaf24@1710 320 /* base of stack frame must contain ss/esp (inter-priv iret) */
kaf24@1710 321 subl $8,%esi
kaf24@2954 322 movl XREGS_esp+4(%esp),%eax
kaf24@3127 323 FLT8: movl %eax,%gs:(%esi)
kaf24@2954 324 movl XREGS_ss+4(%esp),%eax
kaf24@3127 325 FLT9: movl %eax,%gs:4(%esi)
kaf24@1710 326 jmp 2f
kaf24@1710 327 1: /* obtain ss/esp from oldss/oldesp -- a ring-1 activation exists */
kaf24@2954 328 movl XREGS_esp+4(%esp),%esi
kaf24@3127 329 FLT10: movl XREGS_ss+4(%esp),%gs
kaf24@1710 330 2: /* Construct a stack frame: EFLAGS, CS/EIP */
kaf24@1710 331 subl $12,%esi
kaf24@2954 332 movl XREGS_eip+4(%esp),%eax
kaf24@3127 333 FLT11: movl %eax,%gs:(%esi)
kaf24@2954 334 movl XREGS_cs+4(%esp),%eax
kaf24@3127 335 FLT12: movl %eax,%gs:4(%esi)
kaf24@2954 336 movl XREGS_eflags+4(%esp),%eax
kaf24@3127 337 FLT13: movl %eax,%gs:8(%esi)
kaf24@3127 338 movb TRAPBOUNCE_flags(%edx),%cl
kaf24@3127 339 test $TBF_EXCEPTION_ERRCODE,%cl
kaf24@3127 340 jz 1f
kaf24@3127 341 subl $4,%esi # push error_code onto guest frame
kaf24@3127 342 movl TRAPBOUNCE_error_code(%edx),%eax
kaf24@3127 343 FLT14: movl %eax,%gs:(%esi)
kaf24@3127 344 testb $TBF_EXCEPTION_CR2,%cl
kaf24@3127 345 jz 2f
kaf24@3127 346 subl $4,%esi # push %cr2 onto guest frame
kaf24@3127 347 movl TRAPBOUNCE_cr2(%edx),%eax
kaf24@3127 348 FLT15: movl %eax,%gs:(%esi)
kaf24@3127 349 1: testb $TBF_FAILSAFE,%cl
kaf24@3127 350 jz 2f
kaf24@3127 351 subl $16,%esi # add DS/ES/FS/GS to failsafe stack frame
kaf24@3127 352 movl XREGS_ds+4(%esp),%eax
kaf24@3127 353 FLT16: movl %eax,%gs:(%esi)
kaf24@3127 354 movl XREGS_es+4(%esp),%eax
kaf24@3127 355 FLT17: movl %eax,%gs:4(%esi)
kaf24@3127 356 movl XREGS_fs+4(%esp),%eax
kaf24@3127 357 FLT18: movl %eax,%gs:8(%esi)
kaf24@3127 358 movl XREGS_gs+4(%esp),%eax
kaf24@3127 359 FLT19: movl %eax,%gs:12(%esi)
kaf24@3127 360 2: movb $0,TRAPBOUNCE_flags(%edx)
kaf24@1710 361 /* Rewrite our stack frame and return to ring 1. */
kaf24@1710 362 /* IA32 Ref. Vol. 3: TF, VM, RF and NT flags are cleared on trap. */
kaf24@3127 363 andl $0xfffcbeff,XREGS_eflags+4(%esp)
kaf24@2954 364 movl %gs,XREGS_ss+4(%esp)
kaf24@2954 365 movl %esi,XREGS_esp+4(%esp)
kaf24@3081 366 movzwl TRAPBOUNCE_cs(%edx),%eax
kaf24@2954 367 movl %eax,XREGS_cs+4(%esp)
kaf24@3081 368 movl TRAPBOUNCE_eip(%edx),%eax
kaf24@2954 369 movl %eax,XREGS_eip+4(%esp)
kaf24@1710 370 ret
kaf24@3127 371 .section .fixup,"ax"
kaf24@3127 372 FIX7: sti
kaf24@3127 373 popl %esi
kaf24@3127 374 addl $4,%esp # Discard create_b_frame return address
kaf24@3127 375 pushfl # EFLAGS
kaf24@3127 376 movl $__HYPERVISOR_CS,%eax
kaf24@3127 377 pushl %eax # CS
kaf24@3127 378 movl $DBLFLT2,%eax
kaf24@3127 379 pushl %eax # EIP
kaf24@3127 380 pushl %esi # error_code/entry_vector
kaf24@3127 381 jmp error_code
kaf24@3127 382 DBLFLT2:jmp process_guest_exception_and_events
kaf24@3127 383 .previous
kaf24@3127 384 .section __pre_ex_table,"a"
kaf24@3127 385 .long FLT7,FIX7
kaf24@3127 386 .long FLT8,FIX7
kaf24@3127 387 .long FLT9,FIX7
kaf24@3127 388 .long FLT10,FIX7
kaf24@3127 389 .long FLT11,FIX7
kaf24@3127 390 .long FLT12,FIX7
kaf24@3127 391 .long FLT13,FIX7
kaf24@3127 392 .long FLT14,FIX7
kaf24@3127 393 .long FLT15,FIX7
kaf24@3127 394 .long FLT16,FIX7
kaf24@3127 395 .long FLT17,FIX7
kaf24@3127 396 .long FLT18,FIX7
kaf24@3127 397 .long FLT19,FIX7
kaf24@3127 398 .previous
kaf24@1710 399 .section __ex_table,"a"
kaf24@3127 400 .long DBLFLT2,domain_crash
kaf24@1710 401 .previous
kaf24@1710 402
kaf24@1710 403 ALIGN
kaf24@3127 404 process_guest_exception_and_events:
kaf24@3081 405 leal DOMAIN_trap_bounce(%ebx),%edx
kaf24@3127 406 testb $TBF_EXCEPTION,TRAPBOUNCE_flags(%edx)
kaf24@1710 407 jz test_all_events
kaf24@3127 408 call create_bounce_frame
kaf24@1710 409 jmp test_all_events
kaf24@1710 410
kaf24@1710 411 ALIGN
kaf24@1710 412 ENTRY(ret_from_intr)
kaf24@1710 413 GET_CURRENT(%ebx)
kaf24@2954 414 movb XREGS_cs(%esp),%al
kaf24@1710 415 testb $3,%al # return to non-supervisor?
kaf24@3127 416 jnz test_all_events
kaf24@1710 417 jmp restore_all_xen
kaf24@1710 418
kaf24@1710 419 ENTRY(divide_error)
kaf24@3127 420 pushl $TRAP_divide_error<<16
kaf24@1710 421 ALIGN
kaf24@1710 422 error_code:
kaf24@3127 423 SAVE_ALL_NOSEGREGS(a)
kaf24@3127 424 SET_XEN_SEGMENTS(a)
kaf24@3127 425 testb $X86_EFLAGS_IF>>8,XREGS_eflags+1(%esp)
kaf24@3127 426 jz exception_with_ints_disabled
kaf24@3127 427 sti # re-enable interrupts
kaf24@3127 428 xorl %eax,%eax
kaf24@3127 429 movw XREGS_entry_vector(%esp),%ax
kaf24@3127 430 movl %esp,%edx
ach61@2843 431 pushl %edx # push the xen_regs pointer
kaf24@1710 432 GET_CURRENT(%ebx)
kaf24@3127 433 call *SYMBOL_NAME(exception_table)(,%eax,4)
kaf24@3127 434 addl $4,%esp
kaf24@2954 435 movb XREGS_cs(%esp),%al
kaf24@1710 436 testb $3,%al
kaf24@3127 437 jz restore_all_xen
kaf24@1710 438 jmp process_guest_exception_and_events
kaf24@1710 439
kaf24@3127 440 exception_with_ints_disabled:
kaf24@3127 441 movb XREGS_cs(%esp),%al
kaf24@3127 442 testb $3,%al # interrupts disabled outside Xen?
kaf24@3127 443 jnz FATAL_exception_with_ints_disabled
kaf24@3127 444 pushl XREGS_eip(%esp)
kaf24@3127 445 call search_pre_exception_table
kaf24@3127 446 addl $4,%esp
kaf24@3127 447 testl %eax,%eax # no fixup code for faulting EIP?
kaf24@3127 448 jz FATAL_exception_with_ints_disabled
kaf24@3127 449 movl %eax,XREGS_eip(%esp)
kaf24@3127 450 movl %esp,%esi
kaf24@3127 451 subl $4,%esp
kaf24@3127 452 movl %esp,%edi
kaf24@3127 453 movl $XREGS_kernel_sizeof/4,%ecx
kaf24@3127 454 rep; movsl # make room for error_code/entry_vector
kaf24@3127 455 movl XREGS_error_code(%esp),%eax # error_code/entry_vector
kaf24@3127 456 movl %eax,XREGS_kernel_sizeof(%esp)
kaf24@3127 457 jmp restore_all_xen # return to fixup code
kaf24@3127 458
kaf24@3127 459 FATAL_exception_with_ints_disabled:
kaf24@3127 460 xorl %esi,%esi
kaf24@3127 461 movw XREGS_entry_vector(%esp),%si
kaf24@3127 462 movl %esp,%edx
kaf24@3127 463 pushl %edx # push the xen_regs pointer
kaf24@3127 464 pushl %esi # push the trapnr (entry vector)
kaf24@3127 465 call SYMBOL_NAME(fatal_trap)
kaf24@3127 466 ud2
kaf24@3127 467
kaf24@1710 468 ENTRY(coprocessor_error)
kaf24@3127 469 pushl $TRAP_copro_error<<16
kaf24@1710 470 jmp error_code
kaf24@1710 471
kaf24@1710 472 ENTRY(simd_coprocessor_error)
kaf24@3127 473 pushl $TRAP_simd_error<<16
kaf24@1710 474 jmp error_code
kaf24@1710 475
kaf24@1710 476 ENTRY(device_not_available)
kaf24@3127 477 pushl $TRAP_no_device<<16
kaf24@1710 478 jmp error_code
kaf24@1710 479
kaf24@1710 480 ENTRY(debug)
kaf24@3127 481 pushl $TRAP_debug<<16
kaf24@1710 482 jmp error_code
kaf24@1710 483
kaf24@1710 484 ENTRY(int3)
kaf24@3127 485 pushl $TRAP_int3<<16
kaf24@1710 486 jmp error_code
kaf24@1710 487
kaf24@1710 488 ENTRY(overflow)
kaf24@3127 489 pushl $TRAP_overflow<<16
kaf24@1710 490 jmp error_code
kaf24@1710 491
kaf24@1710 492 ENTRY(bounds)
kaf24@3127 493 pushl $TRAP_bounds<<16
kaf24@1710 494 jmp error_code
kaf24@1710 495
kaf24@1710 496 ENTRY(invalid_op)
kaf24@3127 497 pushl $TRAP_invalid_op<<16
kaf24@1710 498 jmp error_code
kaf24@1710 499
kaf24@1710 500 ENTRY(coprocessor_segment_overrun)
kaf24@3127 501 pushl $TRAP_copro_seg<<16
kaf24@1710 502 jmp error_code
kaf24@1710 503
kaf24@1710 504 ENTRY(invalid_TSS)
kaf24@3127 505 movw $TRAP_invalid_tss,2(%esp)
kaf24@1710 506 jmp error_code
kaf24@1710 507
kaf24@1710 508 ENTRY(segment_not_present)
kaf24@3127 509 movw $TRAP_no_segment,2(%esp)
kaf24@1710 510 jmp error_code
kaf24@1710 511
kaf24@1710 512 ENTRY(stack_segment)
kaf24@3127 513 movw $TRAP_stack_error,2(%esp)
kaf24@1710 514 jmp error_code
kaf24@1710 515
kaf24@1710 516 ENTRY(general_protection)
kaf24@3127 517 movw $TRAP_gp_fault,2(%esp)
kaf24@1710 518 jmp error_code
kaf24@1710 519
kaf24@1710 520 ENTRY(alignment_check)
kaf24@3127 521 movw $TRAP_alignment_check,2(%esp)
kaf24@1710 522 jmp error_code
kaf24@1710 523
kaf24@1710 524 ENTRY(page_fault)
kaf24@3127 525 movw $TRAP_page_fault,2(%esp)
kaf24@1710 526 jmp error_code
kaf24@1710 527
kaf24@1710 528 ENTRY(machine_check)
kaf24@3127 529 pushl $TRAP_machine_check<<16
kaf24@1710 530 jmp error_code
kaf24@1710 531
kaf24@1710 532 ENTRY(spurious_interrupt_bug)
kaf24@3127 533 pushl $TRAP_spurious_int<<16
kaf24@1710 534 jmp error_code
kaf24@1710 535
kaf24@1710 536 ENTRY(nmi)
kaf24@1710 537 # Save state but do not trash the segment registers!
kaf24@1710 538 # We may otherwise be unable to reload them or copy them to ring 1.
kaf24@1710 539 pushl %eax
kaf24@2955 540 SAVE_ALL_NOSEGREGS(a)
kaf24@1710 541
kaf24@2085 542 # Check for hardware problems.
kaf24@1710 543 inb $0x61,%al
kaf24@1710 544 testb $0x80,%al
kaf24@2080 545 jne nmi_parity_err
kaf24@1710 546 testb $0x40,%al
kaf24@1710 547 jne nmi_io_err
kaf24@1710 548 movl %eax,%ebx
kaf24@1710 549
kaf24@1710 550 # Okay, its almost a normal NMI tick. We can only process it if:
kaf24@1710 551 # A. We are the outermost Xen activation (in which case we have
kaf24@1710 552 # the selectors safely saved on our stack)
kaf24@1710 553 # B. DS-GS all contain sane Xen values.
kaf24@1710 554 # In all other cases we bail without touching DS-GS, as we have
kaf24@1710 555 # interrupted an enclosing Xen activation in tricky prologue or
kaf24@1710 556 # epilogue code.
kaf24@2954 557 movb XREGS_cs(%esp),%al
kaf24@1710 558 testb $3,%al
kaf24@3127 559 jnz do_watchdog_tick
kaf24@2954 560 movl XREGS_ds(%esp),%eax
kaf24@1710 561 cmpw $(__HYPERVISOR_DS),%ax
kaf24@2954 562 jne restore_all_xen
kaf24@2954 563 movl XREGS_es(%esp),%eax
kaf24@1710 564 cmpw $(__HYPERVISOR_DS),%ax
kaf24@2954 565 jne restore_all_xen
kaf24@2954 566 movl XREGS_fs(%esp),%eax
kaf24@1710 567 cmpw $(__HYPERVISOR_DS),%ax
kaf24@2954 568 jne restore_all_xen
kaf24@2954 569 movl XREGS_gs(%esp),%eax
kaf24@1710 570 cmpw $(__HYPERVISOR_DS),%ax
kaf24@2954 571 jne restore_all_xen
kaf24@1710 572
kaf24@1710 573 do_watchdog_tick:
kaf24@1710 574 movl $(__HYPERVISOR_DS),%edx
kaf24@1710 575 movl %edx,%ds
kaf24@1710 576 movl %edx,%es
kaf24@1710 577 movl %esp,%edx
kaf24@1710 578 pushl %ebx # reason
kaf24@1710 579 pushl %edx # regs
kaf24@1710 580 call SYMBOL_NAME(do_nmi)
kaf24@1710 581 addl $8,%esp
kaf24@2954 582 movb XREGS_cs(%esp),%al
kaf24@1710 583 testb $3,%al
kaf24@3127 584 jz restore_all_xen
kaf24@1710 585 GET_CURRENT(%ebx)
kaf24@1710 586 jmp restore_all_guest
kaf24@1710 587
kaf24@2085 588 nmi_parity_err:
kaf24@2085 589 # Clear and disable the parity-error line
kaf24@2085 590 andb $0xf,%al
kaf24@2085 591 orb $0x4,%al
kaf24@2085 592 outb %al,$0x61
kaf24@2085 593 cmpb $'i',%ss:SYMBOL_NAME(opt_nmi) # nmi=ignore
kaf24@2954 594 je restore_all_xen
kaf24@2085 595 bts $0,%ss:SYMBOL_NAME(nmi_softirq_reason)
kaf24@2085 596 bts $NMI_SOFTIRQ,%ss:SYMBOL_NAME(irq_stat)
kaf24@2085 597 cmpb $'d',%ss:SYMBOL_NAME(opt_nmi) # nmi=dom0
kaf24@2954 598 je restore_all_xen
kaf24@2085 599 movl $(__HYPERVISOR_DS),%edx # nmi=fatal
kaf24@1710 600 movl %edx,%ds
kaf24@1710 601 movl %edx,%es
kaf24@2079 602 movl %esp,%edx
kaf24@2079 603 push %edx
kaf24@2079 604 call SYMBOL_NAME(mem_parity_error)
kaf24@2085 605 addl $4,%esp
kaf24@2085 606 jmp ret_from_intr
kaf24@2085 607
kaf24@1710 608 nmi_io_err:
kaf24@2085 609 # Clear and disable the I/O-error line
kaf24@2085 610 andb $0xf,%al
kaf24@2085 611 orb $0x8,%al
kaf24@2085 612 outb %al,$0x61
kaf24@2085 613 cmpb $'i',%ss:SYMBOL_NAME(opt_nmi) # nmi=ignore
kaf24@2954 614 je restore_all_xen
kaf24@2085 615 bts $1,%ss:SYMBOL_NAME(nmi_softirq_reason)
kaf24@2085 616 bts $NMI_SOFTIRQ,%ss:SYMBOL_NAME(irq_stat)
kaf24@2085 617 cmpb $'d',%ss:SYMBOL_NAME(opt_nmi) # nmi=dom0
kaf24@2954 618 je restore_all_xen
kaf24@2085 619 movl $(__HYPERVISOR_DS),%edx # nmi=fatal
kaf24@1710 620 movl %edx,%ds
kaf24@1710 621 movl %edx,%es
kaf24@2079 622 movl %esp,%edx
kaf24@2079 623 push %edx
kaf24@2079 624 call SYMBOL_NAME(io_check_error)
kaf24@2085 625 addl $4,%esp
kaf24@2085 626 jmp ret_from_intr
kaf24@2079 627
kaf24@1710 628 .data
kaf24@3127 629
kaf24@3127 630 ENTRY(exception_table)
kaf24@3127 631 .long SYMBOL_NAME(do_divide_error)
kaf24@3127 632 .long SYMBOL_NAME(do_debug)
kaf24@3127 633 .long 0 # nmi
kaf24@3127 634 .long SYMBOL_NAME(do_int3)
kaf24@3127 635 .long SYMBOL_NAME(do_overflow)
kaf24@3127 636 .long SYMBOL_NAME(do_bounds)
kaf24@3127 637 .long SYMBOL_NAME(do_invalid_op)
kaf24@3127 638 .long SYMBOL_NAME(math_state_restore)
kaf24@3127 639 .long 0 # double fault
kaf24@3127 640 .long SYMBOL_NAME(do_coprocessor_segment_overrun)
kaf24@3127 641 .long SYMBOL_NAME(do_invalid_TSS)
kaf24@3127 642 .long SYMBOL_NAME(do_segment_not_present)
kaf24@3127 643 .long SYMBOL_NAME(do_stack_segment)
kaf24@3127 644 .long SYMBOL_NAME(do_general_protection)
kaf24@3127 645 .long SYMBOL_NAME(do_page_fault)
kaf24@3127 646 .long SYMBOL_NAME(do_spurious_interrupt_bug)
kaf24@3127 647 .long SYMBOL_NAME(do_coprocessor_error)
kaf24@3127 648 .long SYMBOL_NAME(do_alignment_check)
kaf24@3127 649 .long SYMBOL_NAME(do_machine_check)
kaf24@3127 650 .long SYMBOL_NAME(do_simd_coprocessor_error)
kaf24@3127 651
kaf24@1710 652 ENTRY(hypercall_table)
kaf24@1710 653 .long SYMBOL_NAME(do_set_trap_table) /* 0 */
kaf24@1710 654 .long SYMBOL_NAME(do_mmu_update)
kaf24@1710 655 .long SYMBOL_NAME(do_set_gdt)
kaf24@1710 656 .long SYMBOL_NAME(do_stack_switch)
kaf24@1710 657 .long SYMBOL_NAME(do_set_callbacks)
kaf24@1710 658 .long SYMBOL_NAME(do_fpu_taskswitch) /* 5 */
kaf24@1710 659 .long SYMBOL_NAME(do_sched_op)
kaf24@1710 660 .long SYMBOL_NAME(do_dom0_op)
kaf24@1710 661 .long SYMBOL_NAME(do_set_debugreg)
kaf24@1710 662 .long SYMBOL_NAME(do_get_debugreg)
kaf24@1710 663 .long SYMBOL_NAME(do_update_descriptor) /* 10 */
kaf24@1710 664 .long SYMBOL_NAME(do_set_fast_trap)
kaf24@1710 665 .long SYMBOL_NAME(do_dom_mem_op)
kaf24@1710 666 .long SYMBOL_NAME(do_multicall)
kaf24@1710 667 .long SYMBOL_NAME(do_update_va_mapping)
kaf24@1710 668 .long SYMBOL_NAME(do_set_timer_op) /* 15 */
kaf24@1710 669 .long SYMBOL_NAME(do_event_channel_op)
kaf24@1710 670 .long SYMBOL_NAME(do_xen_version)
kaf24@1710 671 .long SYMBOL_NAME(do_console_io)
kaf24@1710 672 .long SYMBOL_NAME(do_physdev_op)
kaf24@2375 673 .long SYMBOL_NAME(do_grant_table_op) /* 20 */
kaf24@2111 674 .long SYMBOL_NAME(do_vm_assist)
kaf24@2375 675 .long SYMBOL_NAME(do_update_va_mapping_otherdomain)
kaf24@1710 676 .rept NR_hypercalls-((.-hypercall_table)/4)
kaf24@1710 677 .long SYMBOL_NAME(do_ni_hypercall)
kaf24@1710 678 .endr