1/* 2 * Copyright 2002-2011, 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(%edi) 576 jnz kernel_exit_work 5771: 578 579 cli // disable interrupts 580 581 // update the thread's kernel time and return 582 UPDATE_THREAD_KERNEL_TIME() 583 POP_IFRAME_AND_RETURN() 584FUNCTION_END(int_bottom_user) 585 586 587// test interrupt handler for performance measurements 588.align 16 589FUNCTION(trap98): 590 iret 591FUNCTION_END(trap98) 592 593 594.align 16 595FUNCTION(trap99): 596 // push error, vector, orig_edx, orig_eax, and other registers 597 PUSH_IFRAME_BOTTOM_SYSCALL() 598 599 call handle_syscall 600 601 POP_IFRAME_AND_RETURN() 602FUNCTION_END(trap99) 603 604 605STATIC_FUNCTION(handle_syscall): 606 movl $KERNEL_TLS_SELECTOR, %edx 607 movw %dx, %gs 608 609 // save %eax, the number of the syscall 610 movl %eax, %esi 611 612 movl $KERNEL_DATA_SELECTOR, %eax 613 cld 614 movl %eax,%ds 615 movl %eax,%es 616 617 lea 4(%esp), %ebp // skipping the return address, the stack 618 // frame pointer is the iframe 619 movl %gs:0, %edi // thread pointer 620 621 // disable breakpoints, if installed 622 cli // disable interrupts 623 STOP_USER_DEBUGGING() 624 625 // update the thread's user time 626 UPDATE_THREAD_USER_TIME_PUSH_TIME() 627 // leave the time on the stack (needed for post syscall debugging) 628 629 sti // enable interrupts 630 631 cmp $SYSCALL_COUNT, %esi // check syscall number 632 jae bad_syscall_number 633 movl $kSyscallInfos, %eax // get syscall info 634 lea (%eax, %esi, SYSCALL_INFO_sizeof), %edx 635 636 // copy parameters onto this stack 637 COPY_SYSCALL_PARAMETERS() 638 639 // pre syscall debugging 640 TRACE_PRE_SYSCALL() 641 testl $THREAD_FLAGS_DEBUGGER_INSTALLED, THREAD_flags(%edi) 642 jnz do_pre_syscall_debug 643 pre_syscall_debug_done: 644 645 // call the syscall function 646 call *SYSCALL_INFO_function(%esi) 647 648 // overwrite the values of %eax and %edx on the stack (the syscall return 649 // value) 650 movl %edx, IFRAME_dx(%ebp) 651 movl %eax, IFRAME_ax(%ebp) 652 653 TRACE_POST_SYSCALL() 654 655 testl $(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \ 656 | THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED \ 657 | THREAD_FLAGS_64_BIT_SYSCALL_RETURN \ 658 | THREAD_FLAGS_RESTART_SYSCALL | THREAD_FLAGS_SYSCALL_RESTARTED) \ 659 , THREAD_flags(%edi) 660 jnz post_syscall_work 661 662 cli // disable interrupts 663 664 // update the thread's kernel time 665 UPDATE_THREAD_KERNEL_TIME() 666 667 lea -4(%ebp), %esp // remove all parameters from the stack 668 669 ret 670FUNCTION_END(handle_syscall) 671 672 STATIC_FUNCTION(do_pre_syscall_debug): 673 movl %esp, %eax // syscall parameters 674 push %eax 675 movl IFRAME_orig_eax(%ebp), %eax // syscall number 676 push %eax 677 call user_debug_pre_syscall 678 addl $8, %esp 679 jmp pre_syscall_debug_done 680 FUNCTION_END(do_pre_syscall_debug) 681 682 STATIC_FUNCTION(post_syscall_work): 683 // clear the 64 bit return value and syscall restarted bits 684 testl $(THREAD_FLAGS_64_BIT_SYSCALL_RETURN \ 685 | THREAD_FLAGS_SYSCALL_RESTARTED), THREAD_flags(%edi) 686 jz 2f 687 1: 688 movl THREAD_flags(%edi), %eax 689 movl %eax, %edx 690 andl $~(THREAD_FLAGS_64_BIT_SYSCALL_RETURN \ 691 | THREAD_FLAGS_SYSCALL_RESTARTED), %edx 692 lock 693 cmpxchgl %edx, THREAD_flags(%edi) 694 jnz 1b 695 2: 696 697 // post syscall debugging 698 testl $THREAD_FLAGS_DEBUGGER_INSTALLED, THREAD_flags(%edi) 699 jz 1f 700 pushl -8(%ebp) // syscall start time 701 pushl -12(%ebp) 702 movl IFRAME_dx(%ebp), %edx // syscall return value 703 movl IFRAME_ax(%ebp), %eax 704 push %edx 705 push %eax 706 lea 16(%esp), %eax // syscall parameters 707 push %eax 708 movl IFRAME_orig_eax(%ebp), %eax // syscall number 709 push %eax 710 call user_debug_post_syscall 711 addl $24, %esp 712 1: 713 FUNCTION_END(post_syscall_work) 714 715 bad_syscall_number: 716 STATIC_FUNCTION(kernel_exit_work): 717 // if no signals are pending and the thread shall not be debugged, we can 718 // use the quick kernel exit function 719 testl $(THREAD_FLAGS_SIGNALS_PENDING | THREAD_FLAGS_DEBUG_THREAD) \ 720 , THREAD_flags(%edi) 721 jnz kernel_exit_handle_signals 722 cli // disable interrupts 723 call thread_at_kernel_exit_no_signals 724 kernel_exit_work_done: 725 726 // syscall restart 727 // TODO: this only needs to be done for syscalls! 728 testl $THREAD_FLAGS_RESTART_SYSCALL, THREAD_flags(%edi) 729 jz 1f 730 push %ebp 731 call x86_restart_syscall 732 addl $4, %esp 733 1: 734 735 // install breakpoints, if defined 736 testl $THREAD_FLAGS_BREAKPOINTS_DEFINED, THREAD_flags(%edi) 737 jz 1f 738 push %ebp 739 call x86_init_user_debug_at_kernel_exit 740 1: 741 POP_IFRAME_AND_RETURN() 742 FUNCTION_END(kernel_exit_work) 743 744 STATIC_FUNCTION(kernel_exit_handle_signals): 745 // make sure interrupts are enabled (they are, when coming from a syscall 746 // but otherwise they might be disabled) 747 sti 748 call thread_at_kernel_exit // also disables interrupts 749 jmp kernel_exit_work_done 750 FUNCTION_END(kernel_exit_handle_signals) 751 752 STATIC_FUNCTION(bad_syscall_params): 753 // clear the fault handler and exit normally 754 movl %gs:0, %edi 755 movl $0, THREAD_fault_handler(%edi) 756 jmp kernel_exit_work 757 FUNCTION_END(bad_syscall_params) 758 759 760/*! Handler called by the sysenter instruction 761 ecx - user esp 762*/ 763FUNCTION(x86_sysenter): 764 // get the thread 765 push %gs 766 movl $KERNEL_TLS_SELECTOR, %edx 767 movw %dx, %gs 768 movl %gs:0, %edx 769 pop %gs 770 771 // push the iframe 772 pushl $USER_DATA_SELECTOR // user_ss 773 pushl %ecx // user_esp 774 pushfl // eflags 775 orl $(1 << 9), (%esp) // set the IF (interrupts) bit 776 pushl $USER_CODE_SELECTOR // user cs 777 778 // user_eip 779 movl THREAD_team(%edx), %edx 780 movl TEAM_commpage_address(%edx), %edx 781 addl 4 * COMMPAGE_ENTRY_X86_SYSCALL(%edx), %edx 782 addl $4, %edx // sysenter is at offset 2, 2 bytes long 783 pushl %edx 784 785 PUSH_IFRAME_BOTTOM_SYSCALL() 786 787 call handle_syscall 788 789 // pop the bottom of the iframe 790 lea 4(%ebp), %esp // skip iframe type 791 792 pop %gs 793 addl $4, %esp /* we skip %fs, as this contains the CPU 794 dependent TLS segment */ 795 pop %es 796 pop %ds 797 798 popa 799 800 // ecx already contains the user esp -- load edx with the return address 801 movl 16(%esp), %edx 802 803 // pop eflags, which also reenables interrupts 804 addl $24, %esp // skip, orig_eax/edx, vector, error_code, eip, cs 805 popfl 806 807 sysexit 808FUNCTION_END(x86_sysenter) 809 810 811/*! \fn void x86_return_to_userland(iframe* frame) 812 \brief Returns to the userland environment given by \a frame. 813 814 Before returning to userland all potentially necessary kernel exit work is 815 done. 816 817 \a frame must point to a location somewhere on the caller's stack (e.g. a 818 local variable). 819 The function must be called with interrupts disabled. 820 821 \param frame The iframe defining the userland environment. 822*/ 823FUNCTION(x86_return_to_userland): 824 // get the iframe* parameter 825 movl 4(%esp), %ebp 826 movl %ebp, %esp 827 828 // check, if any kernel exit work has to be done 829 movl %gs:0, %edi 830 testl $(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \ 831 | THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED) \ 832 , THREAD_flags(%edi) 833 jnz kernel_exit_work 834 835 // update the thread's kernel time and return 836 UPDATE_THREAD_KERNEL_TIME() 837 POP_IFRAME_AND_RETURN() 838FUNCTION_END(x86_return_to_userland) 839