debuggers.hg

annotate xen/arch/x86/x86_32/entry.S @ 1710:138e97a36173

bitkeeper revision 1.1041.6.6 (40e96d3bioFNWNS55cowRl9PXLQZ9Q)

More x86-64 stuff.
author kaf24@scramble.cl.cam.ac.uk
date Mon Jul 05 15:01:15 2004 +0000 (2004-07-05)
parents
children 1c1155a226ec
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@1710 6 */
kaf24@1710 7
kaf24@1710 8 /*
kaf24@1710 9 * The idea for callbacks to guest OSes
kaf24@1710 10 * ====================================
kaf24@1710 11 *
kaf24@1710 12 * First, we require that all callbacks (either via a supplied
kaf24@1710 13 * interrupt-descriptor-table, or via the special event or failsafe callbacks
kaf24@1710 14 * in the shared-info-structure) are to ring 1. This just makes life easier,
kaf24@1710 15 * in that it means we don't have to do messy GDT/LDT lookups to find
kaf24@1710 16 * out which the privilege-level of the return code-selector. That code
kaf24@1710 17 * would just be a hassle to write, and would need to account for running
kaf24@1710 18 * off the end of the GDT/LDT, for example. For all callbacks we check
kaf24@1710 19 * that the provided
kaf24@1710 20 * return CS is not == __HYPERVISOR_{CS,DS}. Apart from that we're safe as
kaf24@1710 21 * don't allow a guest OS to install ring-0 privileges into the GDT/LDT.
kaf24@1710 22 * It's up to the guest OS to ensure all returns via the IDT are to ring 1.
kaf24@1710 23 * If not, we load incorrect SS/ESP values from the TSS (for ring 1 rather
kaf24@1710 24 * than the correct ring) and bad things are bound to ensue -- IRET is
kaf24@1710 25 * likely to fault, and we may end up killing the domain (no harm can
kaf24@1710 26 * come to Xen, though).
kaf24@1710 27 *
kaf24@1710 28 * When doing a callback, we check if the return CS is in ring 0. If so,
kaf24@1710 29 * callback is delayed until next return to ring != 0.
kaf24@1710 30 * If return CS is in ring 1, then we create a callback frame
kaf24@1710 31 * starting at return SS/ESP. The base of the frame does an intra-privilege
kaf24@1710 32 * interrupt-return.
kaf24@1710 33 * If return CS is in ring > 1, we create a callback frame starting
kaf24@1710 34 * at SS/ESP taken from appropriate section of the current TSS. The base
kaf24@1710 35 * of the frame does an inter-privilege interrupt-return.
kaf24@1710 36 *
kaf24@1710 37 * Note that the "failsafe callback" uses a special stackframe:
kaf24@1710 38 * { return_DS, return_ES, return_FS, return_GS, return_EIP,
kaf24@1710 39 * return_CS, return_EFLAGS[, return_ESP, return_SS] }
kaf24@1710 40 * That is, original values for DS/ES/FS/GS are placed on stack rather than
kaf24@1710 41 * in DS/ES/FS/GS themselves. Why? It saves us loading them, only to have them
kaf24@1710 42 * saved/restored in guest OS. Furthermore, if we load them we may cause
kaf24@1710 43 * a fault if they are invalid, which is a hassle to deal with. We avoid
kaf24@1710 44 * that problem if we don't load them :-) This property allows us to use
kaf24@1710 45 * the failsafe callback as a fallback: if we ever fault on loading DS/ES/FS/GS
kaf24@1710 46 * on return to ring != 0, we can simply package it up as a return via
kaf24@1710 47 * the failsafe callback, and let the guest OS sort it out (perhaps by
kaf24@1710 48 * killing an application process). Note that we also do this for any
kaf24@1710 49 * faulting IRET -- just let the guest OS handle it via the event
kaf24@1710 50 * callback.
kaf24@1710 51 *
kaf24@1710 52 * We terminate a domain in the following cases:
kaf24@1710 53 * - creating a callback stack frame (due to bad ring-1 stack).
kaf24@1710 54 * - faulting IRET on entry to failsafe callback handler.
kaf24@1710 55 * So, each domain must keep its ring-1 %ss/%esp and failsafe callback
kaf24@1710 56 * handler in good order (absolutely no faults allowed!).
kaf24@1710 57 */
kaf24@1710 58
kaf24@1710 59 #include <xen/config.h>
kaf24@1710 60 #include <xen/errno.h>
kaf24@1710 61 #include <hypervisor-ifs/hypervisor-if.h>
kaf24@1710 62
kaf24@1710 63 EBX = 0x00
kaf24@1710 64 ECX = 0x04
kaf24@1710 65 EDX = 0x08
kaf24@1710 66 ESI = 0x0C
kaf24@1710 67 EDI = 0x10
kaf24@1710 68 EBP = 0x14
kaf24@1710 69 EAX = 0x18
kaf24@1710 70 DS = 0x1C
kaf24@1710 71 ES = 0x20
kaf24@1710 72 FS = 0x24
kaf24@1710 73 GS = 0x28
kaf24@1710 74 ORIG_EAX = 0x2C
kaf24@1710 75 EIP = 0x30
kaf24@1710 76 CS = 0x34
kaf24@1710 77 EFLAGS = 0x38
kaf24@1710 78 OLDESP = 0x3C
kaf24@1710 79 OLDSS = 0x40
kaf24@1710 80
kaf24@1710 81 /* Offsets in domain structure */
kaf24@1710 82 PROCESSOR = 0
kaf24@1710 83 SHARED_INFO = 4
kaf24@1710 84 EVENT_SEL = 8
kaf24@1710 85 EVENT_ADDR = 12
kaf24@1710 86 FAILSAFE_BUFFER = 16
kaf24@1710 87 FAILSAFE_SEL = 32
kaf24@1710 88 FAILSAFE_ADDR = 36
kaf24@1710 89
kaf24@1710 90 /* Offsets in shared_info_t */
kaf24@1710 91 #define UPCALL_PENDING /* 0 */
kaf24@1710 92 #define UPCALL_MASK 1
kaf24@1710 93
kaf24@1710 94 /* Offsets in guest_trap_bounce */
kaf24@1710 95 GTB_ERROR_CODE = 0
kaf24@1710 96 GTB_CR2 = 4
kaf24@1710 97 GTB_FLAGS = 8
kaf24@1710 98 GTB_CS = 10
kaf24@1710 99 GTB_EIP = 12
kaf24@1710 100 GTBF_TRAP = 1
kaf24@1710 101 GTBF_TRAP_NOCODE = 2
kaf24@1710 102 GTBF_TRAP_CR2 = 4
kaf24@1710 103
kaf24@1710 104 CF_MASK = 0x00000001
kaf24@1710 105 IF_MASK = 0x00000200
kaf24@1710 106 NT_MASK = 0x00004000
kaf24@1710 107
kaf24@1710 108 #define SAVE_ALL_NOSEGREGS \
kaf24@1710 109 cld; \
kaf24@1710 110 pushl %gs; \
kaf24@1710 111 pushl %fs; \
kaf24@1710 112 pushl %es; \
kaf24@1710 113 pushl %ds; \
kaf24@1710 114 pushl %eax; \
kaf24@1710 115 pushl %ebp; \
kaf24@1710 116 pushl %edi; \
kaf24@1710 117 pushl %esi; \
kaf24@1710 118 pushl %edx; \
kaf24@1710 119 pushl %ecx; \
kaf24@1710 120 pushl %ebx; \
kaf24@1710 121
kaf24@1710 122 #define SAVE_ALL \
kaf24@1710 123 SAVE_ALL_NOSEGREGS \
kaf24@1710 124 movl $(__HYPERVISOR_DS),%edx; \
kaf24@1710 125 movl %edx,%ds; \
kaf24@1710 126 movl %edx,%es; \
kaf24@1710 127 movl %edx,%fs; \
kaf24@1710 128 movl %edx,%gs; \
kaf24@1710 129 sti;
kaf24@1710 130
kaf24@1710 131 #define GET_CURRENT(reg) \
kaf24@1710 132 movl $4096-4, reg; \
kaf24@1710 133 orl %esp, reg; \
kaf24@1710 134 andl $~3,reg; \
kaf24@1710 135 movl (reg),reg;
kaf24@1710 136
kaf24@1710 137 ENTRY(continue_nonidle_task)
kaf24@1710 138 GET_CURRENT(%ebx)
kaf24@1710 139 jmp test_all_events
kaf24@1710 140
kaf24@1710 141 ALIGN
kaf24@1710 142 /*
kaf24@1710 143 * HYPERVISOR_multicall(call_list, nr_calls)
kaf24@1710 144 * Execute a list of 'nr_calls' hypercalls, pointed at by 'call_list'.
kaf24@1710 145 * This is fairly easy except that:
kaf24@1710 146 * 1. We may fault reading the call list, and must patch that up; and
kaf24@1710 147 * 2. We cannot recursively call HYPERVISOR_multicall, or a malicious
kaf24@1710 148 * caller could cause our stack to blow up.
kaf24@1710 149 */
kaf24@1710 150 do_multicall:
kaf24@1710 151 popl %eax
kaf24@1710 152 cmpl $SYMBOL_NAME(multicall_return_from_call),%eax
kaf24@1710 153 je multicall_return_from_call
kaf24@1710 154 pushl %ebx
kaf24@1710 155 movl 4(%esp),%ebx /* EBX == call_list */
kaf24@1710 156 movl 8(%esp),%ecx /* ECX == nr_calls */
kaf24@1710 157 multicall_loop:
kaf24@1710 158 pushl %ecx
kaf24@1710 159 multicall_fault1:
kaf24@1710 160 pushl 20(%ebx) # args[4]
kaf24@1710 161 multicall_fault2:
kaf24@1710 162 pushl 16(%ebx) # args[3]
kaf24@1710 163 multicall_fault3:
kaf24@1710 164 pushl 12(%ebx) # args[2]
kaf24@1710 165 multicall_fault4:
kaf24@1710 166 pushl 8(%ebx) # args[1]
kaf24@1710 167 multicall_fault5:
kaf24@1710 168 pushl 4(%ebx) # args[0]
kaf24@1710 169 multicall_fault6:
kaf24@1710 170 movl (%ebx),%eax # op
kaf24@1710 171 andl $(NR_hypercalls-1),%eax
kaf24@1710 172 call *SYMBOL_NAME(hypercall_table)(,%eax,4)
kaf24@1710 173 multicall_return_from_call:
kaf24@1710 174 multicall_fault7:
kaf24@1710 175 movl %eax,24(%ebx) # args[5] == result
kaf24@1710 176 addl $20,%esp
kaf24@1710 177 popl %ecx
kaf24@1710 178 addl $(ARGS_PER_MULTICALL_ENTRY*4),%ebx
kaf24@1710 179 loop multicall_loop
kaf24@1710 180 popl %ebx
kaf24@1710 181 xorl %eax,%eax
kaf24@1710 182 jmp ret_from_hypercall
kaf24@1710 183
kaf24@1710 184 .section __ex_table,"a"
kaf24@1710 185 .align 4
kaf24@1710 186 .long multicall_fault1, multicall_fixup1
kaf24@1710 187 .long multicall_fault2, multicall_fixup2
kaf24@1710 188 .long multicall_fault3, multicall_fixup3
kaf24@1710 189 .long multicall_fault4, multicall_fixup4
kaf24@1710 190 .long multicall_fault5, multicall_fixup5
kaf24@1710 191 .long multicall_fault6, multicall_fixup6
kaf24@1710 192 .previous
kaf24@1710 193
kaf24@1710 194 .section .fixup,"ax"
kaf24@1710 195 multicall_fixup6:
kaf24@1710 196 addl $4,%esp
kaf24@1710 197 multicall_fixup5:
kaf24@1710 198 addl $4,%esp
kaf24@1710 199 multicall_fixup4:
kaf24@1710 200 addl $4,%esp
kaf24@1710 201 multicall_fixup3:
kaf24@1710 202 addl $4,%esp
kaf24@1710 203 multicall_fixup2:
kaf24@1710 204 addl $4,%esp
kaf24@1710 205 multicall_fixup1:
kaf24@1710 206 addl $4,%esp
kaf24@1710 207 popl %ebx
kaf24@1710 208 movl $-EFAULT,%eax
kaf24@1710 209 jmp ret_from_hypercall
kaf24@1710 210 .previous
kaf24@1710 211
kaf24@1710 212 ALIGN
kaf24@1710 213 restore_all_guest:
kaf24@1710 214 # First, may need to restore %ds if clobbered by create_bounce_frame
kaf24@1710 215 pushl %ss
kaf24@1710 216 popl %ds
kaf24@1710 217 # Second, create a failsafe copy of DS,ES,FS,GS in case any are bad
kaf24@1710 218 leal DS(%esp),%esi
kaf24@1710 219 leal FAILSAFE_BUFFER(%ebx),%edi
kaf24@1710 220 movsl
kaf24@1710 221 movsl
kaf24@1710 222 movsl
kaf24@1710 223 movsl
kaf24@1710 224 # Finally, restore guest registers -- faults will cause failsafe
kaf24@1710 225 popl %ebx
kaf24@1710 226 popl %ecx
kaf24@1710 227 popl %edx
kaf24@1710 228 popl %esi
kaf24@1710 229 popl %edi
kaf24@1710 230 popl %ebp
kaf24@1710 231 popl %eax
kaf24@1710 232 1: popl %ds
kaf24@1710 233 2: popl %es
kaf24@1710 234 3: popl %fs
kaf24@1710 235 4: popl %gs
kaf24@1710 236 addl $4,%esp
kaf24@1710 237 5: iret
kaf24@1710 238 .section .fixup,"ax"
kaf24@1710 239 10: subl $4,%esp
kaf24@1710 240 pushl %gs
kaf24@1710 241 9: pushl %fs
kaf24@1710 242 8: pushl %es
kaf24@1710 243 7: pushl %ds
kaf24@1710 244 6: pushl %eax
kaf24@1710 245 pushl %ebp
kaf24@1710 246 pushl %edi
kaf24@1710 247 pushl %esi
kaf24@1710 248 pushl %edx
kaf24@1710 249 pushl %ecx
kaf24@1710 250 pushl %ebx
kaf24@1710 251 pushl %ss
kaf24@1710 252 popl %ds
kaf24@1710 253 pushl %ss
kaf24@1710 254 popl %es
kaf24@1710 255 jmp failsafe_callback
kaf24@1710 256 .previous
kaf24@1710 257 .section __ex_table,"a"
kaf24@1710 258 .align 4
kaf24@1710 259 .long 1b,6b
kaf24@1710 260 .long 2b,7b
kaf24@1710 261 .long 3b,8b
kaf24@1710 262 .long 4b,9b
kaf24@1710 263 .long 5b,10b
kaf24@1710 264 .previous
kaf24@1710 265
kaf24@1710 266 /* No special register assumptions */
kaf24@1710 267 failsafe_callback:
kaf24@1710 268 GET_CURRENT(%ebx)
kaf24@1710 269 movl PROCESSOR(%ebx),%eax
kaf24@1710 270 shl $4,%eax
kaf24@1710 271 lea guest_trap_bounce(%eax),%edx
kaf24@1710 272 movl FAILSAFE_ADDR(%ebx),%eax
kaf24@1710 273 movl %eax,GTB_EIP(%edx)
kaf24@1710 274 movl FAILSAFE_SEL(%ebx),%eax
kaf24@1710 275 movw %ax,GTB_CS(%edx)
kaf24@1710 276 call create_bounce_frame
kaf24@1710 277 subl $16,%esi # add DS/ES/FS/GS to failsafe stack frame
kaf24@1710 278 leal FAILSAFE_BUFFER(%ebx),%ebp
kaf24@1710 279 movl 0(%ebp),%eax # DS
kaf24@1710 280 FAULT1: movl %eax,(%esi)
kaf24@1710 281 movl 4(%ebp),%eax # ES
kaf24@1710 282 FAULT2: movl %eax,4(%esi)
kaf24@1710 283 movl 8(%ebp),%eax # FS
kaf24@1710 284 FAULT3: movl %eax,8(%esi)
kaf24@1710 285 movl 12(%ebp),%eax # GS
kaf24@1710 286 FAULT4: movl %eax,12(%esi)
kaf24@1710 287 movl %esi,OLDESP(%esp)
kaf24@1710 288 popl %ebx
kaf24@1710 289 popl %ecx
kaf24@1710 290 popl %edx
kaf24@1710 291 popl %esi
kaf24@1710 292 popl %edi
kaf24@1710 293 popl %ebp
kaf24@1710 294 popl %eax
kaf24@1710 295 addl $20,%esp # skip DS/ES/FS/GS/ORIG_EAX
kaf24@1710 296 FAULT5: iret
kaf24@1710 297
kaf24@1710 298
kaf24@1710 299 ALIGN
kaf24@1710 300 # Simple restore -- we should never fault as we we will only interrupt ring 0
kaf24@1710 301 # when sane values have been placed in all registers. The only exception is
kaf24@1710 302 # NMI, which may interrupt before good values have been placed in DS-GS.
kaf24@1710 303 # The NMI return code deals with this problem itself.
kaf24@1710 304 restore_all_xen:
kaf24@1710 305 popl %ebx
kaf24@1710 306 popl %ecx
kaf24@1710 307 popl %edx
kaf24@1710 308 popl %esi
kaf24@1710 309 popl %edi
kaf24@1710 310 popl %ebp
kaf24@1710 311 popl %eax
kaf24@1710 312 popl %ds
kaf24@1710 313 popl %es
kaf24@1710 314 popl %fs
kaf24@1710 315 popl %gs
kaf24@1710 316 addl $4,%esp
kaf24@1710 317 iret
kaf24@1710 318
kaf24@1710 319 ALIGN
kaf24@1710 320 ENTRY(hypercall)
kaf24@1710 321 pushl %eax # save orig_eax
kaf24@1710 322 SAVE_ALL
kaf24@1710 323 GET_CURRENT(%ebx)
kaf24@1710 324 andl $(NR_hypercalls-1),%eax
kaf24@1710 325 call *SYMBOL_NAME(hypercall_table)(,%eax,4)
kaf24@1710 326
kaf24@1710 327 ret_from_hypercall:
kaf24@1710 328 movl %eax,EAX(%esp) # save the return value
kaf24@1710 329
kaf24@1710 330 test_all_events:
kaf24@1710 331 xorl %ecx,%ecx
kaf24@1710 332 notl %ecx
kaf24@1710 333 cli # tests must not race interrupts
kaf24@1710 334 /*test_softirqs:*/
kaf24@1710 335 movl PROCESSOR(%ebx),%eax
kaf24@1710 336 shl $6,%eax # sizeof(irq_cpustat) == 64
kaf24@1710 337 test %ecx,SYMBOL_NAME(irq_stat)(%eax,1)
kaf24@1710 338 jnz process_softirqs
kaf24@1710 339 /*test_guest_events:*/
kaf24@1710 340 movl SHARED_INFO(%ebx),%eax
kaf24@1710 341 testb $0xFF,UPCALL_MASK(%eax)
kaf24@1710 342 jnz restore_all_guest
kaf24@1710 343 testb $0xFF,UPCALL_PENDING(%eax)
kaf24@1710 344 jz restore_all_guest
kaf24@1710 345 movb $1,UPCALL_MASK(%eax) # Upcalls are masked during delivery
kaf24@1710 346 /*process_guest_events:*/
kaf24@1710 347 movl PROCESSOR(%ebx),%edx
kaf24@1710 348 shl $4,%edx # sizeof(guest_trap_bounce) == 16
kaf24@1710 349 lea guest_trap_bounce(%edx),%edx
kaf24@1710 350 movl EVENT_ADDR(%ebx),%eax
kaf24@1710 351 movl %eax,GTB_EIP(%edx)
kaf24@1710 352 movl EVENT_SEL(%ebx),%eax
kaf24@1710 353 movw %ax,GTB_CS(%edx)
kaf24@1710 354 call create_bounce_frame
kaf24@1710 355 jmp restore_all_guest
kaf24@1710 356
kaf24@1710 357 ALIGN
kaf24@1710 358 process_softirqs:
kaf24@1710 359 sti
kaf24@1710 360 call SYMBOL_NAME(do_softirq)
kaf24@1710 361 jmp test_all_events
kaf24@1710 362
kaf24@1710 363 /* CREATE A BASIC EXCEPTION FRAME ON GUEST OS (RING-1) STACK: */
kaf24@1710 364 /* {EIP, CS, EFLAGS, [ESP, SS]} */
kaf24@1710 365 /* %edx == guest_trap_bounce, %ebx == task_struct */
kaf24@1710 366 /* %eax,%ecx are clobbered. %ds:%esi contain new OLDSS/OLDESP. */
kaf24@1710 367 create_bounce_frame:
kaf24@1710 368 mov CS+4(%esp),%cl
kaf24@1710 369 test $2,%cl
kaf24@1710 370 jz 1f /* jump if returning to an existing ring-1 activation */
kaf24@1710 371 /* obtain ss/esp from TSS -- no current ring-1 activations */
kaf24@1710 372 movl PROCESSOR(%ebx),%eax
kaf24@1710 373 /* next 4 lines multiply %eax by 8320, which is sizeof(tss_struct) */
kaf24@1710 374 movl %eax, %ecx
kaf24@1710 375 shll $7, %ecx
kaf24@1710 376 shll $13, %eax
kaf24@1710 377 addl %ecx,%eax
kaf24@1710 378 addl $init_tss + 12,%eax
kaf24@1710 379 movl (%eax),%esi /* tss->esp1 */
kaf24@1710 380 FAULT6: movl 4(%eax),%ds /* tss->ss1 */
kaf24@1710 381 /* base of stack frame must contain ss/esp (inter-priv iret) */
kaf24@1710 382 subl $8,%esi
kaf24@1710 383 movl OLDESP+4(%esp),%eax
kaf24@1710 384 FAULT7: movl %eax,(%esi)
kaf24@1710 385 movl OLDSS+4(%esp),%eax
kaf24@1710 386 FAULT8: movl %eax,4(%esi)
kaf24@1710 387 jmp 2f
kaf24@1710 388 1: /* obtain ss/esp from oldss/oldesp -- a ring-1 activation exists */
kaf24@1710 389 movl OLDESP+4(%esp),%esi
kaf24@1710 390 FAULT9: movl OLDSS+4(%esp),%ds
kaf24@1710 391 2: /* Construct a stack frame: EFLAGS, CS/EIP */
kaf24@1710 392 subl $12,%esi
kaf24@1710 393 movl EIP+4(%esp),%eax
kaf24@1710 394 FAULT10:movl %eax,(%esi)
kaf24@1710 395 movl CS+4(%esp),%eax
kaf24@1710 396 FAULT11:movl %eax,4(%esi)
kaf24@1710 397 movl EFLAGS+4(%esp),%eax
kaf24@1710 398 FAULT12:movl %eax,8(%esi)
kaf24@1710 399 /* Rewrite our stack frame and return to ring 1. */
kaf24@1710 400 /* IA32 Ref. Vol. 3: TF, VM, RF and NT flags are cleared on trap. */
kaf24@1710 401 andl $0xfffcbeff,%eax
kaf24@1710 402 movl %eax,EFLAGS+4(%esp)
kaf24@1710 403 movl %ds,OLDSS+4(%esp)
kaf24@1710 404 movl %esi,OLDESP+4(%esp)
kaf24@1710 405 movzwl %es:GTB_CS(%edx),%eax
kaf24@1710 406 movl %eax,CS+4(%esp)
kaf24@1710 407 movl %es:GTB_EIP(%edx),%eax
kaf24@1710 408 movl %eax,EIP+4(%esp)
kaf24@1710 409 ret
kaf24@1710 410
kaf24@1710 411
kaf24@1710 412 .section __ex_table,"a"
kaf24@1710 413 .align 4
kaf24@1710 414 .long FAULT1, crash_domain_fixup3 # Fault writing to ring-1 stack
kaf24@1710 415 .long FAULT2, crash_domain_fixup3 # Fault writing to ring-1 stack
kaf24@1710 416 .long FAULT3, crash_domain_fixup3 # Fault writing to ring-1 stack
kaf24@1710 417 .long FAULT4, crash_domain_fixup3 # Fault writing to ring-1 stack
kaf24@1710 418 .long FAULT5, crash_domain_fixup1 # Fault executing failsafe iret
kaf24@1710 419 .long FAULT6, crash_domain_fixup2 # Fault loading ring-1 stack selector
kaf24@1710 420 .long FAULT7, crash_domain_fixup2 # Fault writing to ring-1 stack
kaf24@1710 421 .long FAULT8, crash_domain_fixup2 # Fault writing to ring-1 stack
kaf24@1710 422 .long FAULT9, crash_domain_fixup2 # Fault loading ring-1 stack selector
kaf24@1710 423 .long FAULT10,crash_domain_fixup2 # Fault writing to ring-1 stack
kaf24@1710 424 .long FAULT11,crash_domain_fixup2 # Fault writing to ring-1 stack
kaf24@1710 425 .long FAULT12,crash_domain_fixup2 # Fault writing to ring-1 stack
kaf24@1710 426 .long FAULT13,crash_domain_fixup3 # Fault writing to ring-1 stack
kaf24@1710 427 .long FAULT14,crash_domain_fixup3 # Fault writing to ring-1 stack
kaf24@1710 428 .previous
kaf24@1710 429
kaf24@1710 430 # This handler kills domains which experience unrecoverable faults.
kaf24@1710 431 .section .fixup,"ax"
kaf24@1710 432 crash_domain_fixup1:
kaf24@1710 433 subl $4,%esp
kaf24@1710 434 SAVE_ALL
kaf24@1710 435 jmp domain_crash
kaf24@1710 436 crash_domain_fixup2:
kaf24@1710 437 addl $4,%esp
kaf24@1710 438 crash_domain_fixup3:
kaf24@1710 439 pushl %ss
kaf24@1710 440 popl %ds
kaf24@1710 441 jmp domain_crash
kaf24@1710 442 .previous
kaf24@1710 443
kaf24@1710 444 ALIGN
kaf24@1710 445 process_guest_exception_and_events:
kaf24@1710 446 movl PROCESSOR(%ebx),%eax
kaf24@1710 447 shl $4,%eax
kaf24@1710 448 lea guest_trap_bounce(%eax),%edx
kaf24@1710 449 testb $~0,GTB_FLAGS(%edx)
kaf24@1710 450 jz test_all_events
kaf24@1710 451 call create_bounce_frame # just the basic frame
kaf24@1710 452 mov %es:GTB_FLAGS(%edx),%cl
kaf24@1710 453 test $GTBF_TRAP_NOCODE,%cl
kaf24@1710 454 jnz 2f
kaf24@1710 455 subl $4,%esi # push error_code onto guest frame
kaf24@1710 456 movl %es:GTB_ERROR_CODE(%edx),%eax
kaf24@1710 457 FAULT13:movl %eax,(%esi)
kaf24@1710 458 test $GTBF_TRAP_CR2,%cl
kaf24@1710 459 jz 1f
kaf24@1710 460 subl $4,%esi # push %cr2 onto guest frame
kaf24@1710 461 movl %es:GTB_CR2(%edx),%eax
kaf24@1710 462 FAULT14:movl %eax,(%esi)
kaf24@1710 463 1: movl %esi,OLDESP(%esp)
kaf24@1710 464 2: push %es # unclobber %ds
kaf24@1710 465 pop %ds
kaf24@1710 466 movb $0,GTB_FLAGS(%edx)
kaf24@1710 467 jmp test_all_events
kaf24@1710 468
kaf24@1710 469 ALIGN
kaf24@1710 470 ENTRY(ret_from_intr)
kaf24@1710 471 GET_CURRENT(%ebx)
kaf24@1710 472 movb CS(%esp),%al
kaf24@1710 473 testb $3,%al # return to non-supervisor?
kaf24@1710 474 jne test_all_events
kaf24@1710 475 jmp restore_all_xen
kaf24@1710 476
kaf24@1710 477 ENTRY(divide_error)
kaf24@1710 478 pushl $0 # no error code
kaf24@1710 479 pushl $ SYMBOL_NAME(do_divide_error)
kaf24@1710 480 ALIGN
kaf24@1710 481 error_code:
kaf24@1710 482 pushl %fs
kaf24@1710 483 pushl %es
kaf24@1710 484 pushl %ds
kaf24@1710 485 pushl %eax
kaf24@1710 486 xorl %eax,%eax
kaf24@1710 487 pushl %ebp
kaf24@1710 488 pushl %edi
kaf24@1710 489 pushl %esi
kaf24@1710 490 pushl %edx
kaf24@1710 491 decl %eax # eax = -1
kaf24@1710 492 pushl %ecx
kaf24@1710 493 pushl %ebx
kaf24@1710 494 cld
kaf24@1710 495 movl %gs,%ecx
kaf24@1710 496 movl ORIG_EAX(%esp), %esi # get the error code
kaf24@1710 497 movl GS(%esp), %edi # get the function address
kaf24@1710 498 movl %eax, ORIG_EAX(%esp)
kaf24@1710 499 movl %ecx, GS(%esp)
kaf24@1710 500 movl $(__HYPERVISOR_DS),%edx
kaf24@1710 501 movl %edx,%ds
kaf24@1710 502 movl %edx,%es
kaf24@1710 503 movl %edx,%fs
kaf24@1710 504 movl %edx,%gs
kaf24@1710 505 movl %esp,%edx
kaf24@1710 506 pushl %esi # push the error code
kaf24@1710 507 pushl %edx # push the pt_regs pointer
kaf24@1710 508 GET_CURRENT(%ebx)
kaf24@1710 509 call *%edi
kaf24@1710 510 addl $8,%esp
kaf24@1710 511 movb CS(%esp),%al
kaf24@1710 512 testb $3,%al
kaf24@1710 513 je restore_all_xen
kaf24@1710 514 jmp process_guest_exception_and_events
kaf24@1710 515
kaf24@1710 516 ENTRY(coprocessor_error)
kaf24@1710 517 pushl $0
kaf24@1710 518 pushl $ SYMBOL_NAME(do_coprocessor_error)
kaf24@1710 519 jmp error_code
kaf24@1710 520
kaf24@1710 521 ENTRY(simd_coprocessor_error)
kaf24@1710 522 pushl $0
kaf24@1710 523 pushl $ SYMBOL_NAME(do_simd_coprocessor_error)
kaf24@1710 524 jmp error_code
kaf24@1710 525
kaf24@1710 526 ENTRY(device_not_available)
kaf24@1710 527 pushl $0
kaf24@1710 528 pushl $SYMBOL_NAME(math_state_restore)
kaf24@1710 529 jmp error_code
kaf24@1710 530
kaf24@1710 531 ENTRY(debug)
kaf24@1710 532 pushl $0
kaf24@1710 533 pushl $ SYMBOL_NAME(do_debug)
kaf24@1710 534 jmp error_code
kaf24@1710 535
kaf24@1710 536 ENTRY(int3)
kaf24@1710 537 pushl $0
kaf24@1710 538 pushl $ SYMBOL_NAME(do_int3)
kaf24@1710 539 jmp error_code
kaf24@1710 540
kaf24@1710 541 ENTRY(overflow)
kaf24@1710 542 pushl $0
kaf24@1710 543 pushl $ SYMBOL_NAME(do_overflow)
kaf24@1710 544 jmp error_code
kaf24@1710 545
kaf24@1710 546 ENTRY(bounds)
kaf24@1710 547 pushl $0
kaf24@1710 548 pushl $ SYMBOL_NAME(do_bounds)
kaf24@1710 549 jmp error_code
kaf24@1710 550
kaf24@1710 551 ENTRY(invalid_op)
kaf24@1710 552 pushl $0
kaf24@1710 553 pushl $ SYMBOL_NAME(do_invalid_op)
kaf24@1710 554 jmp error_code
kaf24@1710 555
kaf24@1710 556 ENTRY(coprocessor_segment_overrun)
kaf24@1710 557 pushl $0
kaf24@1710 558 pushl $ SYMBOL_NAME(do_coprocessor_segment_overrun)
kaf24@1710 559 jmp error_code
kaf24@1710 560
kaf24@1710 561 ENTRY(invalid_TSS)
kaf24@1710 562 pushl $ SYMBOL_NAME(do_invalid_TSS)
kaf24@1710 563 jmp error_code
kaf24@1710 564
kaf24@1710 565 ENTRY(segment_not_present)
kaf24@1710 566 pushl $ SYMBOL_NAME(do_segment_not_present)
kaf24@1710 567 jmp error_code
kaf24@1710 568
kaf24@1710 569 ENTRY(stack_segment)
kaf24@1710 570 pushl $ SYMBOL_NAME(do_stack_segment)
kaf24@1710 571 jmp error_code
kaf24@1710 572
kaf24@1710 573 ENTRY(general_protection)
kaf24@1710 574 pushl $ SYMBOL_NAME(do_general_protection)
kaf24@1710 575 jmp error_code
kaf24@1710 576
kaf24@1710 577 ENTRY(alignment_check)
kaf24@1710 578 pushl $ SYMBOL_NAME(do_alignment_check)
kaf24@1710 579 jmp error_code
kaf24@1710 580
kaf24@1710 581 ENTRY(page_fault)
kaf24@1710 582 pushl $ SYMBOL_NAME(do_page_fault)
kaf24@1710 583 jmp error_code
kaf24@1710 584
kaf24@1710 585 ENTRY(machine_check)
kaf24@1710 586 pushl $0
kaf24@1710 587 pushl $ SYMBOL_NAME(do_machine_check)
kaf24@1710 588 jmp error_code
kaf24@1710 589
kaf24@1710 590 ENTRY(spurious_interrupt_bug)
kaf24@1710 591 pushl $0
kaf24@1710 592 pushl $ SYMBOL_NAME(do_spurious_interrupt_bug)
kaf24@1710 593 jmp error_code
kaf24@1710 594
kaf24@1710 595 ENTRY(nmi)
kaf24@1710 596 # Save state but do not trash the segment registers!
kaf24@1710 597 # We may otherwise be unable to reload them or copy them to ring 1.
kaf24@1710 598 pushl %eax
kaf24@1710 599 SAVE_ALL_NOSEGREGS
kaf24@1710 600
kaf24@1710 601 # Check for hardware problems. These are always fatal so we can
kaf24@1710 602 # reload DS and ES when handling them.
kaf24@1710 603 inb $0x61,%al
kaf24@1710 604 testb $0x80,%al
kaf24@1710 605 jne nmi_parity_err
kaf24@1710 606 testb $0x40,%al
kaf24@1710 607 jne nmi_io_err
kaf24@1710 608 movl %eax,%ebx
kaf24@1710 609
kaf24@1710 610 # Okay, its almost a normal NMI tick. We can only process it if:
kaf24@1710 611 # A. We are the outermost Xen activation (in which case we have
kaf24@1710 612 # the selectors safely saved on our stack)
kaf24@1710 613 # B. DS-GS all contain sane Xen values.
kaf24@1710 614 # In all other cases we bail without touching DS-GS, as we have
kaf24@1710 615 # interrupted an enclosing Xen activation in tricky prologue or
kaf24@1710 616 # epilogue code.
kaf24@1710 617 movb CS(%esp),%al
kaf24@1710 618 testb $3,%al
kaf24@1710 619 jne do_watchdog_tick
kaf24@1710 620 movl DS(%esp),%eax
kaf24@1710 621 cmpw $(__HYPERVISOR_DS),%ax
kaf24@1710 622 jne nmi_badseg
kaf24@1710 623 movl ES(%esp),%eax
kaf24@1710 624 cmpw $(__HYPERVISOR_DS),%ax
kaf24@1710 625 jne nmi_badseg
kaf24@1710 626 movl FS(%esp),%eax
kaf24@1710 627 cmpw $(__HYPERVISOR_DS),%ax
kaf24@1710 628 jne nmi_badseg
kaf24@1710 629 movl GS(%esp),%eax
kaf24@1710 630 cmpw $(__HYPERVISOR_DS),%ax
kaf24@1710 631 jne nmi_badseg
kaf24@1710 632
kaf24@1710 633 do_watchdog_tick:
kaf24@1710 634 movl $(__HYPERVISOR_DS),%edx
kaf24@1710 635 movl %edx,%ds
kaf24@1710 636 movl %edx,%es
kaf24@1710 637 movl %esp,%edx
kaf24@1710 638 pushl %ebx # reason
kaf24@1710 639 pushl %edx # regs
kaf24@1710 640 call SYMBOL_NAME(do_nmi)
kaf24@1710 641 addl $8,%esp
kaf24@1710 642 movb CS(%esp),%al
kaf24@1710 643 testb $3,%al
kaf24@1710 644 je restore_all_xen
kaf24@1710 645 GET_CURRENT(%ebx)
kaf24@1710 646 jmp restore_all_guest
kaf24@1710 647
kaf24@1710 648 nmi_badseg:
kaf24@1710 649 popl %ebx
kaf24@1710 650 popl %ecx
kaf24@1710 651 popl %edx
kaf24@1710 652 popl %esi
kaf24@1710 653 popl %edi
kaf24@1710 654 popl %ebp
kaf24@1710 655 popl %eax
kaf24@1710 656 addl $20,%esp
kaf24@1710 657 iret
kaf24@1710 658
kaf24@1710 659 nmi_parity_err:
kaf24@1710 660 movl $(__HYPERVISOR_DS),%edx
kaf24@1710 661 movl %edx,%ds
kaf24@1710 662 movl %edx,%es
kaf24@1710 663 jmp SYMBOL_NAME(mem_parity_error)
kaf24@1710 664
kaf24@1710 665 nmi_io_err:
kaf24@1710 666 movl $(__HYPERVISOR_DS),%edx
kaf24@1710 667 movl %edx,%ds
kaf24@1710 668 movl %edx,%es
kaf24@1710 669 jmp SYMBOL_NAME(io_check_error)
kaf24@1710 670
kaf24@1710 671 .data
kaf24@1710 672 ENTRY(hypercall_table)
kaf24@1710 673 .long SYMBOL_NAME(do_set_trap_table) /* 0 */
kaf24@1710 674 .long SYMBOL_NAME(do_mmu_update)
kaf24@1710 675 .long SYMBOL_NAME(do_set_gdt)
kaf24@1710 676 .long SYMBOL_NAME(do_stack_switch)
kaf24@1710 677 .long SYMBOL_NAME(do_set_callbacks)
kaf24@1710 678 .long SYMBOL_NAME(do_fpu_taskswitch) /* 5 */
kaf24@1710 679 .long SYMBOL_NAME(do_sched_op)
kaf24@1710 680 .long SYMBOL_NAME(do_dom0_op)
kaf24@1710 681 .long SYMBOL_NAME(do_set_debugreg)
kaf24@1710 682 .long SYMBOL_NAME(do_get_debugreg)
kaf24@1710 683 .long SYMBOL_NAME(do_update_descriptor) /* 10 */
kaf24@1710 684 .long SYMBOL_NAME(do_set_fast_trap)
kaf24@1710 685 .long SYMBOL_NAME(do_dom_mem_op)
kaf24@1710 686 .long SYMBOL_NAME(do_multicall)
kaf24@1710 687 .long SYMBOL_NAME(do_update_va_mapping)
kaf24@1710 688 .long SYMBOL_NAME(do_set_timer_op) /* 15 */
kaf24@1710 689 .long SYMBOL_NAME(do_event_channel_op)
kaf24@1710 690 .long SYMBOL_NAME(do_xen_version)
kaf24@1710 691 .long SYMBOL_NAME(do_console_io)
kaf24@1710 692 .long SYMBOL_NAME(do_physdev_op)
kaf24@1710 693 .long SYMBOL_NAME(do_update_va_mapping_otherdomain) /* 20 */
kaf24@1710 694 .rept NR_hypercalls-((.-hypercall_table)/4)
kaf24@1710 695 .long SYMBOL_NAME(do_ni_hypercall)
kaf24@1710 696 .endr