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 650 // value) 651 movl %edx, IFRAME_dx(%ebp) 652 movl %eax, IFRAME_ax(%ebp) 653 654 TRACE_POST_SYSCALL() 655 656 testl $(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \ 657 | THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED \ 658 | THREAD_FLAGS_TRAP_FOR_CORE_DUMP \ 659 | THREAD_FLAGS_64_BIT_SYSCALL_RETURN \ 660 | THREAD_FLAGS_RESTART_SYSCALL | THREAD_FLAGS_SYSCALL_RESTARTED) \ 661 , THREAD_flags(%edi) 662 jnz post_syscall_work 663 664 cli // disable interrupts 665 666 // update the thread's kernel time 667 UPDATE_THREAD_KERNEL_TIME() 668 669 lea -4(%ebp), %esp // remove all parameters from the stack 670 671 ret 672FUNCTION_END(handle_syscall) 673 674 STATIC_FUNCTION(do_pre_syscall_debug): 675 movl %esp, %eax // syscall parameters 676 push %eax 677 movl IFRAME_orig_eax(%ebp), %eax // syscall number 678 push %eax 679 call user_debug_pre_syscall 680 addl $8, %esp 681 jmp pre_syscall_debug_done 682 FUNCTION_END(do_pre_syscall_debug) 683 684 STATIC_FUNCTION(post_syscall_work): 685 // clear the 64 bit return value and syscall restarted bits 686 testl $(THREAD_FLAGS_64_BIT_SYSCALL_RETURN \ 687 | THREAD_FLAGS_SYSCALL_RESTARTED), THREAD_flags(%edi) 688 jz 2f 689 1: 690 movl THREAD_flags(%edi), %eax 691 movl %eax, %edx 692 andl $~(THREAD_FLAGS_64_BIT_SYSCALL_RETURN \ 693 | THREAD_FLAGS_SYSCALL_RESTARTED), %edx 694 lock 695 cmpxchgl %edx, THREAD_flags(%edi) 696 jnz 1b 697 2: 698 699 // post syscall debugging 700 testl $THREAD_FLAGS_DEBUGGER_INSTALLED, THREAD_flags(%edi) 701 jz 1f 702 pushl -8(%ebp) // syscall start time 703 pushl -12(%ebp) 704 movl IFRAME_dx(%ebp), %edx // syscall return value 705 movl IFRAME_ax(%ebp), %eax 706 push %edx 707 push %eax 708 lea 16(%esp), %eax // syscall parameters 709 push %eax 710 movl IFRAME_orig_eax(%ebp), %eax // syscall number 711 push %eax 712 call user_debug_post_syscall 713 addl $24, %esp 714 1: 715 FUNCTION_END(post_syscall_work) 716 717 bad_syscall_number: 718 STATIC_FUNCTION(kernel_exit_work): 719 // if no signals are pending and the thread shall not be debugged or stopped 720 // for a core dump, we can use the quick kernel exit function 721 testl $(THREAD_FLAGS_SIGNALS_PENDING | THREAD_FLAGS_DEBUG_THREAD \ 722 | THREAD_FLAGS_TRAP_FOR_CORE_DUMP) \ 723 , THREAD_flags(%edi) 724 jnz kernel_exit_handle_signals 725 cli // disable interrupts 726 call thread_at_kernel_exit_no_signals 727 kernel_exit_work_done: 728 729 // syscall restart 730 // TODO: this only needs to be done for syscalls! 731 testl $THREAD_FLAGS_RESTART_SYSCALL, THREAD_flags(%edi) 732 jz 1f 733 push %ebp 734 call x86_restart_syscall 735 addl $4, %esp 736 1: 737 738 // install breakpoints, if defined 739 testl $THREAD_FLAGS_BREAKPOINTS_DEFINED, THREAD_flags(%edi) 740 jz 1f 741 push %ebp 742 call x86_init_user_debug_at_kernel_exit 743 1: 744 POP_IFRAME_AND_RETURN() 745 FUNCTION_END(kernel_exit_work) 746 747 STATIC_FUNCTION(kernel_exit_handle_signals): 748 // make sure interrupts are enabled (they are, when coming from a syscall 749 // but otherwise they might be disabled) 750 sti 751 call thread_at_kernel_exit // also disables interrupts 752 jmp kernel_exit_work_done 753 FUNCTION_END(kernel_exit_handle_signals) 754 755 STATIC_FUNCTION(bad_syscall_params): 756 // clear the fault handler and exit normally 757 movl %gs:0, %edi 758 movl $0, THREAD_fault_handler(%edi) 759 jmp kernel_exit_work 760 FUNCTION_END(bad_syscall_params) 761 762 763/*! Handler called by the sysenter instruction 764 ecx - user esp 765*/ 766FUNCTION(x86_sysenter): 767 // get the thread 768 push %gs 769 movl $KERNEL_TLS_SELECTOR, %edx 770 movw %dx, %gs 771 movl %gs:0, %edx 772 pop %gs 773 774 // push the iframe 775 pushl $USER_DATA_SELECTOR // user_ss 776 pushl %ecx // user_esp 777 pushfl // eflags 778 orl $(1 << 9), (%esp) // set the IF (interrupts) bit 779 pushl $USER_CODE_SELECTOR // user cs 780 781 // user_eip 782 movl THREAD_team(%edx), %edx 783 movl TEAM_commpage_address(%edx), %edx 784 addl 4 * COMMPAGE_ENTRY_X86_SYSCALL(%edx), %edx 785 addl $4, %edx // sysenter is at offset 2, 2 bytes long 786 pushl %edx 787 788 PUSH_IFRAME_BOTTOM_SYSCALL() 789 790 call handle_syscall 791 792 // pop the bottom of the iframe 793 lea 4(%ebp), %esp // skip iframe type 794 795 pop %gs 796 addl $4, %esp /* we skip %fs, as this contains the CPU 797 dependent TLS segment */ 798 pop %es 799 pop %ds 800 801 popa 802 803 // ecx already contains the user esp -- load edx with the return address 804 movl 16(%esp), %edx 805 806 // pop eflags, which also reenables interrupts 807 addl $24, %esp // skip, orig_eax/edx, vector, error_code, eip, cs 808 popfl 809 810 sysexit 811FUNCTION_END(x86_sysenter) 812 813 814/*! \fn void x86_return_to_userland(iframe* frame) 815 \brief Returns to the userland environment given by \a frame. 816 817 Before returning to userland all potentially necessary kernel exit work is 818 done. 819 820 \a frame must point to a location somewhere on the caller's stack (e.g. a 821 local variable). 822 The function must be called with interrupts disabled. 823 824 \param frame The iframe defining the userland environment. 825*/ 826FUNCTION(x86_return_to_userland): 827 // get the iframe* parameter 828 movl 4(%esp), %ebp 829 movl %ebp, %esp 830 831 // check, if any kernel exit work has to be done 832 movl %gs:0, %edi 833 testl $(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \ 834 | THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED \ 835 | THREAD_FLAGS_TRAP_FOR_CORE_DUMP) \ 836 , THREAD_flags(%edi) 837 jnz kernel_exit_work 838 839 // update the thread's kernel time and return 840 UPDATE_THREAD_KERNEL_TIME() 841 POP_IFRAME_AND_RETURN() 842FUNCTION_END(x86_return_to_userland) 843