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