/* * do_child_1() */ void do_child_1(void) { int kid_count, fork_kid_pid[MAXKIDS]; int ret_val; int i, j, k, found; int group1, group2; int wait_kid_pid[MAXKIDS], status; setup_sigint(); group1 = getpgrp(); for (kid_count = 0; kid_count < MAXKIDS; kid_count++) { if (kid_count == (MAXKIDS / 2)) { group2 = setpgrp(); } intintr = 0; ret_val = FORK_OR_VFORK(); if (ret_val == 0) { /* child */ #ifdef UCLINUX if (self_exec(argv0, "n", 2) < 0) { tst_resm(TFAIL, "Fork kid %d failed. " "errno = %d", kid_count, errno); exit(ret_val); } #else do_exit(); #endif /*NOTREACHED*/ } else if (ret_val < 0) { tst_resm(TFAIL, "Fork kid %d failed. " "errno = %d", kid_count, errno); exit(ret_val); } /* parent */ fork_kid_pid[kid_count] = ret_val; } #ifdef UCLINUX /* Give the kids a chance to setup SIGINT again, since this is * cleared by exec(). */ sleep(3); #endif /* Now send all the kids a SIGINT to tell them to * proceed */ for (i = 0; i < MAXKIDS; i++) { if (kill(fork_kid_pid[i], SIGINT) < 0) { tst_resm(TFAIL, "Kill of child %d " "failed, errno = %d", i, errno); exit(-1); } } /* * Wait till all kids have terminated. Stash away their * pid's in an array. */ kid_count = 0; errno = 0; while (((ret_val = waitpid(-1, &status, 0)) != -1) || (errno == EINTR)) { if (ret_val == -1) { continue; } if (!WIFEXITED(status)) { tst_resm(TFAIL, "Child %d did not exit " "normally", ret_val); flag = FAILED; printf("status: %d\n", status); } else { if (WEXITSTATUS(status) != 3) { tst_resm(TFAIL, "Child %d" "exited with wrong " "status", ret_val); tst_resm(TFAIL, "Expected 3 " "got %d ", WEXITSTATUS(status)); flag = FAILED; } } wait_kid_pid[kid_count++] = ret_val; } /* * Check that for every entry in the fork_kid_pid array, * there is a matching pid in the wait_kid_pid array. If * not, it's an error. */ for (i = 0; i < kid_count; i++) { found = 0; for (j = 0; j < MAXKIDS; j++) { if (fork_kid_pid[j] == wait_kid_pid[i]){ found = 1; break; } } if (!found) { tst_resm(TFAIL, "Did not find a " "wait_kid_pid for the " "fork_kid_pid of %d", fork_kid_pid[j]); for (k = 0; k < MAXKIDS; k++) { tst_resm(TFAIL, "fork_kid_pid[%d] = " "%d", k, fork_kid_pid[k]); } for (k = 0; k < kid_count; k++) { tst_resm(TFAIL, "wait_kid_pid[%d] = " "%d", k, wait_kid_pid[k]); } flag = FAILED; } } if (flag) { exit(1); } else { exit(0); } }
/** * Execute a command. * @var argc The number of arguments * @var argv The array of arguments * @var should_background Whether or not to run it as a background process */ int execute_cmd(int argc, char** argv, int* should_background) { if (argv[0] && strcmp(argv[0], "exit") == 0) { do_exit(); } pid_t pid = fork(); if (pid < 0) { // Uh oh, an error with forking fprintf(stderr, "Fork Failed"); return 1; } else if (pid == 0) { // Child process char* stdin_fname = NULL; char* stdout_fname = NULL; char* stderr_fname = NULL; int bad_syntax = 0; // Checking for stdin/stdout redirection for (int i = 0; i < argc; i++) { char* arg = argv[i]; // redirection check if (is_redirection(arg)) { char* next_arg = argv[i+1]; if (next_arg == NULL || is_redirection(next_arg) || strcmp(next_arg, "&") == 0) { bad_syntax = 1; break; } if ((i + 2) < argc) { char* next_next_arg = argv[i+2]; if (next_next_arg != NULL) { if (!is_redirection(next_next_arg) && strcmp(next_next_arg, "&") != 0) { bad_syntax = 1; break; } } } if (strcmp(arg, ">") == 0) { stdout_fname = argv[i+1]; } else if (strcmp(arg, "<") == 0) { stdin_fname = argv[i+1]; } else if (strcmp(arg, "2>") == 0) { stderr_fname = argv[i+1]; } argv[i] = NULL; } } if (bad_syntax == 1) { printf("Error: Invalid syntax.\n"); exit(3); } // Redirect stdout if (stdout_fname != NULL) { if (!is_redirection(stdout_fname) && !(strcmp(stdout_fname, "&") == 0)) { FILE* stdout_file; stdout_file= freopen(stdout_fname, "w", stdout); if (stdout_file == NULL) { printf("Error: Unable to open redirection file.\n"); exit(errno); } } else { printf("Error: Invalid syntax.\n"); exit(3); } } // stdin redirection if (stdin_fname != NULL) { if (!is_redirection(stdin_fname) && !(strcmp(stdin_fname, "&") == 0)) { FILE* stdin_file; stdin_file = freopen(stdin_fname, "r", stdin); if (stdin_file == NULL) { printf("Error: Unable to open redirection file.\n"); exit(errno); } } else { printf("Error: Invalid syntax.\n"); exit(3); } } // stderr redirection if (stderr_fname != NULL) { if (!is_redirection(stderr_fname) && !(strcmp(stderr_fname, "&") == 0)) { FILE* stderr_file; stderr_file = freopen(stderr_fname, "w", stderr); if (stderr_file == NULL) { printf("Error: Unable to open redirection file.\n"); exit(errno); } } else { printf("Error: Invalid syntax.\n"); exit(3); } } execvp(argv[0], argv); if (errno == ENOENT) { printf("Error: Command not found.\n"); } else if (errno == EACCES) { printf("Error: Permission denied.\n"); } else { printf("Error: Exit code %d\n", errno); } exit(-1); } else { if (*should_background == 0) { // Wait for the child waitpid(pid, NULL, 0); } } return 0; }
/* * Create a kernel thread */ ATTRIB_NORET void kernel_thread_helper(void *arg, int (*fn)(void *)) { do_exit(fn(arg)); }
/* * Make pt_pfn a new 'level' page table frame and hook it into the page * table at offset in previous level MFN (pref_l_mfn). pt_pfn is a guest * PFN. */ static void new_pt_frame(unsigned long *pt_pfn, unsigned long prev_l_mfn, unsigned long offset, unsigned long level) { pgentry_t *tab = (pgentry_t *)start_info.pt_base; unsigned long pt_page = (unsigned long)pfn_to_virt(*pt_pfn); pgentry_t prot_e, prot_t; mmu_update_t mmu_updates[1]; int rc; prot_e = prot_t = 0; DEBUG("Allocating new L%d pt frame for pfn=%lx, " "prev_l_mfn=%lx, offset=%lx", level, *pt_pfn, prev_l_mfn, offset); /* We need to clear the page, otherwise we might fail to map it as a page table page */ memset((void*) pt_page, 0, PAGE_SIZE); switch ( level ) { case L1_FRAME: prot_e = L1_PROT; prot_t = L2_PROT; break; case L2_FRAME: prot_e = L2_PROT; prot_t = L3_PROT; break; case L3_FRAME: prot_e = L3_PROT; prot_t = L4_PROT; break; default: printk("new_pt_frame() called with invalid level number %d\n", level); do_exit(); break; } /* Make PFN a page table page */ tab = pte_to_virt(tab[l4_table_offset(pt_page)]); tab = pte_to_virt(tab[l3_table_offset(pt_page)]); mmu_updates[0].ptr = (tab[l2_table_offset(pt_page)] & PAGE_MASK) + sizeof(pgentry_t) * l1_table_offset(pt_page); mmu_updates[0].val = (pgentry_t)pfn_to_mfn(*pt_pfn) << PAGE_SHIFT | (prot_e & ~_PAGE_RW); if ( (rc = HYPERVISOR_mmu_update(mmu_updates, 1, NULL, DOMID_SELF)) < 0 ) { printk("ERROR: PTE for new page table page could not be updated\n"); printk(" mmu_update failed with rc=%d\n", rc); do_exit(); } /* Hook the new page table page into the hierarchy */ mmu_updates[0].ptr = ((pgentry_t)prev_l_mfn << PAGE_SHIFT) + sizeof(pgentry_t) * offset; mmu_updates[0].val = (pgentry_t)pfn_to_mfn(*pt_pfn) << PAGE_SHIFT | prot_t; if ( (rc = HYPERVISOR_mmu_update(mmu_updates, 1, NULL, DOMID_SELF)) < 0 ) { printk("ERROR: mmu_update failed with rc=%d\n", rc); do_exit(); } *pt_pfn += 1; }
// STATUS 1 = End of line, execute command // STATUS 2 = Background the process char* get_arg(int* status, int* is_eof) { char* buffer = (char*) calloc(10, 1); char c; char next; int bufsz = 0; int count = 0; int do_loop = 1; c = getchar(); // Read through any whitespace while (is_white_space(c) && c != '\n') { c = getchar(); } // Check for redirection if (c == '>' || c == '<') { buffer[0] = c; count = 1; do_loop = 0; } else if (c == '2') { next = getchar(); if (next == '>') { do_loop = 0; } buffer[0] = c; count = 1; if (!is_white_space(next)) { buffer[1] = next; count = 2; } c = next; } // Parse the argument while (c != EOF && !is_white_space(c) && do_loop) { if (c == '\\') { next = getchar(); if (next == EOF) { *is_eof = 1; } // Handle escape cases if (next == 't') { c = '\t'; } else if (next == '\\') { c = '\\'; } else if (next == ' ') { c = ' '; } else if (next == '&') { c = '&'; } else { printf("Error: Unrecognized escape sequence.\n"); if (next == '\n') { *status = 1; } else { empty_input(is_eof); } free(buffer); return NULL; } } else if (c == '&') { *status = 2; c = getchar(); while (is_white_space(c) && c != '\n' && c != EOF) { c = getchar(); } if (c != '\n' && c != EOF) { printf("Error: Invalid syntax.\n"); empty_input(is_eof); free(buffer); return NULL; } if (c == EOF) { *is_eof = 1; } break; } if (count + 1 > bufsz) { buffer = realloc(buffer, bufsz + 10); if (buffer == NULL) { perror("Error resizing buffer for arg."); do_exit(); } bufsz += 10; } buffer[count] = c; count++; c = getchar(); } // Check to see if we've read in the full line if ((c == '\n' || c == EOF) && (*status != 2)) { *status= 1; } if (c == EOF) { *is_eof = 1; } // Save the argument to memory char* ret = (char*) calloc(count + 1, 1); strncpy(ret, buffer, count); free(buffer); return ret; }
static int syscall_dispatch(uint32_t sysnum, uint32_t args, regs_t *regs) { switch (sysnum) { case SYS_waitpid: return sys_waitpid((waitpid_args_t *)args); case SYS_exit: do_exit((int)args); panic("exit failed!\n"); return 0; case SYS_thr_exit: kthread_exit((void *)args); panic("thr_exit failed!\n"); return 0; case SYS_thr_yield: sched_make_runnable(curthr); sched_switch(); return 0; case SYS_fork: return sys_fork(regs); case SYS_getpid: return curproc->p_pid; case SYS_sync: sys_sync(); return 0; #ifdef __MOUNTING__ case SYS_mount: return sys_mount((mount_args_t *) args); case SYS_umount: return sys_umount((argstr_t *) args); #endif case SYS_mmap: return (int) sys_mmap((mmap_args_t *) args); case SYS_munmap: return sys_munmap((munmap_args_t *) args); case SYS_open: return sys_open((open_args_t *) args); case SYS_close: return sys_close((int)args); case SYS_read: return sys_read((read_args_t *)args); case SYS_write: return sys_write((write_args_t *)args); case SYS_dup: return sys_dup((int)args); case SYS_dup2: return sys_dup2((dup2_args_t *)args); case SYS_mkdir: return sys_mkdir((mkdir_args_t *)args); case SYS_rmdir: return sys_rmdir((argstr_t *)args); case SYS_unlink: return sys_unlink((argstr_t *)args); case SYS_link: return sys_link((link_args_t *)args); case SYS_rename: return sys_rename((rename_args_t *)args); case SYS_chdir: return sys_chdir((argstr_t *)args); case SYS_getdents: return sys_getdents((getdents_args_t *)args); case SYS_brk: return (int) sys_brk((void *)args); case SYS_lseek: return sys_lseek((lseek_args_t *)args); case SYS_halt: sys_halt(); return -1; case SYS_set_errno: curthr->kt_errno = (int)args; return 0; case SYS_errno: return curthr->kt_errno; case SYS_execve: return sys_execve((execve_args_t *)args, regs); case SYS_stat: return sys_stat((stat_args_t *)args); case SYS_pipe: return sys_pipe((int *)args); case SYS_uname: return sys_uname((struct utsname *)args); case SYS_debug: return sys_debug((argstr_t *)args); case SYS_kshell: return sys_kshell((int)args); default: dbg(DBG_ERROR, "ERROR: unknown system call: %d (args: %#08x)\n", sysnum, args); curthr->kt_errno = ENOSYS; return -1; } }
static void trap_dispatch(struct trapframe *tf) { char c; int ret=0; switch (tf->tf_trapno) { case T_PGFLT: //page fault if ((ret = pgfault_handler(tf)) != 0) { print_trapframe(tf); if (current == NULL) { panic("handle pgfault failed. ret=%d\n", ret); } else { if (trap_in_kernel(tf)) { panic("handle pgfault failed in kernel mode. ret=%d\n", ret); } cprintf("killed by kernel.\n"); cprintf("current %s.\n",current->name); panic("handle user mode pgfault failed. ret=%d\n", ret); do_exit(-E_KILLED); } } break; case T_SYSCALL: syscall(); break; case IRQ_OFFSET + IRQ_TIMER: #if 0 LAB3 : If some page replacement algorithm(such as CLOCK PRA) need tick to change the priority of pages, then you can add code here. #endif /* LAB1 YOUR CODE : STEP 3 */ /* handle the timer interrupt */ /* (1) After a timer interrupt, you should record this event using a global variable (increase it), such as ticks in kern/driver/clock.c * (2) Every TICK_NUM cycle, you can print some info using a funciton, such as print_ticks(). * (3) Too Simple? Yes, I think so! */ /* LAB5 YOUR CODE */ /* you should upate you lab1 code (just add ONE or TWO lines of code): * Every TICK_NUM cycle, you should set current process's current->need_resched = 1 */ break; case IRQ_OFFSET + IRQ_COM1: c = cons_getc(); cprintf("serial [%03d] %c\n", c, c); break; case IRQ_OFFSET + IRQ_KBD: c = cons_getc(); cprintf("kbd [%03d] %c\n", c, c); break; //LAB1 CHALLENGE 1 : YOUR CODE you should modify below codes. case T_SWITCH_TOU: case T_SWITCH_TOK: panic("T_SWITCH_** ??\n"); break; case IRQ_OFFSET + IRQ_IDE1: case IRQ_OFFSET + IRQ_IDE2: /* do nothing */ break; default: print_trapframe(tf); if (current != NULL) { cprintf("unhandled trap.\n"); do_exit(-E_KILLED); } // in kernel, it must be a mistake panic("unexpected trap in kernel.\n"); } }
static uint32_t sys_exit(uint32_t arg[]) { int error_code = (int)arg[0]; return do_exit(error_code); }
static void trap_dispatch(struct trapframe *tf) { char c; int ret=0; switch (tf->tf_trapno) { case T_PGFLT: //page fault if ((ret = pgfault_handler(tf)) != 0) { print_trapframe(tf); if (current == NULL) { panic("handle pgfault failed. ret=%d\n", ret); } else { if (trap_in_kernel(tf)) { panic("handle pgfault failed in kernel mode. ret=%d\n", ret); } cprintf("killed by kernel.\n"); panic("handle user mode pgfault failed. ret=%d\n", ret); do_exit(-E_KILLED); } } break; case T_SYSCALL: syscall(); break; case IRQ_OFFSET + IRQ_TIMER: //LAB3_X 2013011509 //Call swap manager timer handler here if (check_mm_struct != NULL) { assert(swap_tick_event(check_mm_struct) == 0); } ticks++; run_timer_list(); #if 0 LAB3 : If some page replacement algorithm(such as CLOCK PRA) need tick to change the priority of pages, then you can add code here. #endif /* LAB1 YOUR CODE : STEP 3 */ /* handle the timer interrupt */ /* (1) After a timer interrupt, you should record this event using a global variable (increase it), such as ticks in kern/driver/clock.c * (2) Every TICK_NUM cycle, you can print some info using a funciton, such as print_ticks(). * (3) Too Simple? Yes, I think so! */ /* you should upate you lab1 code (just add ONE or TWO lines of code): * Every TICK_NUM cycle, you should set current process's current->need_resched = 1 */ /* LAB6 YOUR CODE */ /* you should upate you lab5 code * IMPORTANT FUNCTIONS: * sched_class_proc_tick */ /* LAB7 YOUR CODE */ /* you should upate you lab6 code * IMPORTANT FUNCTIONS: * run_timer_list */ break; case IRQ_OFFSET + IRQ_COM1: case IRQ_OFFSET + IRQ_KBD: // There are user level shell in LAB8, so we need change COM/KBD interrupt processing. c = cons_getc(); { extern void dev_stdin_write(char c); dev_stdin_write(c); } break; //LAB1 CHALLENGE 1 : YOUR CODE you should modify below codes. case T_SWITCH_TOU: case T_SWITCH_TOK: panic("T_SWITCH_** ??\n"); break; case IRQ_OFFSET + IRQ_IDE1: case IRQ_OFFSET + IRQ_IDE2: /* do nothing */ break; default: print_trapframe(tf); if (current != NULL) { cprintf("unhandled trap.\n"); do_exit(-E_KILLED); } // in kernel, it must be a mistake panic("unexpected trap in kernel.\n"); } }
/** * <Ring 1> The main loop of TASK MM. * *****************************************************************************/ PUBLIC void task_mm() { init_mm(); while (1) { send_recv(RECEIVE, ANY, &mm_msg); int src = mm_msg.source; int reply = 1; int msgtype = mm_msg.type; switch (msgtype) { case FORK: mm_msg.RETVAL = do_fork(); break; case EXIT: do_exit(mm_msg.STATUS); reply = 0; break; case EXEC: mm_msg.RETVAL = do_exec(); break; case WAIT: do_wait(); reply = 0; break; case KILL: mm_msg.RETVAL = do_kill(); break; case RAISE: mm_msg.RETVAL = do_raise(); break; case BRK: mm_msg.RETVAL = do_brk(); break; case ACCT: mm_msg.RETVAL = do_acct(); break; case GETUID: mm_msg.RETVAL = do_getuid(); break; case SETUID: mm_msg.RETVAL = do_setuid(); break; case GETGID: mm_msg.RETVAL = do_getgid(); break; case SETGID: mm_msg.RETVAL = do_setgid(); break; case GETEUID: mm_msg.RETVAL = do_geteuid(); break; case GETEGID: mm_msg.RETVAL = do_getegid(); break; case SIGACTION: mm_msg.RETVAL = do_sigaction(); break; case ALARM: mm_msg.RETVAL = do_alarm(); break; default: dump_msg("MM::unknown msg", &mm_msg); assert(0); break; } if (reply) { mm_msg.type = SYSCALL_RET; send_recv(SEND, src, &mm_msg); } } }
/* * This is the mechanism for creating a new kernel thread. * * NOTE! Only a kernel-only process(ie the swapper or direct descendants * who haven't done an "execve()") should use this: it will work within * a system call from a "real" process, but the process memory space will * not be free'd until both the parent and the child have exited. */ static void kernel_thread_helper(void *nouse, int (*fn)(void *), void *arg) { fn(arg); do_exit(-1); }
/* * If we ever come here the user sp is bad. Zap the process right away. * Due to the bad stack signaling wouldn't work. */ asmlinkage void bad_stack(void) { do_exit(SIGSEGV); }
static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, struct kvm_s390_interrupt_info *inti) { const unsigned short table[] = { 2, 4, 4, 6 }; int rc, exception = 0; switch (inti->type) { case KVM_S390_INT_EMERGENCY: VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp emerg"); vcpu->stat.deliver_emergency_signal++; rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1201); if (rc == -EFAULT) exception = 1; rc = put_guest_u16(vcpu, __LC_CPU_ADDRESS, inti->emerg.code); if (rc == -EFAULT) exception = 1; rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); if (rc == -EFAULT) exception = 1; rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, __LC_EXT_NEW_PSW, sizeof(psw_t)); if (rc == -EFAULT) exception = 1; break; case KVM_S390_INT_SERVICE: VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x", inti->ext.ext_params); vcpu->stat.deliver_service_signal++; rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x2401); if (rc == -EFAULT) exception = 1; rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); if (rc == -EFAULT) exception = 1; rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, __LC_EXT_NEW_PSW, sizeof(psw_t)); if (rc == -EFAULT) exception = 1; rc = put_guest_u32(vcpu, __LC_EXT_PARAMS, inti->ext.ext_params); if (rc == -EFAULT) exception = 1; break; case KVM_S390_INT_VIRTIO: VCPU_EVENT(vcpu, 4, "interrupt: virtio parm:%x,parm64:%llx", inti->ext.ext_params, inti->ext.ext_params2); vcpu->stat.deliver_virtio_interrupt++; rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x2603); if (rc == -EFAULT) exception = 1; rc = put_guest_u16(vcpu, __LC_CPU_ADDRESS, 0x0d00); if (rc == -EFAULT) exception = 1; rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); if (rc == -EFAULT) exception = 1; rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, __LC_EXT_NEW_PSW, sizeof(psw_t)); if (rc == -EFAULT) exception = 1; rc = put_guest_u32(vcpu, __LC_EXT_PARAMS, inti->ext.ext_params); if (rc == -EFAULT) exception = 1; rc = put_guest_u64(vcpu, __LC_EXT_PARAMS2, inti->ext.ext_params2); if (rc == -EFAULT) exception = 1; break; case KVM_S390_SIGP_STOP: VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu stop"); vcpu->stat.deliver_stop_signal++; __set_intercept_indicator(vcpu, inti); break; case KVM_S390_SIGP_SET_PREFIX: VCPU_EVENT(vcpu, 4, "interrupt: set prefix to %x", inti->prefix.address); vcpu->stat.deliver_prefix_signal++; vcpu->arch.sie_block->prefix = inti->prefix.address; vcpu->arch.sie_block->ihcpu = 0xffff; break; case KVM_S390_RESTART: VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu restart"); vcpu->stat.deliver_restart_signal++; rc = copy_to_guest(vcpu, offsetof(struct _lowcore, restart_old_psw), &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); if (rc == -EFAULT) exception = 1; rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, offsetof(struct _lowcore, restart_psw), sizeof(psw_t)); if (rc == -EFAULT) exception = 1; break; case KVM_S390_PROGRAM_INT: VCPU_EVENT(vcpu, 4, "interrupt: pgm check code:%x, ilc:%x", inti->pgm.code, table[vcpu->arch.sie_block->ipa >> 14]); vcpu->stat.deliver_program_int++; rc = put_guest_u16(vcpu, __LC_PGM_INT_CODE, inti->pgm.code); if (rc == -EFAULT) exception = 1; rc = put_guest_u16(vcpu, __LC_PGM_ILC, table[vcpu->arch.sie_block->ipa >> 14]); if (rc == -EFAULT) exception = 1; rc = copy_to_guest(vcpu, __LC_PGM_OLD_PSW, &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); if (rc == -EFAULT) exception = 1; rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, __LC_PGM_NEW_PSW, sizeof(psw_t)); if (rc == -EFAULT) exception = 1; break; default: BUG(); } if (exception) { printk("kvm: The guest lowcore is not mapped during interrupt " "delivery, killing userspace\n"); do_exit(SIGKILL); } }
/* * do_child_2_uclinux() * sets up sigint handler again, then calls the normal child 2 function */ void do_child_2_uclinux(void) { setup_sigint(); do_exit(); }
/* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate * routines. * * error_code: * 04 Protection -> Write-Protection (suprression) * 10 Segment translation -> Not present (nullification) * 11 Page translation -> Not present (nullification) * 3b Region third trans. -> Not present (nullification) */ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection) { struct task_struct *tsk; struct mm_struct *mm; struct vm_area_struct * vma; unsigned long address; int user_address; const struct exception_table_entry *fixup; int si_code = SEGV_MAPERR; tsk = current; mm = tsk->mm; /* * Check for low-address protection. This needs to be treated * as a special case because the translation exception code * field is not guaranteed to contain valid data in this case. */ if (is_protection && !(S390_lowcore.trans_exc_code & 4)) { /* Low-address protection hit in kernel mode means NULL pointer write access in kernel mode. */ if (!(regs->psw.mask & PSW_MASK_PSTATE)) { address = 0; user_address = 0; goto no_context; } /* Low-address protection hit in user mode 'cannot happen'. */ die ("Low-address protection", regs, error_code); do_exit(SIGKILL); } /* * get the failing address * more specific the segment and page table portion of * the address */ address = S390_lowcore.trans_exc_code & __FAIL_ADDR_MASK; user_address = check_user_space(regs, error_code); /* * Verify that the fault happened in user space, that * we are not in an interrupt and that there is a * user context. */ if (user_address == 0 || in_interrupt() || !mm) goto no_context; /* * When we get here, the fault happened in the current * task's user address space, so we can switch on the * interrupts again and then search the VMAs */ local_irq_enable(); down_read(&mm->mmap_sem); vma = find_vma(mm, address); if (!vma) goto bad_area; if (vma->vm_start <= address) goto good_area; if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; if (expand_stack(vma, address)) goto bad_area; /* * Ok, we have a good vm_area for this memory access, so * we can handle it.. */ good_area: si_code = SEGV_ACCERR; if (!is_protection) { /* page not present, check vm flags */ if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) goto bad_area; } else { if (!(vma->vm_flags & VM_WRITE)) goto bad_area; } survive: /* * If for any reason at all we couldn't handle the fault, * make sure we exit gracefully rather than endlessly redo * the fault. */ switch (handle_mm_fault(mm, vma, address, is_protection)) { case VM_FAULT_MINOR: tsk->min_flt++; break; case VM_FAULT_MAJOR: tsk->maj_flt++; break; case VM_FAULT_SIGBUS: goto do_sigbus; case VM_FAULT_OOM: goto out_of_memory; default: BUG(); } up_read(&mm->mmap_sem); /* * The instruction that caused the program check will * be repeated. Don't signal single step via SIGTRAP. */ clear_tsk_thread_flag(current, TIF_SINGLE_STEP); return; /* * Something tried to access memory that isn't in our memory map.. * Fix it, but check if it's kernel or user first.. */ bad_area: up_read(&mm->mmap_sem); /* User mode accesses just cause a SIGSEGV */ if (regs->psw.mask & PSW_MASK_PSTATE) { tsk->thread.prot_addr = address; tsk->thread.trap_no = error_code; do_sigsegv(regs, error_code, si_code, address); return; } no_context: /* Are we prepared to handle this kernel fault? */ fixup = search_exception_tables(regs->psw.addr & __FIXUP_MASK); if (fixup) { regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE; return; } /* * Oops. The kernel tried to access some bad page. We'll have to * terminate things with extreme prejudice. */ if (user_address == 0) printk(KERN_ALERT "Unable to handle kernel pointer dereference" " at virtual kernel address %p\n", (void *)address); else printk(KERN_ALERT "Unable to handle kernel paging request" " at virtual user address %p\n", (void *)address); die("Oops", regs, error_code); do_exit(SIGKILL); /* * We ran out of memory, or some other thing happened to us that made * us unable to handle the page fault gracefully. */ out_of_memory: up_read(&mm->mmap_sem); if (tsk->pid == 1) { yield(); goto survive; } printk("VM: killing process %s\n", tsk->comm); if (regs->psw.mask & PSW_MASK_PSTATE) do_exit(SIGKILL); goto no_context; do_sigbus: up_read(&mm->mmap_sem); /* * Send a sigbus, regardless of whether we were in kernel * or user mode. */ tsk->thread.prot_addr = address; tsk->thread.trap_no = error_code; force_sig(SIGBUS, tsk); /* Kernel mode? Handle exceptions or die */ if (!(regs->psw.mask & PSW_MASK_PSTATE)) goto no_context; }
//// 系统调用exit()。终止进程。 int sys_exit (int error_code) { return do_exit ((error_code & 0xff) << 8); }
SYSCALL_DEFINE1(exit, int, error_code) { do_exit((error_code&0xff) << 8); return SYSCALL_RETURN(0); }
static void __noreturn kernel_thread_helper(void *unused0, int (*fn)(void *), void *arg, void *unused1) { do_exit(fn(arg)); }
int do_execve(const char *filename, const char **argv, const char **envp) { static_assert(EXEC_MAX_ARG_LEN >= FS_MAX_FPATH_LEN); struct mm_struct *mm = current->mm; char local_name[PROC_NAME_LEN + 1]; memset(local_name, 0, sizeof(local_name)); char *kargv[EXEC_MAX_ARG_NUM], *kenvp[EXEC_MAX_ENV_NUM]; const char *path; int ret = -E_INVAL; lock_mm(mm); #if 0 if (name == NULL) { snprintf(local_name, sizeof(local_name), "<null> %d", current->pid); } else { if (!copy_string(mm, local_name, name, sizeof(local_name))) { unlock_mm(mm); return ret; } } #endif snprintf(local_name, sizeof(local_name), "<null> %d", current->pid); int argc = 0, envc = 0; if ((ret = copy_kargv(mm, kargv, argv, EXEC_MAX_ARG_NUM, &argc)) != 0) { unlock_mm(mm); return ret; } if ((ret = copy_kargv(mm, kenvp, envp, EXEC_MAX_ENV_NUM, &envc)) != 0) { unlock_mm(mm); put_kargv(argc, kargv); return ret; } #if 0 int i; kprintf("## fn %s\n", filename); kprintf("## argc %d\n", argc); for (i = 0; i < argc; i++) kprintf("## %08x %s\n", kargv[i], kargv[i]); kprintf("## envc %d\n", envc); for (i = 0; i < envc; i++) kprintf("## %08x %s\n", kenvp[i], kenvp[i]); #endif //path = argv[0]; //copy_from_user (mm, &path, argv, sizeof (char*), 0); path = filename; unlock_mm(mm); /* linux never do this */ //fs_closeall(current->fs_struct); /* sysfile_open will check the first argument path, thus we have to use a user-space pointer, and argv[0] may be incorrect */ int fd; if ((ret = fd = sysfile_open(path, O_RDONLY)) < 0) { goto execve_exit; } if (mm != NULL) { mm->cpuid = -1; mp_set_mm_pagetable(NULL); if (mm_count_dec(mm) == 0) { exit_mmap(mm); put_pgdir(mm); bool intr_flag; local_intr_save(intr_flag); { list_del(&(mm->proc_mm_link)); } local_intr_restore(intr_flag); mm_destroy(mm); } current->mm = NULL; } put_sem_queue(current); ret = -E_NO_MEM; /* init signal */ put_sighand(current); if ((current->signal_info.sighand = sighand_create()) == NULL) { goto execve_exit; } sighand_count_inc(current->signal_info.sighand); put_signal(current); if ((current->signal_info.signal = signal_create()) == NULL) { goto execve_exit; } signal_count_inc(current->signal_info.signal); if ((current->sem_queue = sem_queue_create()) == NULL) { goto execve_exit; } sem_queue_count_inc(current->sem_queue); if ((ret = load_icode(fd, argc, kargv, envc, kenvp)) != 0) { goto execve_exit; } set_proc_name(current, local_name); if (do_execve_arch_hook(argc, kargv) < 0) goto execve_exit; put_kargv(argc, kargv); put_kargv(envc, kenvp); return 0; execve_exit: put_kargv(argc, kargv); put_kargv(envc, kenvp); /* exec should return -1 if failed */ //return ret; do_exit(ret); panic("already exit: %e.\n", ret); }
static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs, int signo, sigset_t *oldset) { struct signal_frame __user *sf; int sigframe_size, err; /* 1. Make sure everything is clean */ synchronize_user_stack(); sigframe_size = SF_ALIGNEDSZ; if (!used_math()) sigframe_size -= sizeof(__siginfo_fpu_t); sf = (struct signal_frame __user *) get_sigframe(&ka->sa, regs, sigframe_size); if (invalid_frame_pointer(sf, sigframe_size)) goto sigill_and_return; if (current_thread_info()->w_saved != 0) goto sigill_and_return; /* 2. Save the current process state */ err = __copy_to_user(&sf->info.si_regs, regs, sizeof(struct pt_regs)); err |= __put_user(0, &sf->extra_size); if (used_math()) { err |= save_fpu_state(regs, &sf->fpu_state); err |= __put_user(&sf->fpu_state, &sf->fpu_save); } else { err |= __put_user(0, &sf->fpu_save); } err |= __put_user(oldset->sig[0], &sf->info.si_mask); err |= __copy_to_user(sf->extramask, &oldset->sig[1], (_NSIG_WORDS - 1) * sizeof(unsigned int)); err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP], sizeof(struct reg_window32)); if (err) goto sigsegv; /* 3. signal handler back-trampoline and parameters */ regs->u_regs[UREG_FP] = (unsigned long) sf; regs->u_regs[UREG_I0] = signo; regs->u_regs[UREG_I1] = (unsigned long) &sf->info; regs->u_regs[UREG_I2] = (unsigned long) &sf->info; /* 4. signal handler */ regs->pc = (unsigned long) ka->sa.sa_handler; regs->npc = (regs->pc + 4); /* 5. return to kernel instructions */ if (ka->ka_restorer) regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; else { regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2); /* mov __NR_sigreturn, %g1 */ err |= __put_user(0x821020d8, &sf->insns[0]); /* t 0x10 */ err |= __put_user(0x91d02010, &sf->insns[1]); if (err) goto sigsegv; /* Flush instruction space. */ flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); } return 0; sigill_and_return: do_exit(SIGILL); return -EINVAL; sigsegv: force_sigsegv(signo, current); return -EFAULT; }
struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *next) { struct thread_info *_prev = task_thread_info(prev); struct thread_info *_next = task_thread_info(next); /* * schedule() expects the return of this function to be the task that we * switched away from. Returning prev is not going to work because we * are actually going to return the previous taks that was scheduled * before the task we are going to wake up, and not the current task, * e.g.: * * swapper -> init: saved prev on swapper stack is swapper * init -> ksoftirqd0: saved prev on init stack is init * ksoftirqd0 -> swapper: returned prev is swapper */ static struct task_struct *abs_prev = &init_task; /* * We need to free the thread_info structure in free_thread_info to * avoid races between the dying thread and other threads. We also need * to cleanup sched_sem and signal to the prev thread that it needs to * exit, and we use this stack varible to pass this info. */ struct thread_exit_info ei = { .dead = false, .sched_sem = _prev->sched_sem, }; _current_thread_info = task_thread_info(next); _next->prev_sched = prev; abs_prev = prev; _prev->exit_info = &ei; lkl_ops->sem_up(_next->sched_sem); /* _next may be already gone so use ei instead */ lkl_ops->sem_down(ei.sched_sem); if (ei.dead) { lkl_ops->sem_free(ei.sched_sem); threads_counter_dec(); lkl_ops->thread_exit(); } _prev->exit_info = NULL; return abs_prev; } struct thread_bootstrap_arg { struct thread_info *ti; int (*f)(void *); void *arg; }; static void thread_bootstrap(void *_tba) { struct thread_bootstrap_arg *tba = (struct thread_bootstrap_arg *)_tba; struct thread_info *ti = tba->ti; int (*f)(void *) = tba->f; void *arg = tba->arg; lkl_ops->sem_down(ti->sched_sem); kfree(tba); if (ti->prev_sched) schedule_tail(ti->prev_sched); f(arg); do_exit(0); } int copy_thread(unsigned long clone_flags, unsigned long esp, unsigned long unused, struct task_struct *p) { struct thread_info *ti = task_thread_info(p); struct thread_bootstrap_arg *tba; int ret; tba = kmalloc(sizeof(*tba), GFP_KERNEL); if (!tba) return -ENOMEM; tba->f = (int (*)(void *))esp; tba->arg = (void *)unused; tba->ti = ti; ret = lkl_ops->thread_create(thread_bootstrap, tba); if (ret) { kfree(tba); return -ENOMEM; } threads_counter_inc(); return 0; } void show_stack(struct task_struct *task, unsigned long *esp) { } static inline void pr_early(const char *str) { if (lkl_ops->print) lkl_ops->print(str, strlen(str)); } /** * This is called before the kernel initializes, so no kernel calls (including * printk) can't be made yet. */ int threads_init(void) { struct thread_info *ti = &init_thread_union.thread_info; int ret = 0; ti->exit_info = NULL; ti->prev_sched = NULL; ti->sched_sem = lkl_ops->sem_alloc(0); if (!ti->sched_sem) { pr_early("lkl: failed to allocate init schedule semaphore\n"); ret = -ENOMEM; goto out; } threads_counter_lock = lkl_ops->sem_alloc(1); if (!threads_counter_lock) { pr_early("lkl: failed to alllocate threads counter lock\n"); ret = -ENOMEM; goto out_free_init_sched_sem; } return 0; out_free_init_sched_sem: lkl_ops->sem_free(ti->sched_sem); out: return ret; } void threads_cleanup(void) { struct task_struct *p; for_each_process(p) { struct thread_info *ti = task_thread_info(p); if (p->pid != 1) WARN(!(p->flags & PF_KTHREAD), "non kernel thread task %p\n", p->comm); WARN(p->state == TASK_RUNNING, "thread %s still running while halting\n", p->comm); kill_thread(ti->exit_info); } while (threads_counter_get()) ; lkl_ops->sem_free(init_thread_union.thread_info.sched_sem); lkl_ops->sem_free(threads_counter_lock); }
static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, int signo, sigset_t *oldset, siginfo_t *info) { struct rt_signal_frame __user *sf; int sigframe_size; unsigned int psr; int err; synchronize_user_stack(); sigframe_size = RT_ALIGNEDSZ; if (!used_math()) sigframe_size -= sizeof(__siginfo_fpu_t); sf = (struct rt_signal_frame __user *) get_sigframe(&ka->sa, regs, sigframe_size); if (invalid_frame_pointer(sf, sigframe_size)) goto sigill; if (current_thread_info()->w_saved != 0) goto sigill; err = __put_user(regs->pc, &sf->regs.pc); err |= __put_user(regs->npc, &sf->regs.npc); err |= __put_user(regs->y, &sf->regs.y); psr = regs->psr; if (used_math()) psr |= PSR_EF; err |= __put_user(psr, &sf->regs.psr); err |= __copy_to_user(&sf->regs.u_regs, regs->u_regs, sizeof(regs->u_regs)); err |= __put_user(0, &sf->extra_size); if (psr & PSR_EF) { err |= save_fpu_state(regs, &sf->fpu_state); err |= __put_user(&sf->fpu_state, &sf->fpu_save); } else { err |= __put_user(0, &sf->fpu_save); } err |= __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t)); /* Setup sigaltstack */ err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp); err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags); err |= __put_user(current->sas_ss_size, &sf->stack.ss_size); err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP], sizeof(struct reg_window32)); err |= copy_siginfo_to_user(&sf->info, info); if (err) goto sigsegv; regs->u_regs[UREG_FP] = (unsigned long) sf; regs->u_regs[UREG_I0] = signo; regs->u_regs[UREG_I1] = (unsigned long) &sf->info; regs->u_regs[UREG_I2] = (unsigned long) &sf->regs; regs->pc = (unsigned long) ka->sa.sa_handler; regs->npc = (regs->pc + 4); if (ka->ka_restorer) regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; else { regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2); /* mov __NR_sigreturn, %g1 */ err |= __put_user(0x821020d8, &sf->insns[0]); /* t 0x10 */ err |= __put_user(0x91d02010, &sf->insns[1]); if (err) goto sigsegv; /* Flush instruction space. */ flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); } return 0; sigill: do_exit(SIGILL); return -EINVAL; sigsegv: force_sigsegv(signo, current); return -EFAULT; }
/* * Create a kernel thread */ static void __noreturn kernel_thread_helper(void *arg, int (*fn)(void *)) { do_exit(fn(arg)); }
bool emulate_vsyscall(struct pt_regs *regs, unsigned long address) { struct task_struct *tsk; unsigned long caller; int vsyscall_nr, syscall_nr, tmp; int prev_sig_on_uaccess_error; long ret; /* * No point in checking CS -- the only way to get here is a user mode * trap to a high address, which means that we're in 64-bit user code. */ WARN_ON_ONCE(address != regs->ip); if (vsyscall_mode == NONE) { warn_bad_vsyscall(KERN_INFO, regs, "vsyscall attempted with vsyscall=none"); return false; } vsyscall_nr = addr_to_vsyscall_nr(address); trace_emulate_vsyscall(vsyscall_nr); if (vsyscall_nr < 0) { warn_bad_vsyscall(KERN_WARNING, regs, "misaligned vsyscall (exploit attempt or buggy program) -- look up the vsyscall kernel parameter if you need a workaround"); goto sigsegv; } if (get_user(caller, (unsigned long __user *)regs->sp) != 0) { warn_bad_vsyscall(KERN_WARNING, regs, "vsyscall with bad stack (exploit attempt?)"); goto sigsegv; } tsk = current; /* * Check for access_ok violations and find the syscall nr. * * NULL is a valid user pointer (in the access_ok sense) on 32-bit and * 64-bit, so we don't need to special-case it here. For all the * vsyscalls, NULL means "don't write anything" not "write it at * address 0". */ switch (vsyscall_nr) { case 0: if (!write_ok_or_segv(regs->di, sizeof(struct timeval)) || !write_ok_or_segv(regs->si, sizeof(struct timezone))) { ret = -EFAULT; goto check_fault; } syscall_nr = __NR_gettimeofday; break; case 1: if (!write_ok_or_segv(regs->di, sizeof(time_t))) { ret = -EFAULT; goto check_fault; } syscall_nr = __NR_time; break; case 2: if (!write_ok_or_segv(regs->di, sizeof(unsigned)) || !write_ok_or_segv(regs->si, sizeof(unsigned))) { ret = -EFAULT; goto check_fault; } syscall_nr = __NR_getcpu; break; } /* * Handle seccomp. regs->ip must be the original value. * See seccomp_send_sigsys and Documentation/prctl/seccomp_filter.txt. * * We could optimize the seccomp disabled case, but performance * here doesn't matter. */ regs->orig_ax = syscall_nr; regs->ax = -ENOSYS; tmp = secure_computing(syscall_nr); if ((!tmp && regs->orig_ax != syscall_nr) || regs->ip != address) { warn_bad_vsyscall(KERN_DEBUG, regs, "seccomp tried to change syscall nr or ip"); do_exit(SIGSYS); } if (tmp) goto do_ret; /* skip requested */ /* * With a real vsyscall, page faults cause SIGSEGV. We want to * preserve that behavior to make writing exploits harder. */ prev_sig_on_uaccess_error = current_thread_info()->sig_on_uaccess_error; current_thread_info()->sig_on_uaccess_error = 1; ret = -EFAULT; switch (vsyscall_nr) { case 0: ret = sys_gettimeofday( (struct timeval __user *)regs->di, (struct timezone __user *)regs->si); break; case 1: ret = sys_time((time_t __user *)regs->di); break; case 2: ret = sys_getcpu((unsigned __user *)regs->di, (unsigned __user *)regs->si, NULL); break; } current_thread_info()->sig_on_uaccess_error = prev_sig_on_uaccess_error; check_fault: if (ret == -EFAULT) { /* Bad news -- userspace fed a bad pointer to a vsyscall. */ warn_bad_vsyscall(KERN_INFO, regs, "vsyscall fault (exploit attempt?)"); /* * If we failed to generate a signal for any reason, * generate one here. (This should be impossible.) */ if (WARN_ON_ONCE(!sigismember(&tsk->pending.signal, SIGBUS) && !sigismember(&tsk->pending.signal, SIGSEGV))) goto sigsegv; return true; /* Don't emulate the ret. */ } regs->ax = ret; do_ret: /* Emulate a ret instruction. */ regs->ip = caller; regs->sp += 8; return true; sigsegv: force_sig(SIGSEGV, current); return true; }
// There was a memory error. Exit. void mem_error() { perror("Out of memory.\n"); do_exit(); }
static inline int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, int signo, sigset_t *oldset, siginfo_t *info) { struct rt_signal_frame __user *sf; int wsaved, err, sf_size; void __user *tail; synchronize_user_stack(); save_and_clear_fpu(); wsaved = get_thread_wsaved(); sf_size = sizeof(struct rt_signal_frame); if (current_thread_info()->fpsaved[0] & FPRS_FEF) sf_size += sizeof(__siginfo_fpu_t); if (wsaved) sf_size += sizeof(__siginfo_rwin_t); sf = (struct rt_signal_frame __user *) get_sigframe(ka, regs, sf_size); if (invalid_frame_pointer (sf)) goto sigill; tail = (sf + 1); err = copy_to_user(&sf->regs, regs, sizeof (*regs)); if (current_thread_info()->fpsaved[0] & FPRS_FEF) { __siginfo_fpu_t __user *fpu_save = tail; tail += sizeof(__siginfo_fpu_t); err |= save_fpu_state(regs, fpu_save); err |= __put_user((u64)fpu_save, &sf->fpu_save); } else { err |= __put_user(0, &sf->fpu_save); } if (wsaved) { __siginfo_rwin_t __user *rwin_save = tail; tail += sizeof(__siginfo_rwin_t); err |= save_rwin_state(wsaved, rwin_save); err |= __put_user((u64)rwin_save, &sf->rwin_save); set_thread_wsaved(0); } else { err |= __put_user(0, &sf->rwin_save); } err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp); err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags); err |= __put_user(current->sas_ss_size, &sf->stack.ss_size); err |= copy_to_user(&sf->mask, oldset, sizeof(sigset_t)); if (!wsaved) { err |= copy_in_user((u64 __user *)sf, (u64 __user *)(regs->u_regs[UREG_FP] + STACK_BIAS), sizeof(struct reg_window)); } else { struct reg_window *rp; rp = ¤t_thread_info()->reg_window[wsaved - 1]; err |= copy_to_user(sf, rp, sizeof(struct reg_window)); } if (info) err |= copy_siginfo_to_user(&sf->info, info); else { err |= __put_user(signo, &sf->info.si_signo); err |= __put_user(SI_NOINFO, &sf->info.si_code); } if (err) goto sigsegv; regs->u_regs[UREG_FP] = ((unsigned long) sf) - STACK_BIAS; regs->u_regs[UREG_I0] = signo; regs->u_regs[UREG_I1] = (unsigned long) &sf->info; regs->u_regs[UREG_I2] = (unsigned long) &sf->info; regs->tpc = (unsigned long) ka->sa.sa_handler; regs->tnpc = (regs->tpc + 4); if (test_thread_flag(TIF_32BIT)) { regs->tpc &= 0xffffffff; regs->tnpc &= 0xffffffff; } regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; return 0; sigill: do_exit(SIGILL); return -EINVAL; sigsegv: force_sigsegv(signo, current); return -EFAULT; }
asmlinkage long sys_exit(int error_code) { do_exit((error_code&0xff)<<8); }
static inline int setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs) { struct rt_signal_frame __user *sf; int wsaved, err, sf_size; void __user *tail; /* 1. Make sure everything is clean */ synchronize_user_stack(); save_and_clear_fpu(); wsaved = get_thread_wsaved(); sf_size = sizeof(struct rt_signal_frame); if (current_thread_info()->fpsaved[0] & FPRS_FEF) sf_size += sizeof(__siginfo_fpu_t); if (wsaved) sf_size += sizeof(__siginfo_rwin_t); sf = (struct rt_signal_frame __user *) get_sigframe(ksig, regs, sf_size); if (invalid_frame_pointer (sf)) { do_exit(SIGILL); /* won't return, actually */ return -EINVAL; } tail = (sf + 1); /* 2. Save the current process state */ err = copy_to_user(&sf->regs, regs, sizeof (*regs)); if (current_thread_info()->fpsaved[0] & FPRS_FEF) { __siginfo_fpu_t __user *fpu_save = tail; tail += sizeof(__siginfo_fpu_t); err |= save_fpu_state(regs, fpu_save); err |= __put_user((u64)fpu_save, &sf->fpu_save); } else { err |= __put_user(0, &sf->fpu_save); } if (wsaved) { __siginfo_rwin_t __user *rwin_save = tail; tail += sizeof(__siginfo_rwin_t); err |= save_rwin_state(wsaved, rwin_save); err |= __put_user((u64)rwin_save, &sf->rwin_save); set_thread_wsaved(0); } else { err |= __put_user(0, &sf->rwin_save); } /* Setup sigaltstack */ err |= __save_altstack(&sf->stack, regs->u_regs[UREG_FP]); err |= copy_to_user(&sf->mask, sigmask_to_save(), sizeof(sigset_t)); if (!wsaved) { err |= copy_in_user((u64 __user *)sf, (u64 __user *)(regs->u_regs[UREG_FP] + STACK_BIAS), sizeof(struct reg_window)); } else { struct reg_window *rp; rp = ¤t_thread_info()->reg_window[wsaved - 1]; err |= copy_to_user(sf, rp, sizeof(struct reg_window)); } if (ksig->ka.sa.sa_flags & SA_SIGINFO) err |= copy_siginfo_to_user(&sf->info, &ksig->info); else { err |= __put_user(ksig->sig, &sf->info.si_signo); err |= __put_user(SI_NOINFO, &sf->info.si_code); } if (err) return err; /* 3. signal handler back-trampoline and parameters */ regs->u_regs[UREG_FP] = ((unsigned long) sf) - STACK_BIAS; regs->u_regs[UREG_I0] = ksig->sig; regs->u_regs[UREG_I1] = (unsigned long) &sf->info; /* The sigcontext is passed in this way because of how it * is defined in GLIBC's /usr/include/bits/sigcontext.h * for sparc64. It includes the 128 bytes of siginfo_t. */ regs->u_regs[UREG_I2] = (unsigned long) &sf->info; /* 5. signal handler */ regs->tpc = (unsigned long) ksig->ka.sa.sa_handler; regs->tnpc = (regs->tpc + 4); if (test_thread_flag(TIF_32BIT)) { regs->tpc &= 0xffffffff; regs->tnpc &= 0xffffffff; } /* 4. return to kernel instructions */ regs->u_regs[UREG_I7] = (unsigned long)ksig->ka.ka_restorer; return 0; }
asmlinkage unsigned long asm_do_sig(unsigned long esr, struct pt_regs *regs) { struct siginfo info; struct task_struct *tsk; struct mm_struct *mm; int sig; int trapidx = 0; unsigned long addr; //register unsigned long sp asm("sp"); switch(esr & ESR_CODE) { case TCT_PRIVILEGED: addr = regs->elkr; printk("Privileged Instruction Exception @ %lx\n", addr); sig = SIGSEGV; trapidx = 1; break; case TCT_UNDEFINED: addr = regs->elkr; printk("Undefined Instruction Exception @ %lx\n", addr); sig = SIGSEGV; trapidx = 2; break; case TCT_ITLB: addr = regs->elkr; printk("Instruction TLB Exception @ %lx\n", addr); sig = SIGSEGV; trapidx = 3; break; case TCT_DTLB: addr = regs->elkr; printk("Data TLB Exception @ %lx\n", addr); sig = SIGSEGV; trapidx = 4; break; case TCT_FETCH_ABORT: addr = regs->elkr; printk("Fetch Abort Exception @ address %lx\n", addr); sig = SIGABRT; trapidx= 5; break; case TCT_DATA_ABORT:/*interrupt exception */ addr = regs->elkr; printk("Data Abort Exception @ %lx\n", addr); sig = SIGABRT; trapidx = 6; break; case TCT_ZERO_DIV:/*interrupt exception */ addr = regs->elkr; printk("Zero Division Exception @ %lx\n", addr); sig = SIGSEGV; trapidx = 7; break; default: addr = regs->elkr; printk("Unknown exception, defaulting to SIGSEGV @ %lx\n", addr); sig = SIGSEGV; trapidx = 8; break; } memset(&info, 0, sizeof(info)); info.si_signo = sig; info.si_addr = (void*)addr; tsk = current; mm = tsk->mm; /* * If we're on the kernel stack or during disabled interrupts * or in an atomic section or if we have no user context, the kernel gets the fault. */ if( !mm || in_atomic()) { /* the kernel gets the fault */ bust_spinlocks(1); printk(KERN_ALERT "%s: unhandled kernel space fault (%d) @ %lx\n", tsk->comm, sig, addr); bust_spinlocks(0); local_irq_enable(); do_exit(SIGKILL); return 0; } else { /* the user space gets the fault */ if( sig != SIGTRAP ) printk(KERN_ERR "%s: unhandled user space fault (%d) @ %lx\n", tsk->comm, sig, addr); force_sig_info(sig, &info, tsk); return regs->r1; } }
asmlinkage int irix_ioctl(int fd, unsigned long cmd, unsigned long arg) { struct tty_struct *tp, *rtp; mm_segment_t old_fs; int i, error = 0; #ifdef DEBUG_IOCTLS printk("[%s:%d] irix_ioctl(%d, ", current->comm, current->pid, fd); #endif switch(cmd) { case 0x00005401: #ifdef DEBUG_IOCTLS printk("TCGETA, %08lx) ", arg); #endif error = sys_ioctl(fd, TCGETA, arg); break; case 0x0000540d: { struct termios kt; struct irix_termios __user *it = (struct irix_termios __user *) arg; #ifdef DEBUG_IOCTLS printk("TCGETS, %08lx) ", arg); #endif if (!access_ok(VERIFY_WRITE, it, sizeof(*it))) { error = -EFAULT; break; } old_fs = get_fs(); set_fs(get_ds()); error = sys_ioctl(fd, TCGETS, (unsigned long) &kt); set_fs(old_fs); if (error) break; error = __put_user(kt.c_iflag, &it->c_iflag); error |= __put_user(kt.c_oflag, &it->c_oflag); error |= __put_user(kt.c_cflag, &it->c_cflag); error |= __put_user(kt.c_lflag, &it->c_lflag); for (i = 0; i < NCCS; i++) error |= __put_user(kt.c_cc[i], &it->c_cc[i]); break; } case 0x0000540e: { struct termios kt; struct irix_termios *it = (struct irix_termios *) arg; #ifdef DEBUG_IOCTLS printk("TCSETS, %08lx) ", arg); #endif if (!access_ok(VERIFY_READ, it, sizeof(*it))) { error = -EFAULT; break; } old_fs = get_fs(); set_fs(get_ds()); error = sys_ioctl(fd, TCGETS, (unsigned long) &kt); set_fs(old_fs); if (error) break; error = __get_user(kt.c_iflag, &it->c_iflag); error |= __get_user(kt.c_oflag, &it->c_oflag); error |= __get_user(kt.c_cflag, &it->c_cflag); error |= __get_user(kt.c_lflag, &it->c_lflag); for (i = 0; i < NCCS; i++) error |= __get_user(kt.c_cc[i], &it->c_cc[i]); if (error) break; old_fs = get_fs(); set_fs(get_ds()); error = sys_ioctl(fd, TCSETS, (unsigned long) &kt); set_fs(old_fs); break; } case 0x0000540f: #ifdef DEBUG_IOCTLS printk("TCSETSW, %08lx) ", arg); #endif error = sys_ioctl(fd, TCSETSW, arg); break; case 0x00005471: #ifdef DEBUG_IOCTLS printk("TIOCNOTTY, %08lx) ", arg); #endif error = sys_ioctl(fd, TIOCNOTTY, arg); break; case 0x00007416: { pid_t pid; #ifdef DEBUG_IOCTLS printk("TIOCGSID, %08lx) ", arg); #endif old_fs = get_fs(); set_fs(get_ds()); error = sys_ioctl(fd, TIOCGSID, (unsigned long)&pid); set_fs(old_fs); if (!error) error = put_user(pid, (unsigned long __user *) arg); break; } case 0x746e: /* TIOCSTART, same effect as hitting ^Q */ #ifdef DEBUG_IOCTLS printk("TIOCSTART, %08lx) ", arg); #endif error = sys_ioctl(fd, TCXONC, TCOON); break; case 0x20006968: #ifdef DEBUG_IOCTLS printk("SIOCGETLABEL, %08lx) ", arg); #endif error = -ENOPKG; break; case 0x40047477: #ifdef DEBUG_IOCTLS printk("TIOCGPGRP, %08lx) ", arg); #endif error = sys_ioctl(fd, TIOCGPGRP, arg); #ifdef DEBUG_IOCTLS printk("arg=%d ", *(int *)arg); #endif break; case 0x40087468: #ifdef DEBUG_IOCTLS printk("TIOCGWINSZ, %08lx) ", arg); #endif error = sys_ioctl(fd, TIOCGWINSZ, arg); break; case 0x8004667e: error = sys_ioctl(fd, FIONBIO, arg); break; case 0x80047476: error = sys_ioctl(fd, TIOCSPGRP, arg); break; case 0x8020690c: error = sys_ioctl(fd, SIOCSIFADDR, arg); break; case 0x80206910: error = sys_ioctl(fd, SIOCSIFFLAGS, arg); break; case 0xc0206911: error = sys_ioctl(fd, SIOCGIFFLAGS, arg); break; case 0xc020691b: error = sys_ioctl(fd, SIOCGIFMETRIC, arg); break; default: { #ifdef DEBUG_MISSING_IOCTL char *msg = "Unimplemented IOCTL cmd tell [email protected]\n"; #ifdef DEBUG_IOCTLS printk("UNIMP_IOCTL, %08lx)\n", arg); #endif old_fs = get_fs(); set_fs(get_ds()); sys_write(2, msg, strlen(msg)); set_fs(old_fs); printk("[%s:%d] Does unimplemented IRIX ioctl cmd %08lx\n", current->comm, current->pid, cmd); do_exit(255); #else error = sys_ioctl(fd, cmd, arg); #endif } }; #ifdef DEBUG_IOCTLS printk("error=%d\n", error); #endif return error; }