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 %dr3, %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_SEG; // 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 %esp, %ebp // frame pointer is the iframe 513 514 // Set the RF (resume flag) in EFLAGS. This prevents an instruction 515 // breakpoint on the instruction we're returning to to trigger a debug 516 // exception. 517 orl $0x10000, IFRAME_flags(%ebp); 518 519 cmp $USER_CODE_SEG, IFRAME_cs(%ebp) // user mode 520 je int_bottom_user 521 522 // We need to recheck user mode using the thread's in_kernel flag, since 523 // sysexit introduces a raced condition: It doesn't reenable interrupts, 524 // so that we have to do it in the instruction before, thus opening a 525 // window for an interrupt while still being in the kernel, but having set 526 // up everything for userland already. 527 movl %dr3, %edi // thread pointer 528 cmpb $0, THREAD_in_kernel(%edi) 529 je int_bottom_user 530 531 // disable interrupts -- the handler will enable them, if necessary 532 cli 533 534 pushl %ebp 535 movl IFRAME_vector(%ebp), %eax 536 call *gInterruptHandlerTable(, %eax, 4) 537 538 POP_IFRAME_AND_RETURN() 539FUNCTION_END(int_bottom) 540 541 542STATIC_FUNCTION(int_bottom_user): 543 movl $KERNEL_DATA_SEG,%eax 544 cld 545 movl %eax,%ds 546 movl %eax,%es 547 548 // disable breakpoints, if installed 549 movl %dr3, %edi // thread pointer 550 cli // disable interrupts 551 STOP_USER_DEBUGGING() 552 553 // update the thread's user time 554 UPDATE_THREAD_USER_TIME() 555 556 // leave interrupts disabled -- the handler will enable them, if 557 // necessary 558 559 pushl %ebp 560 movl IFRAME_vector(%ebp), %eax 561 call *gInterruptHandlerTable(, %eax, 4) 562 563 // Don't do any kernel exit work, if we actually came from the kernel (but 564 // were already/still prepared for userland), since the iframe in this case 565 // will be a kernel iframe and e.g. trying to set up a signal stack will not 566 // be a very healthy endeavor. 567 cmp $USER_CODE_SEG, IFRAME_cs(%ebp) 568 jne 1f 569 570 testl $(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \ 571 | THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED) \ 572 , THREAD_flags(%edi) 573 jnz kernel_exit_work 5741: 575 576 cli // disable interrupts 577 578 // update the thread's kernel time and return 579 UPDATE_THREAD_KERNEL_TIME() 580 POP_IFRAME_AND_RETURN() 581FUNCTION_END(int_bottom_user) 582 583 584// test interrupt handler for performance measurements 585.align 16 586FUNCTION(trap98): 587 iret 588FUNCTION_END(trap98) 589 590 591.align 16 592FUNCTION(trap99): 593 // push error, vector, orig_edx, orig_eax, and other registers 594 PUSH_IFRAME_BOTTOM_SYSCALL() 595 596 call handle_syscall 597 598 POP_IFRAME_AND_RETURN() 599FUNCTION_END(trap99) 600 601 602STATIC_FUNCTION(handle_syscall): 603 // save %eax, the number of the syscall 604 movl %eax, %esi 605 606 movl $KERNEL_DATA_SEG,%eax 607 cld 608 movl %eax,%ds 609 movl %eax,%es 610 611 lea 4(%esp), %ebp // skipping the return address, the stack 612 // frame pointer is the iframe 613 movl %dr3, %edi // thread pointer 614 615 // disable breakpoints, if installed 616 cli // disable interrupts 617 STOP_USER_DEBUGGING() 618 619 // update the thread's user time 620 UPDATE_THREAD_USER_TIME_PUSH_TIME() 621 // leave the time on the stack (needed for post syscall debugging) 622 623 sti // enable interrupts 624 625 cmp $SYSCALL_COUNT, %esi // check syscall number 626 jae bad_syscall_number 627 movl $kSyscallInfos, %eax // get syscall info 628 lea (%eax, %esi, SYSCALL_INFO_sizeof), %edx 629 630 // copy parameters onto this stack 631 COPY_SYSCALL_PARAMETERS() 632 633 // pre syscall debugging 634 TRACE_PRE_SYSCALL() 635 testl $THREAD_FLAGS_DEBUGGER_INSTALLED, THREAD_flags(%edi) 636 jnz do_pre_syscall_debug 637 pre_syscall_debug_done: 638 639 // call the syscall function 640 call *SYSCALL_INFO_function(%esi) 641 642 // overwrite the values of %eax and %edx on the stack (the syscall return 643 // value) 644 movl %edx, IFRAME_dx(%ebp) 645 movl %eax, IFRAME_ax(%ebp) 646 647 TRACE_POST_SYSCALL() 648 649 testl $(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \ 650 | THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED \ 651 | THREAD_FLAGS_64_BIT_SYSCALL_RETURN \ 652 | THREAD_FLAGS_RESTART_SYSCALL | THREAD_FLAGS_SYSCALL_RESTARTED) \ 653 , THREAD_flags(%edi) 654 jnz post_syscall_work 655 656 cli // disable interrupts 657 658 // update the thread's kernel time 659 UPDATE_THREAD_KERNEL_TIME() 660 661 lea -4(%ebp), %esp // remove all parameters from the stack 662 663 ret 664FUNCTION_END(handle_syscall) 665 666 STATIC_FUNCTION(do_pre_syscall_debug): 667 movl %esp, %eax // syscall parameters 668 push %eax 669 movl IFRAME_orig_eax(%ebp), %eax // syscall number 670 push %eax 671 call user_debug_pre_syscall 672 addl $8, %esp 673 jmp pre_syscall_debug_done 674 FUNCTION_END(do_pre_syscall_debug) 675 676 STATIC_FUNCTION(post_syscall_work): 677 // clear the 64 bit return value and syscall restarted bits 678 testl $(THREAD_FLAGS_64_BIT_SYSCALL_RETURN \ 679 | THREAD_FLAGS_SYSCALL_RESTARTED), THREAD_flags(%edi) 680 jz 2f 681 1: 682 movl THREAD_flags(%edi), %eax 683 movl %eax, %edx 684 andl $~(THREAD_FLAGS_64_BIT_SYSCALL_RETURN \ 685 | THREAD_FLAGS_SYSCALL_RESTARTED), %edx 686 lock 687 cmpxchgl %edx, THREAD_flags(%edi) 688 jnz 1b 689 2: 690 691 // post syscall debugging 692 testl $THREAD_FLAGS_DEBUGGER_INSTALLED, THREAD_flags(%edi) 693 jz 1f 694 pushl -8(%ebp) // syscall start time 695 pushl -12(%ebp) 696 movl IFRAME_dx(%ebp), %edx // syscall return value 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 1: 707 FUNCTION_END(post_syscall_work) 708 709 bad_syscall_number: 710 STATIC_FUNCTION(kernel_exit_work): 711 // if no signals are pending and the thread shall not be debugged, we can 712 // use the quick kernel exit function 713 testl $(THREAD_FLAGS_SIGNALS_PENDING | THREAD_FLAGS_DEBUG_THREAD) \ 714 , THREAD_flags(%edi) 715 jnz kernel_exit_handle_signals 716 cli // disable interrupts 717 call thread_at_kernel_exit_no_signals 718 kernel_exit_work_done: 719 720 // syscall restart 721 // TODO: this only needs to be done for syscalls! 722 testl $THREAD_FLAGS_RESTART_SYSCALL, THREAD_flags(%edi) 723 jz 1f 724 push %ebp 725 call x86_restart_syscall 726 addl $4, %esp 727 1: 728 729 // install breakpoints, if defined 730 testl $THREAD_FLAGS_BREAKPOINTS_DEFINED, THREAD_flags(%edi) 731 jz 1f 732 push %ebp 733 call x86_init_user_debug_at_kernel_exit 734 1: 735 POP_IFRAME_AND_RETURN() 736 FUNCTION_END(kernel_exit_work) 737 738 STATIC_FUNCTION(kernel_exit_handle_signals): 739 // make sure interrupts are enabled (they are, when coming from a syscall 740 // but otherwise they might be disabled) 741 sti 742 call thread_at_kernel_exit // also disables interrupts 743 jmp kernel_exit_work_done 744 FUNCTION_END(kernel_exit_handle_signals) 745 746 STATIC_FUNCTION(bad_syscall_params): 747 // clear the fault handler and exit normally 748 movl %dr3, %edi 749 movl $0, THREAD_fault_handler(%edi) 750 jmp kernel_exit_work 751 FUNCTION_END(bad_syscall_params) 752 753 754/*! Handler called by the sysenter instruction 755 ecx - user esp 756*/ 757FUNCTION(x86_sysenter): 758 // get the thread 759 movl %dr3, %edx 760 761 // push the iframe 762 pushl $USER_DATA_SEG // user_ss 763 pushl %ecx // user_esp 764 pushfl // eflags 765 orl $(1 << 9), (%esp) // set the IF (interrupts) bit 766 pushl $USER_CODE_SEG // 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 %dr3, %edi 820 testl $(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \ 821 | THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED) \ 822 , THREAD_flags(%edi) 823 jnz kernel_exit_work 824 825 // update the thread's kernel time and return 826 UPDATE_THREAD_KERNEL_TIME() 827 POP_IFRAME_AND_RETURN() 828FUNCTION_END(x86_return_to_userland) 829