1/* 2 * Copyright 2002-2016, The Haiku Team. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 6 * Copyright 2002, Michael Noisternig. All rights reserved. 7 * Distributed under the terms of the NewOS License. 8 */ 9 10#include <arch/user_debugger.h> 11#include <arch/x86/arch_cpu.h> 12#include <arch/x86/arch_kernel.h> 13#include <arch/x86/descriptors.h> 14#include <asm_defs.h> 15#include <commpage_defs.h> 16#include <thread_types.h> 17 18#include "tracing_config.h" 19 20#include "asm_offsets.h" 21#include "syscall_numbers.h" 22#include "syscall_table.h" 23 24 25#define LOCK_THREAD_TIME() \ 26 lea THREAD_time_lock(%edi), %eax; \ 27 pushl %eax; \ 28 call acquire_spinlock; 29 /* leave spinlock address on stack for UNLOCK_THREAD_TIME() */ 30 31#define UNLOCK_THREAD_TIME() \ 32 /* spinlock address still on stack from */ \ 33 /* LOCK_THREAD_TIME() */ \ 34 call release_spinlock; \ 35 addl $4, %esp; 36 37#define UPDATE_THREAD_USER_TIME_COMMON() \ 38 movl %eax, %ebx; /* save for later */ \ 39 movl %edx, %ecx; \ 40 \ 41 /* thread->user_time += now - thread->last_time; */ \ 42 sub THREAD_last_time(%edi), %eax; \ 43 sbb (THREAD_last_time + 4)(%edi), %edx; \ 44 add %eax, THREAD_user_time(%edi); \ 45 adc %edx, (THREAD_user_time + 4)(%edi); \ 46 \ 47 /* thread->last_time = now; */ \ 48 movl %ebx, THREAD_last_time(%edi); \ 49 movl %ecx, (THREAD_last_time + 4)(%edi); \ 50 \ 51 /* thread->in_kernel = true; */ \ 52 movb $1, THREAD_in_kernel(%edi); 53 54#define UPDATE_THREAD_USER_TIME() \ 55 LOCK_THREAD_TIME() \ 56 call system_time; \ 57 UPDATE_THREAD_USER_TIME_COMMON() \ 58 UNLOCK_THREAD_TIME() 59 60#define UPDATE_THREAD_USER_TIME_PUSH_TIME() \ 61 call system_time; \ 62 push %edx; \ 63 push %eax; \ 64 \ 65 LOCK_THREAD_TIME() \ 66 \ 67 /* recover the system time, note that */ \ 68 /* LOCK_THREAD_TIME() leaves an address on the stack */ \ 69 movl 4(%esp), %eax; \ 70 movl 8(%esp), %edx; \ 71 \ 72 UPDATE_THREAD_USER_TIME_COMMON() \ 73 \ 74 UNLOCK_THREAD_TIME() 75 76#define UPDATE_THREAD_KERNEL_TIME() \ 77 LOCK_THREAD_TIME() \ 78 \ 79 call system_time; \ 80 \ 81 movl %eax, %ebx; /* save for later */ \ 82 movl %edx, %ecx; \ 83 \ 84 /* thread->kernel_time += now - thread->last_time; */ \ 85 sub THREAD_last_time(%edi), %eax; \ 86 sbb (THREAD_last_time + 4)(%edi), %edx; \ 87 add %eax, THREAD_kernel_time(%edi); \ 88 adc %edx, (THREAD_kernel_time + 4)(%edi); \ 89 \ 90 /* thread->last_time = now; */ \ 91 movl %ebx, THREAD_last_time(%edi); \ 92 movl %ecx, (THREAD_last_time + 4)(%edi); \ 93 \ 94 /* thread->in_kernel = false; */ \ 95 movb $0, THREAD_in_kernel(%edi); \ 96 \ 97 UNLOCK_THREAD_TIME() \ 98 99#define PUSH_IFRAME_BOTTOM(iframeType) \ 100 pusha; \ 101 push %ds; \ 102 push %es; \ 103 push %fs; \ 104 push %gs; \ 105 pushl $iframeType 106 107#define PUSH_IFRAME_BOTTOM_SYSCALL() \ 108 pushl $0; \ 109 pushl $99; \ 110 pushl %edx; \ 111 pushl %eax; \ 112 PUSH_IFRAME_BOTTOM(IFRAME_TYPE_SYSCALL) 113 114#define POP_IFRAME_AND_RETURN() \ 115 /* skip iframe type */ \ 116 lea 4(%ebp), %esp; \ 117 \ 118 pop %gs; \ 119 addl $4, %esp; /* we skip %fs, as this contains the CPU \ 120 dependent TLS segment */ \ 121 pop %es; \ 122 pop %ds; \ 123 \ 124 popa; \ 125 addl $16,%esp; /* ignore the vector, error code, and \ 126 original eax/edx values */ \ 127 iret 128 129#define STOP_USER_DEBUGGING() \ 130 testl $(THREAD_FLAGS_BREAKPOINTS_INSTALLED \ 131 | THREAD_FLAGS_SINGLE_STEP), THREAD_flags(%edi); \ 132 jz 1f; \ 133 call x86_exit_user_debug_at_kernel_entry; \ 134 1: 135 136#define COPY_SYSCALL_PARAMETERS() \ 137 /* make room for the syscall params */ \ 138 subl $80, %esp; \ 139 \ 140 /* get the address of the syscall parameters */ \ 141 movl IFRAME_user_sp(%ebp), %esi; \ 142 addl $4, %esi; \ 143 cmp $KERNEL_BASE, %esi; /* must not be a kernel address */ \ 144 jae bad_syscall_params; \ 145 \ 146 /* set the fault handler */ \ 147 movl $bad_syscall_params, THREAD_fault_handler(%edi); \ 148 \ 149 /* target address is our stack */ \ 150 movl %esp, %edi; \ 151 \ 152 /* number of syscall parameter words */ \ 153 movl SYSCALL_INFO_parameter_size(%edx), %ecx; \ 154 shrl $2, %ecx; \ 155 \ 156 /* copy */ \ 157 cld; \ 158 rep movsl; \ 159 \ 160 /* restore pointers and clear fault handler */ \ 161 movl %edx, %esi; /* syscall info pointer */ \ 162 movl %gs:0, %edi; /* thread pointer */ \ 163 movl $0, THREAD_fault_handler(%edi) 164 165#if SYSCALL_TRACING 166# define TRACE_PRE_SYSCALL() \ 167 movl %esp, %eax; /* syscall parameters */ \ 168 push %eax; \ 169 movl IFRAME_orig_eax(%ebp), %eax; /* syscall number */ \ 170 push %eax; \ 171 call trace_pre_syscall; \ 172 addl $8, %esp; 173 174# define TRACE_POST_SYSCALL() \ 175 testl $THREAD_FLAGS_64_BIT_SYSCALL_RETURN, THREAD_flags(%edi); \ 176 jnz 1f; \ 177 xor %edx, %edx; \ 1781: \ 179 push %edx; /* syscall return value */ \ 180 push %eax; \ 181 movl IFRAME_orig_eax(%ebp), %eax; /* syscall number */ \ 182 push %eax; \ 183 call trace_post_syscall; \ 184 addl $12, %esp 185#else 186# define TRACE_PRE_SYSCALL() 187# define TRACE_POST_SYSCALL() 188#endif 189 190 191.text 192 193#define TRAP_ERRC(name, vector) \ 194.align 8; \ 195FUNCTION(name): \ 196 pushl $vector; \ 197 pushl %edx; \ 198 pushl %eax; \ 199 jmp int_bottom; \ 200FUNCTION_END(name) 201 202#define TRAP(name, vector) \ 203.align 8; \ 204FUNCTION(name): \ 205 pushl $0; \ 206 pushl $vector; \ 207 pushl %edx; \ 208 pushl %eax; \ 209 jmp int_bottom; \ 210FUNCTION_END(name) 211 212TRAP(trap0, 0) 213TRAP(trap1, 1) 214TRAP(trap2, 2) 215TRAP(trap3, 3) 216TRAP(trap4, 4) 217TRAP(trap5, 5) 218TRAP(trap6, 6) 219TRAP(trap7, 7) 220 221.align 8; 222FUNCTION(double_fault): 223 pushl $-1; // user-ss 224 pushl $-1; // user-esp 225 pushl $-1; // flags 226 pushl $KERNEL_CODE_SELECTOR // cs 227 pushl $-1; // eip 228 pushl $0; // error-code 229 pushl $8; 230 pushl $-1; 231 pushl $-1; 232 233 PUSH_IFRAME_BOTTOM(IFRAME_TYPE_OTHER) 234 235 movl %esp, %ebp // frame pointer is the iframe 236 237 pushl %ebp 238 call x86_double_fault_exception 239 240 // Well, there's no returning from a double fault, but maybe a real hacker 241 // can repair things in KDL. 242 POP_IFRAME_AND_RETURN() 243FUNCTION_END(double_fault) 244 245 246TRAP(trap9, 9) 247TRAP_ERRC(trap10, 10) 248TRAP_ERRC(trap11, 11) 249TRAP_ERRC(trap12, 12) 250TRAP_ERRC(trap13, 13) 251TRAP_ERRC(trap14, 14) 252/*TRAP(trap15, 15)*/ 253TRAP(trap16, 16) 254TRAP_ERRC(trap17, 17) 255TRAP(trap18, 18) 256TRAP(trap19, 19) 257 258// legacy or ioapic interrupts 259TRAP(trap32, 32) 260TRAP(trap33, 33) 261TRAP(trap34, 34) 262TRAP(trap35, 35) 263TRAP(trap36, 36) 264TRAP(trap37, 37) 265TRAP(trap38, 38) 266TRAP(trap39, 39) 267TRAP(trap40, 40) 268TRAP(trap41, 41) 269TRAP(trap42, 42) 270TRAP(trap43, 43) 271TRAP(trap44, 44) 272TRAP(trap45, 45) 273TRAP(trap46, 46) 274TRAP(trap47, 47) 275 276// additional ioapic interrupts 277TRAP(trap48, 48) 278TRAP(trap49, 49) 279TRAP(trap50, 50) 280TRAP(trap51, 51) 281TRAP(trap52, 52) 282TRAP(trap53, 53) 283TRAP(trap54, 54) 284TRAP(trap55, 55) 285 286// configurable msi or msi-x interrupts 287TRAP(trap56, 56) 288TRAP(trap57, 57) 289TRAP(trap58, 58) 290TRAP(trap59, 59) 291TRAP(trap60, 60) 292TRAP(trap61, 61) 293TRAP(trap62, 62) 294TRAP(trap63, 63) 295TRAP(trap64, 64) 296TRAP(trap65, 65) 297TRAP(trap66, 66) 298TRAP(trap67, 67) 299TRAP(trap68, 68) 300TRAP(trap69, 69) 301TRAP(trap70, 70) 302TRAP(trap71, 71) 303TRAP(trap72, 72) 304TRAP(trap73, 73) 305TRAP(trap74, 74) 306TRAP(trap75, 75) 307TRAP(trap76, 76) 308TRAP(trap77, 77) 309TRAP(trap78, 78) 310TRAP(trap79, 79) 311TRAP(trap80, 80) 312TRAP(trap81, 81) 313TRAP(trap82, 82) 314TRAP(trap83, 83) 315TRAP(trap84, 84) 316TRAP(trap85, 85) 317TRAP(trap86, 86) 318TRAP(trap87, 87) 319TRAP(trap88, 88) 320TRAP(trap89, 89) 321TRAP(trap90, 90) 322TRAP(trap91, 91) 323TRAP(trap92, 92) 324TRAP(trap93, 93) 325TRAP(trap94, 94) 326TRAP(trap95, 95) 327TRAP(trap96, 96) 328TRAP(trap97, 97) 329//TRAP(trap98, 98) // performance testing interrupt 330//TRAP(trap99, 99) // syscall interrupt 331TRAP(trap100, 100) 332TRAP(trap101, 101) 333TRAP(trap102, 102) 334TRAP(trap103, 103) 335TRAP(trap104, 104) 336TRAP(trap105, 105) 337TRAP(trap106, 106) 338TRAP(trap107, 107) 339TRAP(trap108, 108) 340TRAP(trap109, 109) 341TRAP(trap110, 110) 342TRAP(trap111, 111) 343TRAP(trap112, 112) 344TRAP(trap113, 113) 345TRAP(trap114, 114) 346TRAP(trap115, 115) 347TRAP(trap116, 116) 348TRAP(trap117, 117) 349TRAP(trap118, 118) 350TRAP(trap119, 119) 351TRAP(trap120, 120) 352TRAP(trap121, 121) 353TRAP(trap122, 122) 354TRAP(trap123, 123) 355TRAP(trap124, 124) 356TRAP(trap125, 125) 357TRAP(trap126, 126) 358TRAP(trap127, 127) 359TRAP(trap128, 128) 360TRAP(trap129, 129) 361TRAP(trap130, 130) 362TRAP(trap131, 131) 363TRAP(trap132, 132) 364TRAP(trap133, 133) 365TRAP(trap134, 134) 366TRAP(trap135, 135) 367TRAP(trap136, 136) 368TRAP(trap137, 137) 369TRAP(trap138, 138) 370TRAP(trap139, 139) 371TRAP(trap140, 140) 372TRAP(trap141, 141) 373TRAP(trap142, 142) 374TRAP(trap143, 143) 375TRAP(trap144, 144) 376TRAP(trap145, 145) 377TRAP(trap146, 146) 378TRAP(trap147, 147) 379TRAP(trap148, 148) 380TRAP(trap149, 149) 381TRAP(trap150, 150) 382TRAP(trap151, 151) 383TRAP(trap152, 152) 384TRAP(trap153, 153) 385TRAP(trap154, 154) 386TRAP(trap155, 155) 387TRAP(trap156, 156) 388TRAP(trap157, 157) 389TRAP(trap158, 158) 390TRAP(trap159, 159) 391TRAP(trap160, 160) 392TRAP(trap161, 161) 393TRAP(trap162, 162) 394TRAP(trap163, 163) 395TRAP(trap164, 164) 396TRAP(trap165, 165) 397TRAP(trap166, 166) 398TRAP(trap167, 167) 399TRAP(trap168, 168) 400TRAP(trap169, 169) 401TRAP(trap170, 170) 402TRAP(trap171, 171) 403TRAP(trap172, 172) 404TRAP(trap173, 173) 405TRAP(trap174, 174) 406TRAP(trap175, 175) 407TRAP(trap176, 176) 408TRAP(trap177, 177) 409TRAP(trap178, 178) 410TRAP(trap179, 179) 411TRAP(trap180, 180) 412TRAP(trap181, 181) 413TRAP(trap182, 182) 414TRAP(trap183, 183) 415TRAP(trap184, 184) 416TRAP(trap185, 185) 417TRAP(trap186, 186) 418TRAP(trap187, 187) 419TRAP(trap188, 188) 420TRAP(trap189, 189) 421TRAP(trap190, 190) 422TRAP(trap191, 191) 423TRAP(trap192, 192) 424TRAP(trap193, 193) 425TRAP(trap194, 194) 426TRAP(trap195, 195) 427TRAP(trap196, 196) 428TRAP(trap197, 197) 429TRAP(trap198, 198) 430TRAP(trap199, 199) 431TRAP(trap200, 200) 432TRAP(trap201, 201) 433TRAP(trap202, 202) 434TRAP(trap203, 203) 435TRAP(trap204, 204) 436TRAP(trap205, 205) 437TRAP(trap206, 206) 438TRAP(trap207, 207) 439TRAP(trap208, 208) 440TRAP(trap209, 209) 441TRAP(trap210, 210) 442TRAP(trap211, 211) 443TRAP(trap212, 212) 444TRAP(trap213, 213) 445TRAP(trap214, 214) 446TRAP(trap215, 215) 447TRAP(trap216, 216) 448TRAP(trap217, 217) 449TRAP(trap218, 218) 450TRAP(trap219, 219) 451TRAP(trap220, 220) 452TRAP(trap221, 221) 453TRAP(trap222, 222) 454TRAP(trap223, 223) 455TRAP(trap224, 224) 456TRAP(trap225, 225) 457TRAP(trap226, 226) 458TRAP(trap227, 227) 459TRAP(trap228, 228) 460TRAP(trap229, 229) 461TRAP(trap230, 230) 462TRAP(trap231, 231) 463TRAP(trap232, 232) 464TRAP(trap233, 233) 465TRAP(trap234, 234) 466TRAP(trap235, 235) 467TRAP(trap236, 236) 468TRAP(trap237, 237) 469TRAP(trap238, 238) 470TRAP(trap239, 239) 471TRAP(trap240, 240) 472TRAP(trap241, 241) 473TRAP(trap242, 242) 474TRAP(trap243, 243) 475TRAP(trap244, 244) 476TRAP(trap245, 245) 477TRAP(trap246, 246) 478TRAP(trap247, 247) 479TRAP(trap248, 248) 480TRAP(trap249, 249) 481TRAP(trap250, 250) 482 483// smp / apic local interrupts 484TRAP(trap251, 251) 485TRAP(trap252, 252) 486TRAP(trap253, 253) 487TRAP(trap254, 254) 488TRAP(trap255, 255) 489 490 491.align 8; 492FUNCTION(trap14_double_fault): 493 pushl $14 494 pushl $-1 495 pushl $-1 496 497 PUSH_IFRAME_BOTTOM(IFRAME_TYPE_OTHER) 498 499 movl %esp, %ebp // frame pointer is the iframe 500 501 pushl %ebp 502 call x86_page_fault_exception_double_fault 503 504 POP_IFRAME_AND_RETURN() 505FUNCTION_END(trap14_double_fault) 506 507 508.align 16 509STATIC_FUNCTION(int_bottom): 510 PUSH_IFRAME_BOTTOM(IFRAME_TYPE_OTHER) 511 512 movl $KERNEL_TLS_SELECTOR, %edx 513 movw %dx, %gs 514 515 movl %esp, %ebp // frame pointer is the iframe 516 517 // Set the RF (resume flag) in EFLAGS. This prevents an instruction 518 // breakpoint on the instruction we're returning to to trigger a debug 519 // exception. 520 orl $0x10000, IFRAME_flags(%ebp); 521 522 cmpw $USER_CODE_SELECTOR, IFRAME_cs(%ebp) // user mode 523 je int_bottom_user 524 525 // We need to recheck user mode using the thread's in_kernel flag, since 526 // sysexit introduces a raced condition: It doesn't reenable interrupts, 527 // so that we have to do it in the instruction before, thus opening a 528 // window for an interrupt while still being in the kernel, but having set 529 // up everything for userland already. 530 movl %gs:0, %edi // thread pointer 531 cmpb $0, THREAD_in_kernel(%edi) 532 je int_bottom_user 533 534 // disable interrupts -- the handler will enable them, if necessary 535 cli 536 537 pushl %ebp 538 movl IFRAME_vector(%ebp), %eax 539 call *gInterruptHandlerTable(, %eax, 4) 540 541 POP_IFRAME_AND_RETURN() 542FUNCTION_END(int_bottom) 543 544 545STATIC_FUNCTION(int_bottom_user): 546 movl $KERNEL_DATA_SELECTOR, %eax 547 cld 548 movl %eax,%ds 549 movl %eax,%es 550 551 // disable breakpoints, if installed 552 movl %gs:0, %edi // thread pointer 553 cli // disable interrupts 554 STOP_USER_DEBUGGING() 555 556 // update the thread's user time 557 UPDATE_THREAD_USER_TIME() 558 559 // leave interrupts disabled -- the handler will enable them, if 560 // necessary 561 562 pushl %ebp 563 movl IFRAME_vector(%ebp), %eax 564 call *gInterruptHandlerTable(, %eax, 4) 565 566 // Don't do any kernel exit work, if we actually came from the kernel (but 567 // were already/still prepared for userland), since the iframe in this case 568 // will be a kernel iframe and e.g. trying to set up a signal stack will not 569 // be a very healthy endeavor. 570 cmpw $USER_CODE_SELECTOR, IFRAME_cs(%ebp) 571 jne 1f 572 573 testl $(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \ 574 | THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED \ 575 | THREAD_FLAGS_TRAP_FOR_CORE_DUMP) \ 576 , THREAD_flags(%edi) 577 jnz kernel_exit_work 5781: 579 580 cli // disable interrupts 581 582 // update the thread's kernel time and return 583 UPDATE_THREAD_KERNEL_TIME() 584 POP_IFRAME_AND_RETURN() 585FUNCTION_END(int_bottom_user) 586 587 588// test interrupt handler for performance measurements 589.align 16 590FUNCTION(trap98): 591 iret 592FUNCTION_END(trap98) 593 594 595.align 16 596FUNCTION(trap99): 597 // push error, vector, orig_edx, orig_eax, and other registers 598 PUSH_IFRAME_BOTTOM_SYSCALL() 599 600 call handle_syscall 601 602 POP_IFRAME_AND_RETURN() 603FUNCTION_END(trap99) 604 605 606STATIC_FUNCTION(handle_syscall): 607 movl $KERNEL_TLS_SELECTOR, %edx 608 movw %dx, %gs 609 610 // save %eax, the number of the syscall 611 movl %eax, %esi 612 613 movl $KERNEL_DATA_SELECTOR, %eax 614 cld 615 movl %eax,%ds 616 movl %eax,%es 617 618 lea 4(%esp), %ebp // skipping the return address, the stack 619 // frame pointer is the iframe 620 movl %gs:0, %edi // thread pointer 621 622 // disable breakpoints, if installed 623 cli // disable interrupts 624 STOP_USER_DEBUGGING() 625 626 // update the thread's user time 627 UPDATE_THREAD_USER_TIME_PUSH_TIME() 628 // leave the time on the stack (needed for post syscall debugging) 629 630 sti // enable interrupts 631 632 cmp $SYSCALL_COUNT, %esi // check syscall number 633 jae bad_syscall_number 634 movl $kSyscallInfos, %eax // get syscall info 635 lea (%eax, %esi, SYSCALL_INFO_sizeof), %edx 636 637 // copy parameters onto this stack 638 COPY_SYSCALL_PARAMETERS() 639 640 // pre syscall debugging 641 TRACE_PRE_SYSCALL() 642 testl $THREAD_FLAGS_DEBUGGER_INSTALLED, THREAD_flags(%edi) 643 jnz do_pre_syscall_debug 644 pre_syscall_debug_done: 645 646 // call the syscall function 647 call *SYSCALL_INFO_function(%esi) 648 649 // overwrite the values of %eax and %edx on the stack (the syscall return value) 650 testl $THREAD_FLAGS_64_BIT_SYSCALL_RETURN, THREAD_flags(%edi) 651 jz 1f 652 movl %edx, IFRAME_dx(%ebp) 653 1: 654 movl %eax, IFRAME_ax(%ebp) 655 656 TRACE_POST_SYSCALL() 657 658 testl $(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \ 659 | THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED \ 660 | THREAD_FLAGS_TRAP_FOR_CORE_DUMP \ 661 | THREAD_FLAGS_64_BIT_SYSCALL_RETURN \ 662 | THREAD_FLAGS_RESTART_SYSCALL | THREAD_FLAGS_SYSCALL_RESTARTED) \ 663 , THREAD_flags(%edi) 664 jnz post_syscall_work 665 666 cli // disable interrupts 667 668 // update the thread's kernel time 669 UPDATE_THREAD_KERNEL_TIME() 670 671 lea -4(%ebp), %esp // remove all parameters from the stack 672 673 ret 674FUNCTION_END(handle_syscall) 675 676 STATIC_FUNCTION(do_pre_syscall_debug): 677 movl %esp, %eax // syscall parameters 678 push %eax 679 movl IFRAME_orig_eax(%ebp), %eax // syscall number 680 push %eax 681 call user_debug_pre_syscall 682 addl $8, %esp 683 jmp pre_syscall_debug_done 684 FUNCTION_END(do_pre_syscall_debug) 685 686 STATIC_FUNCTION(post_syscall_work): 687 // post syscall debugging 688 testl $THREAD_FLAGS_DEBUGGER_INSTALLED, THREAD_flags(%edi) 689 jz 2f 690 pushl -8(%ebp) // syscall start time 691 pushl -12(%ebp) 692 xor %edx, %edx 693 testl $THREAD_FLAGS_64_BIT_SYSCALL_RETURN, THREAD_flags(%edi) 694 jz 1f 695 movl IFRAME_dx(%ebp), %edx // syscall return value 696 1: 697 movl IFRAME_ax(%ebp), %eax 698 push %edx 699 push %eax 700 lea 16(%esp), %eax // syscall parameters 701 push %eax 702 movl IFRAME_orig_eax(%ebp), %eax // syscall number 703 push %eax 704 call user_debug_post_syscall 705 addl $24, %esp 706 707 2: 708 // clear the 64 bit return value and syscall restarted bits 709 testl $(THREAD_FLAGS_64_BIT_SYSCALL_RETURN \ 710 | THREAD_FLAGS_SYSCALL_RESTARTED), THREAD_flags(%edi) 711 jz 2f 712 1: 713 movl THREAD_flags(%edi), %eax 714 movl %eax, %edx 715 andl $~(THREAD_FLAGS_64_BIT_SYSCALL_RETURN \ 716 | THREAD_FLAGS_SYSCALL_RESTARTED), %edx 717 lock 718 cmpxchgl %edx, THREAD_flags(%edi) 719 jnz 1b 720 2: 721 FUNCTION_END(post_syscall_work) 722 723 bad_syscall_number: 724 STATIC_FUNCTION(kernel_exit_work): 725 // if no signals are pending and the thread shall not be debugged or stopped 726 // for a core dump, we can use the quick kernel exit function 727 testl $(THREAD_FLAGS_SIGNALS_PENDING | THREAD_FLAGS_DEBUG_THREAD \ 728 | THREAD_FLAGS_TRAP_FOR_CORE_DUMP) \ 729 , THREAD_flags(%edi) 730 jnz kernel_exit_handle_signals 731 cli // disable interrupts 732 call thread_at_kernel_exit_no_signals 733 kernel_exit_work_done: 734 735 // syscall restart 736 // TODO: this only needs to be done for syscalls! 737 testl $THREAD_FLAGS_RESTART_SYSCALL, THREAD_flags(%edi) 738 jz 1f 739 push %ebp 740 call x86_restart_syscall 741 addl $4, %esp 742 1: 743 744 // install breakpoints, if defined 745 testl $THREAD_FLAGS_BREAKPOINTS_DEFINED, THREAD_flags(%edi) 746 jz 1f 747 push %ebp 748 call x86_init_user_debug_at_kernel_exit 749 1: 750 POP_IFRAME_AND_RETURN() 751 FUNCTION_END(kernel_exit_work) 752 753 STATIC_FUNCTION(kernel_exit_handle_signals): 754 // make sure interrupts are enabled (they are, when coming from a syscall 755 // but otherwise they might be disabled) 756 sti 757 call thread_at_kernel_exit // also disables interrupts 758 jmp kernel_exit_work_done 759 FUNCTION_END(kernel_exit_handle_signals) 760 761 STATIC_FUNCTION(bad_syscall_params): 762 // clear the fault handler and exit normally 763 movl %gs:0, %edi 764 movl $0, THREAD_fault_handler(%edi) 765 jmp kernel_exit_work 766 FUNCTION_END(bad_syscall_params) 767 768 769/*! Handler called by the sysenter instruction 770 ecx - user esp 771*/ 772FUNCTION(x86_sysenter): 773 // get the thread 774 push %gs 775 movl $KERNEL_TLS_SELECTOR, %edx 776 movw %dx, %gs 777 movl %gs:0, %edx 778 pop %gs 779 780 // push the iframe 781 pushl $USER_DATA_SELECTOR // user_ss 782 pushl %ecx // user_esp 783 pushfl // eflags 784 orl $(1 << 9), (%esp) // set the IF (interrupts) bit 785 pushl $USER_CODE_SELECTOR // user cs 786 787 // user_eip 788 movl THREAD_team(%edx), %edx 789 movl TEAM_commpage_address(%edx), %edx 790 addl 4 * COMMPAGE_ENTRY_X86_SYSCALL(%edx), %edx 791 addl $4, %edx // sysenter is at offset 2, 2 bytes long 792 pushl %edx 793 794 PUSH_IFRAME_BOTTOM_SYSCALL() 795 796 call handle_syscall 797 798 // pop the bottom of the iframe 799 lea 4(%ebp), %esp // skip iframe type 800 801 pop %gs 802 addl $4, %esp /* we skip %fs, as this contains the CPU 803 dependent TLS segment */ 804 pop %es 805 pop %ds 806 807 popa 808 809 // ecx already contains the user esp -- load edx with the return address 810 movl 16(%esp), %edx 811 812 // pop eflags, which also reenables interrupts 813 addl $24, %esp // skip, orig_eax/edx, vector, error_code, eip, cs 814 popfl 815 816 sysexit 817FUNCTION_END(x86_sysenter) 818 819 820/*! \fn void x86_return_to_userland(iframe* frame) 821 \brief Returns to the userland environment given by \a frame. 822 823 Before returning to userland all potentially necessary kernel exit work is 824 done. 825 826 \a frame must point to a location somewhere on the caller's stack (e.g. a 827 local variable). 828 The function must be called with interrupts disabled. 829 830 \param frame The iframe defining the userland environment. 831*/ 832FUNCTION(x86_return_to_userland): 833 // get the iframe* parameter 834 movl 4(%esp), %ebp 835 movl %ebp, %esp 836 837 // check, if any kernel exit work has to be done 838 movl %gs:0, %edi 839 testl $(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \ 840 | THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED \ 841 | THREAD_FLAGS_TRAP_FOR_CORE_DUMP) \ 842 , THREAD_flags(%edi) 843 jnz kernel_exit_work 844 845 // update the thread's kernel time and return 846 UPDATE_THREAD_KERNEL_TIME() 847 POP_IFRAME_AND_RETURN() 848FUNCTION_END(x86_return_to_userland) 849