Exemple #1
0
static void pth_thread_refl_fault(struct uthread *uthread, unsigned int trap_nr,
                                  unsigned int err, unsigned long aux)
{
	struct pthread_tcb *pthread = (struct pthread_tcb*)uthread;
	pthread->state = PTH_BLK_SYSC;
	mcs_pdr_lock(&queue_lock);
	threads_active--;
	TAILQ_REMOVE(&active_queue, pthread, tq_next);
	mcs_pdr_unlock(&queue_lock);

	/* TODO: RISCV/x86 issue! (0 is divby0, 14 is PF, etc) */
#if defined(__i386__) || defined(__x86_64__) 
	switch(trap_nr) {
		case 0:
			handle_div_by_zero(uthread, err, aux);
			break;
		case 13:
			handle_gp_fault(uthread, err, aux);
			break;
		case 14:
			handle_page_fault(uthread, err, aux);
			break;
		default:
			printf("Pthread has unhandled fault: %d, err: %d, aux: %p\n",
			       trap_nr, err, aux);
			/* Note that uthread.c already copied out our ctx into the uth
			 * struct */
			print_user_context(&uthread->u_ctx);
			printf("Turn on printx to spew unhandled, malignant trap info\n");
			exit(-1);
	}
#else
	#error "Handling hardware faults is currently only supported on x86"
#endif
}
Exemple #2
0
/*
 * We give a *copy* of the faultinfo in the regs to segv.
 * This must be done, since nesting SEGVs could overwrite
 * the info in the regs. A pointer to the info then would
 * give us bad data!
 */
unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc)
{
	struct siginfo si;
	void *catcher;
	int err;
        int is_write = FAULT_WRITE(fi);
        unsigned long address = FAULT_ADDRESS(fi);

        if(!is_user && (address >= start_vm) && (address < end_vm)){
                flush_tlb_kernel_vm();
                return(0);
        }
	else if(current->mm == NULL)
		panic("Segfault with no mm");

	if (SEGV_IS_FIXABLE(&fi) || SEGV_MAYBE_FIXABLE(&fi))
		err = handle_page_fault(address, ip, is_write, is_user, &si.si_code);
	else {
		err = -EFAULT;
		/* A thread accessed NULL, we get a fault, but CR2 is invalid.
		 * This code is used in __do_copy_from_user() of TT mode. */
		address = 0;
	}

	catcher = current->thread.fault_catcher;
	if(!err)
		return(0);
	else if(catcher != NULL){
		current->thread.fault_addr = (void *) address;
		do_longjmp(catcher, 1);
	}
	else if(current->thread.fault_addr != NULL)
		panic("fault_addr set but no fault catcher");
        else if(!is_user && arch_fixup(ip, sc))
		return(0);

 	if(!is_user)
		panic("Kernel mode fault at addr 0x%lx, ip 0x%lx",
		      address, ip);

	if (err == -EACCES) {
		si.si_signo = SIGBUS;
		si.si_errno = 0;
		si.si_code = BUS_ADRERR;
		si.si_addr = (void __user *)address;
                current->thread.arch.faultinfo = fi;
		force_sig_info(SIGBUS, &si, current);
	} else if (err == -ENOMEM) {
		printk("VM: killing process %s\n", current->comm);
		do_exit(SIGKILL);
	} else {
		BUG_ON(err != -EFAULT);
		si.si_signo = SIGSEGV;
		si.si_addr = (void __user *) address;
                current->thread.arch.faultinfo = fi;
		force_sig_info(SIGSEGV, &si, current);
	}
	return(0);
}
Exemple #3
0
void isr_handler(registers_t* regs)
{

  if(exception_depth++ >= 3){
    printf("Exception depth exceeded 3");
    while(1);
  }
  
  if((regs->int_no < 32) && (isFatal(regs->int_no))){

    terminal_bluescreen();
    char* name = interrupt_name(regs->int_no);

    printf("\t\t\t\t\t\tSOMETHING JUST WENT VERY WRONG\n\nI'd like to");
    printf(" interject for a moment.  What you're referring to as:\n\n\t");
    printf("Interrupt %d\n\nIs in fact, a fatal exception, ", (int) regs->int_no);
    printf("or as I've recently taken to  calling it:\n\n");
    printf("\t%s with error code %p\n", name, (void *) regs->err_code);
    
    //Halt the machine
    while(1);
    
  }

  if(regs->int_no >= 32){
    //Handle our IRQs
    //interrupt numbers 0-31 are reserved by intel, so subtract 32
    //to get the isa irq code.  32 is an arbitary number decided in the
    //PIC initialization code
    int isa_irq = (regs->int_no - 32);
    
    switch(isa_irq){
    case 0:
      //Programmable interval timer interrupt
      break;
    case 1:
      //Keyboard interrupt
      handle_keyboard_interrupt();
      break;
    }
    
    PIC_sendEOI(regs->int_no);
  }else{
    //It is an exception we can (and should) handle
    switch(regs->int_no){
    case 14:
      handle_page_fault(regs->err_code);
      break;
    }
  }

  exception_depth = 0;
  return;
}
Exemple #4
0
static void
handle_fault_store(struct hw_trapframe *state)
{
    if(in_kernel(state))
    {
        print_trapframe(state);
        panic("Store Page Fault in the Kernel at %p!", state->badvaddr);
    }

    set_current_ctx_hw(&per_cpu_info[core_id()], state);

    if(handle_page_fault(current, state->badvaddr, PROT_WRITE))
        unhandled_trap(state, "Store Page Fault");
}
Exemple #5
0
static void
handle_fault_fetch(struct hw_trapframe *state)
{
    if(in_kernel(state))
    {
        print_trapframe(state);
        panic("Instruction Page Fault in the Kernel at %p!", state->epc);
    }

    set_current_ctx_hw(&per_cpu_info[core_id()], state);

#warning "returns EAGAIN if you should reflect the fault"
    if(handle_page_fault(current, state->epc, PROT_EXEC))
        unhandled_trap(state, "Instruction Page Fault");
}
Exemple #6
0
static void
handle_fault_load(struct hw_trapframe *state)
{
    if(in_kernel(state))
    {
        print_trapframe(state);
        panic("Load Page Fault in the Kernel at %p!", state->badvaddr);
    }

    set_current_ctx_hw(&per_cpu_info[core_id()], state);

#warning "returns EAGAIN if you should reflect the fault"
    if(handle_page_fault(current, state->badvaddr, PROT_READ))
        unhandled_trap(state, "Load Page Fault");
}
Exemple #7
0
/*
 * Check an async_tlb structure to see if a deferred fault is waiting,
 * and if so pass it to the page-fault code.
 */
static void handle_async_page_fault(struct pt_regs *regs,
				    struct async_tlb *async)
{
	if (async->fault_num) {
		/*
		 * Clear async->fault_num before calling the page-fault
		 * handler so that if we re-interrupt before returning
		 * from the function we have somewhere to put the
		 * information from the new interrupt.
		 */
		int fault_num = async->fault_num;
		async->fault_num = 0;
		handle_page_fault(regs, fault_num, async->is_fault,
				  async->address, async->is_write);
	}
}
static unsigned long maybe_map(unsigned long virt, int is_write)
{
    pte_t pte;
    int err;

    void *phys = um_virt_to_phys(current, virt, &pte);
    int dummy_code;

    if(IS_ERR(phys) || (is_write && !pte_write(pte))) {
        err = handle_page_fault(virt, 0, is_write, 1, &dummy_code);
        if(err)
            return(0);
        phys = um_virt_to_phys(current, virt, NULL);
    }
    return((unsigned long) phys);
}
static pte_t *maybe_map(unsigned long virt, int is_write)
{
	pte_t *pte = virt_to_pte(current->mm, virt);
	int err, dummy_code;

	if ((pte == NULL) || !pte_present(*pte) ||
	    (is_write && !pte_write(*pte))) {
		err = handle_page_fault(virt, 0, is_write, 1, &dummy_code);
		if (err)
			return NULL;
		pte = virt_to_pte(current->mm, virt);
	}
	if (!pte_present(*pte))
		pte = NULL;

	return pte;
}
Exemple #10
0
static void thread0_thread_refl_fault(struct uthread *uth,
                                      struct user_context *ctx)
{
	unsigned int trap_nr = __arch_refl_get_nr(ctx);
	unsigned int err = __arch_refl_get_err(ctx);
	unsigned long aux = __arch_refl_get_aux(ctx);

	assert(ctx->type == ROS_HW_CTX);
	switch (trap_nr) {
	case HW_TRAP_PAGE_FAULT:
		if (!handle_page_fault(uth, err, aux))
			refl_error(uth, trap_nr, err, aux);
		break;
	default:
		refl_error(uth, trap_nr, err, aux);
	}
}
Exemple #11
0
void handle_trap(struct interrupt_frame *frame)
{
    unsigned int address;
    int trap_cause = __builtin_nyuzi_read_control_reg(CR_TRAP_CAUSE);

    switch (trap_cause & 0xf)
    {
        case TT_PAGE_FAULT:
        case TT_ILLEGAL_STORE:
            address = __builtin_nyuzi_read_control_reg(CR_TRAP_ADDR);
            enable_interrupts();
            if (!handle_page_fault(address, (trap_cause & 0x10) != 0))
            {
                // Jump to user_copy fault handler if set
                if (fault_handler[current_hw_thread()] != 0)
                    frame->pc = fault_handler[current_hw_thread()];
                else
                    bad_fault(frame);
            }

            disable_interrupts();
            break;

        case TT_SYSCALL:
            // Enable interrupts
            address = __builtin_nyuzi_read_control_reg(CR_TRAP_ADDR);
            enable_interrupts();

            frame->gpr[0] = handle_syscall(frame->gpr[0], frame->gpr[1],
                                           frame->gpr[2], frame->gpr[3],
                                           frame->gpr[4], frame->gpr[5]);

            frame->pc += 4;    // Next instruction
            disable_interrupts();
            break;

        case TT_INTERRUPT:
            handle_interrupt(frame);
            break;

        default:
            bad_fault(frame);
    }
}
Exemple #12
0
/*
 * This routine effectively re-issues asynchronous page faults
 * when we are returning to user space.
 */
void do_async_page_fault(struct pt_regs *regs)
{
	struct async_tlb *async = &current->thread.dma_async_tlb;

	/*
	 * Clear thread flag early.  If we re-interrupt while processing
	 * code here, we will reset it and recall this routine before
	 * returning to user space.
	 */
	clear_thread_flag(TIF_ASYNC_TLB);

	if (async->fault_num) {
		/*
		 * Clear async->fault_num before calling the page-fault
		 * handler so that if we re-interrupt before returning
		 * from the function we have somewhere to put the
		 * information from the new interrupt.
		 */
		int fault_num = async->fault_num;
		async->fault_num = 0;
		handle_page_fault(regs, fault_num, async->is_fault,
				  async->address, async->is_write);
	}
}
Exemple #13
0
static void handle_fault_fetch(trapframe_t* tf)
{
  if (handle_page_fault(tf->badvaddr, PROT_EXEC) != 0)
    segfault(tf, tf->badvaddr, "fetch");
}
Exemple #14
0
int
vm_event(vm_t* vm, seL4_MessageInfo_t tag)
{
    seL4_Word label;
    seL4_Word length;

    label = seL4_MessageInfo_get_label(tag);
    length = seL4_MessageInfo_get_length(tag);

    switch (label) {
    case SEL4_PFIPC_LABEL: {
        int err;
        fault_t* fault;
        fault = vm->fault;
        err = new_fault(fault);
        assert(!err);
        do {
            err = handle_page_fault(vm, fault);
            if (err) {
                return -1;
            }
        } while (!fault_handled(fault));
    }
    break;

    case SEL4_EXCEPT_IPC_LABEL: {
        int err;
        assert(length == SEL4_EXCEPT_IPC_LENGTH);
        err = handle_syscall(vm, length);
        assert(!err);
        if (!err) {
            seL4_MessageInfo_t reply;
            reply = seL4_MessageInfo_new(0, 0, 0, 0);
            seL4_Reply(reply);
        }
    }
    break;

    case SEL4_USER_EXCEPTION_LABEL: {
        seL4_Word ip;
        int err;
        assert(length == SEL4_USER_EXCEPTION_LENGTH);
        ip = seL4_GetMR(0);
        err = handle_exception(vm, ip);
        assert(!err);
        if (!err) {
            seL4_MessageInfo_t reply;

            reply = seL4_MessageInfo_new(0, 0, 0, 0);
            seL4_Reply(reply);
        }
    }
    break;
    case SEL4_VGIC_MAINTENANCE_LABEL: {
        int idx;
        int err;
        assert(length == SEL4_VGIC_MAINTENANCE_LENGTH);
        idx = seL4_GetMR(EXCEPT_IPC_SYS_MR_R0);
        /* Currently not handling spurious IRQs */
        assert(idx >= 0);

        err = handle_vgic_maintenance(vm, idx);
        assert(!err);
        if (!err) {
            seL4_MessageInfo_t reply;

            reply = seL4_MessageInfo_new(0, 0, 0, 0);
            seL4_Reply(reply);
        }
    }
    break;
    case SEL4_VCPU_FAULT_LABEL: {
        seL4_MessageInfo_t reply;
        seL4_UserContext regs;
        seL4_CPtr tcb;
        uint32_t hsr;
        int err;
        assert(length == SEL4_VCPU_FAULT_LENGTH);
        hsr = seL4_GetMR(EXCEPT_IPC_SYS_MR_R0);
        /* Increment the PC and ignore the fault */
        tcb = vm_get_tcb(vm);
        err = seL4_TCB_ReadRegisters(tcb, false, 0,
                                     sizeof(regs) / sizeof(regs.pc), &regs);
        assert(!err);
        switch (hsr) {
        case HSR_WFI:
        case HSR_WFE:
            regs.pc += (regs.cpsr & BIT(5)) ? 2 : 4;
            err = seL4_TCB_WriteRegisters(tcb, false, 0,
                                          sizeof(regs) / sizeof(regs.pc), &regs);
            assert(!err);
            reply = seL4_MessageInfo_new(0, 0, 0, 0);
            seL4_Reply(reply);
            return 0;
        default:
            printf("Unhandled VCPU fault from [%s]: HSR 0x%08x\n", vm->name, hsr);
            print_ctx_regs(&regs);
            return -1;
        }
    }
    break;
    default:
        /* What? Why are we here? What just happened? */
        printf("Unknown fault from [%s]: label=0x%x length=0x%x\n",
               vm->name, label, length);
        return -1;
    }
    return 0;
}
Exemple #15
0
/*
 * This routine handles page faults.  It determines the address, and the
 * problem, and then passes it handle_page_fault() for normal DTLB and
 * ITLB issues, and for DMA or SN processor faults when we are in user
 * space.  For the latter, if we're in kernel mode, we just save the
 * interrupt away appropriately and return immediately.  We can't do
 * page faults for user code while in kernel mode.
 */
void do_page_fault(struct pt_regs *regs, int fault_num,
		   unsigned long address, unsigned long write)
{
	int is_page_fault;

	/* This case should have been handled by do_page_fault_ics(). */
	BUG_ON(write & ~1);

#if CHIP_HAS_TILE_DMA()
	/*
	 * If it's a DMA fault, suspend the transfer while we're
	 * handling the miss; we'll restart after it's handled.  If we
	 * don't suspend, it's possible that this process could swap
	 * out and back in, and restart the engine since the DMA is
	 * still 'running'.
	 */
	if (fault_num == INT_DMATLB_MISS ||
	    fault_num == INT_DMATLB_ACCESS ||
	    fault_num == INT_DMATLB_MISS_DWNCL ||
	    fault_num == INT_DMATLB_ACCESS_DWNCL) {
		__insn_mtspr(SPR_DMA_CTR, SPR_DMA_CTR__SUSPEND_MASK);
		while (__insn_mfspr(SPR_DMA_USER_STATUS) &
		       SPR_DMA_STATUS__BUSY_MASK)
			;
	}
#endif

	/* Validate fault num and decide if this is a first-time page fault. */
	switch (fault_num) {
	case INT_ITLB_MISS:
	case INT_DTLB_MISS:
#if CHIP_HAS_TILE_DMA()
	case INT_DMATLB_MISS:
	case INT_DMATLB_MISS_DWNCL:
#endif
#if CHIP_HAS_SN_PROC()
	case INT_SNITLB_MISS:
	case INT_SNITLB_MISS_DWNCL:
#endif
		is_page_fault = 1;
		break;

	case INT_DTLB_ACCESS:
#if CHIP_HAS_TILE_DMA()
	case INT_DMATLB_ACCESS:
	case INT_DMATLB_ACCESS_DWNCL:
#endif
		is_page_fault = 0;
		break;

	default:
		panic("Bad fault number %d in do_page_fault", fault_num);
	}

#if CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC()
	if (EX1_PL(regs->ex1) != USER_PL) {
		struct async_tlb *async;
		switch (fault_num) {
#if CHIP_HAS_TILE_DMA()
		case INT_DMATLB_MISS:
		case INT_DMATLB_ACCESS:
		case INT_DMATLB_MISS_DWNCL:
		case INT_DMATLB_ACCESS_DWNCL:
			async = &current->thread.dma_async_tlb;
			break;
#endif
#if CHIP_HAS_SN_PROC()
		case INT_SNITLB_MISS:
		case INT_SNITLB_MISS_DWNCL:
			async = &current->thread.sn_async_tlb;
			break;
#endif
		default:
			async = NULL;
		}
		if (async) {

			/*
			 * No vmalloc check required, so we can allow
			 * interrupts immediately at this point.
			 */
			local_irq_enable();

			set_thread_flag(TIF_ASYNC_TLB);
			if (async->fault_num != 0) {
				panic("Second async fault %d;"
				      " old fault was %d (%#lx/%ld)",
				      fault_num, async->fault_num,
				      address, write);
			}
			BUG_ON(fault_num == 0);
			async->fault_num = fault_num;
			async->is_fault = is_page_fault;
			async->is_write = write;
			async->address = address;
			return;
		}
	}
#endif

	handle_page_fault(regs, fault_num, is_page_fault, address, write);
}
/*
 *  stress_userfaultfd_oomable()
 *	stress userfaultfd system call, this
 *	is an OOM-able child process that the
 *	parent can restart
 */
static int stress_userfaultfd_oomable(
	const args_t *args,
	const size_t userfaultfd_bytes)
{
	const size_t page_size = args->page_size;
	size_t sz;
	uint8_t *data;
	void *zero_page = NULL;
	int fd = -1, fdinfo = -1, status, rc = EXIT_SUCCESS, count = 0;
	const unsigned int uffdio_copy = 1 << _UFFDIO_COPY;
	const unsigned int uffdio_zeropage = 1 << _UFFDIO_ZEROPAGE;
	pid_t pid;
	struct uffdio_api api;
	struct uffdio_register reg;
	context_t c;
	bool do_poll = true;
	char filename[PATH_MAX];

	/* Child clone stack */
	static uint8_t stack[STACK_SIZE];
	const ssize_t stack_offset =
		stress_get_stack_direction() * (STACK_SIZE - 64);
	uint8_t *stack_top = stack + stack_offset;

	sz = userfaultfd_bytes & ~(page_size - 1);

	if (posix_memalign(&zero_page, page_size, page_size)) {
		pr_err("%s: zero page allocation failed\n", args->name);
		return EXIT_NO_RESOURCE;
	}

	data = mmap(NULL, sz, PROT_READ | PROT_WRITE,
		MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
	if (data == MAP_FAILED) {
		rc = EXIT_NO_RESOURCE;
		pr_err("%s: mmap failed\n", args->name);
		goto free_zeropage;
	}

	/* Get userfault fd */
	if ((fd = shim_userfaultfd(0)) < 0) {
		if (errno == ENOSYS) {
			pr_inf("%s: stressor will be skipped, "
				"userfaultfd not supported\n",
				args->name);
			rc = EXIT_NOT_IMPLEMENTED;
			goto unmap_data;
		}
		rc = exit_status(errno);
		pr_err("%s: userfaultfd failed, errno = %d (%s)\n",
			args->name, errno, strerror(errno));
		goto unmap_data;
	}

	(void)snprintf(filename, sizeof(filename), "/proc/%d/fdinfo/%d",
		getpid(), fd);
	fdinfo = open(filename, O_RDONLY);

	if (stress_set_nonblock(fd) < 0)
		do_poll = false;

	/* API sanity check */
	(void)memset(&api, 0, sizeof(api));
	api.api = UFFD_API;
	api.features = 0;
	if (ioctl(fd, UFFDIO_API, &api) < 0) {
		pr_err("%s: ioctl UFFDIO_API failed, errno = %d (%s)\n",
			args->name, errno, strerror(errno));
		rc = EXIT_FAILURE;
		goto unmap_data;
	}
	if (api.api != UFFD_API) {
		pr_err("%s: ioctl UFFDIO_API API check failed\n",
			args->name);
		rc = EXIT_FAILURE;
		goto unmap_data;
	}

	/* Register fault handling mode */
	(void)memset(&reg, 0, sizeof(reg));
	reg.range.start = (unsigned long)data;
	reg.range.len = sz;
	reg.mode = UFFDIO_REGISTER_MODE_MISSING;
	if (ioctl(fd, UFFDIO_REGISTER, &reg) < 0) {
		pr_err("%s: ioctl UFFDIO_REGISTER failed, errno = %d (%s)\n",
			args->name, errno, strerror(errno));
		rc = EXIT_FAILURE;
		goto unmap_data;
	}

	/* OK, so do we have copy supported? */
	if ((reg.ioctls & uffdio_copy) != uffdio_copy) {
		pr_err("%s: ioctl UFFDIO_REGISTER did not support _UFFDIO_COPY\n",
			args->name);
		rc = EXIT_FAILURE;
		goto unmap_data;
	}
	/* OK, so do we have zeropage supported? */
	if ((reg.ioctls & uffdio_zeropage) != uffdio_zeropage) {
		pr_err("%s: ioctl UFFDIO_REGISTER did not support _UFFDIO_ZEROPAGE\n",
			args->name);
		rc = EXIT_FAILURE;
		goto unmap_data;
	}

	/* Set up context for child */
	c.args = args;
	c.data = data;
	c.sz = sz;
	c.page_size = page_size;
	c.parent = getpid();

	/*
	 *  We need to clone the child and share the same VM address space
	 *  as parent so we can perform the page fault handling
	 */
	pid = clone(stress_userfaultfd_child, align_stack(stack_top),
		SIGCHLD | CLONE_FILES | CLONE_FS | CLONE_SIGHAND | CLONE_VM, &c);
	if (pid < 0) {
		pr_err("%s: fork failed, errno = %d (%s)\n",
			args->name, errno, strerror(errno));
		goto unreg;
	}

	/* Parent */
	do {
		struct uffd_msg msg;
		ssize_t ret;

		/* check we should break out before we block on the read */
		if (!g_keep_stressing_flag)
			break;

		/*
		 * polled wait exercises userfaultfd_poll
		 * in the kernel, but only works if fd is NONBLOCKing
		 */
		if (do_poll) {
			struct pollfd fds[1];

			(void)memset(fds, 0, sizeof fds);
			fds[0].fd = fd;
			fds[0].events = POLLIN;
			/* wait for 1 second max */

			ret = poll(fds, 1, 1000);
			if (ret == 0)
				continue;	/* timed out, redo the poll */
			if (ret < 0) {
				if (errno == EINTR)
					continue;
				if (errno != ENOMEM) {
					pr_fail_err("poll userfaultfd");
					if (!g_keep_stressing_flag)
						break;
				}
				/*
				 *  poll ran out of free space for internal
				 *  fd tables, so give up and block on the
				 *  read anyway
				 */
				goto do_read;
			}
			/* No data, re-poll */
			if (!(fds[0].revents & POLLIN))
				continue;

			if (LIKELY(fdinfo > -1) &&
			    UNLIKELY(count++ >= COUNT_MAX)) {
				ret = lseek(fdinfo, 0, SEEK_SET);
				if (ret == 0) {
					char buffer[4096];

					ret = read(fdinfo, buffer, sizeof(buffer));
					(void)ret;
				}
				count = 0;
			}
		}

do_read:
		if ((ret = read(fd, &msg, sizeof(msg))) < 0) {
			if (errno == EINTR)
				continue;
			pr_fail_err("read userfaultfd");
			if (!g_keep_stressing_flag)
				break;
			continue;
		}
		/* We only expect a page fault event */
		if (msg.event != UFFD_EVENT_PAGEFAULT) {
			pr_fail_err("userfaultfd msg not pagefault event");
			continue;
		}
		/* We only expect a write fault */
		if (!(msg.arg.pagefault.flags & UFFD_PAGEFAULT_FLAG_WRITE)) {
			pr_fail_err("userfaultfd msg not write page fault event");
			continue;
		}
		/* Go handle the page fault */
		if (handle_page_fault(args, fd, (uint8_t *)(ptrdiff_t)msg.arg.pagefault.address,
				zero_page, data, data + sz, page_size) < 0)
			break;
		inc_counter(args);
	} while (keep_stressing());

	/* Run it over, zap child */
	(void)kill(pid, SIGKILL);
	if (shim_waitpid(pid, &status, 0) < 0) {
		pr_dbg("%s: waitpid failed, errno = %d (%s)\n",
			args->name, errno, strerror(errno));
	}
unreg:
	if (ioctl(fd, UFFDIO_UNREGISTER, &reg) < 0) {
		pr_err("%s: ioctl UFFDIO_UNREGISTER failed, errno = %d (%s)\n",
			args->name, errno, strerror(errno));
		rc = EXIT_FAILURE;
		goto unmap_data;
	}
unmap_data:
	(void)munmap(data, sz);
free_zeropage:
	free(zero_page);
	if (fdinfo > -1)
		(void)close(fdinfo);
	if (fd > -1)
		(void)close(fd);

	return rc;
}
Exemple #17
0
static void handle_fault_store(trapframe_t* tf)
{
  if (handle_page_fault(tf->badvaddr, PROT_WRITE) != 0)
    segfault(tf, tf->badvaddr, "store");
}
Exemple #18
0
static void handle_fault_load(trapframe_t* tf)
{
  if (handle_page_fault(tf->badvaddr, PROT_READ) != 0)
    segfault(tf, tf->badvaddr, "load");
}
Exemple #19
0
void handle_fault_store(trapframe_t* tf)
{
  tf->badvaddr = read_csr(sbadaddr);
  if (handle_page_fault(tf->badvaddr, PROT_WRITE) != 0)
    segfault(tf, tf->badvaddr, "store");
}
Exemple #20
0
/*
 * This routine handles page faults.  It determines the address, and the
 * problem, and then passes it handle_page_fault() for normal DTLB and
 * ITLB issues, and for DMA or SN processor faults when we are in user
 * space.  For the latter, if we're in kernel mode, we just save the
 * interrupt away appropriately and return immediately.  We can't do
 * page faults for user code while in kernel mode.
 */
void do_page_fault(struct pt_regs *regs, int fault_num,
		   unsigned long address, unsigned long write)
{
	int is_page_fault;

#ifdef CONFIG_KPROBES
	/*
	 * This is to notify the fault handler of the kprobes.  The
	 * exception code is redundant as it is also carried in REGS,
	 * but we pass it anyhow.
	 */
	if (notify_die(DIE_PAGE_FAULT, "page fault", regs, -1,
		       regs->faultnum, SIGSEGV) == NOTIFY_STOP)
		return;
#endif

#ifdef __tilegx__
	/*
	 * We don't need early do_page_fault_ics() support, since unlike
	 * Pro we don't need to worry about unlocking the atomic locks.
	 * There is only one current case in GX where we touch any memory
	 * under ICS other than our own kernel stack, and we handle that
	 * here.  (If we crash due to trying to touch our own stack,
	 * we're in too much trouble for C code to help out anyway.)
	 */
	if (write & ~1) {
		unsigned long pc = write & ~1;
		if (pc >= (unsigned long) __start_unalign_asm_code &&
		    pc < (unsigned long) __end_unalign_asm_code) {
			struct thread_info *ti = current_thread_info();
			/*
			 * Our EX_CONTEXT is still what it was from the
			 * initial unalign exception, but now we've faulted
			 * on the JIT page.  We would like to complete the
			 * page fault however is appropriate, and then retry
			 * the instruction that caused the unalign exception.
			 * Our state has been "corrupted" by setting the low
			 * bit in "sp", and stashing r0..r3 in the
			 * thread_info area, so we revert all of that, then
			 * continue as if this were a normal page fault.
			 */
			regs->sp &= ~1UL;
			regs->regs[0] = ti->unalign_jit_tmp[0];
			regs->regs[1] = ti->unalign_jit_tmp[1];
			regs->regs[2] = ti->unalign_jit_tmp[2];
			regs->regs[3] = ti->unalign_jit_tmp[3];
			write &= 1;
		} else {
			pr_alert("%s/%d: ICS set at page fault at %#lx: %#lx\n",
				 current->comm, current->pid, pc, address);
			show_regs(regs);
			do_group_exit(SIGKILL);
			return;
		}
	}
#else
	/* This case should have been handled by do_page_fault_ics(). */
	BUG_ON(write & ~1);
#endif

#if CHIP_HAS_TILE_DMA()
	/*
	 * If it's a DMA fault, suspend the transfer while we're
	 * handling the miss; we'll restart after it's handled.  If we
	 * don't suspend, it's possible that this process could swap
	 * out and back in, and restart the engine since the DMA is
	 * still 'running'.
	 */
	if (fault_num == INT_DMATLB_MISS ||
	    fault_num == INT_DMATLB_ACCESS ||
	    fault_num == INT_DMATLB_MISS_DWNCL ||
	    fault_num == INT_DMATLB_ACCESS_DWNCL) {
		__insn_mtspr(SPR_DMA_CTR, SPR_DMA_CTR__SUSPEND_MASK);
		while (__insn_mfspr(SPR_DMA_USER_STATUS) &
		       SPR_DMA_STATUS__BUSY_MASK)
			;
	}
#endif

	/* Validate fault num and decide if this is a first-time page fault. */
	switch (fault_num) {
	case INT_ITLB_MISS:
	case INT_DTLB_MISS:
#if CHIP_HAS_TILE_DMA()
	case INT_DMATLB_MISS:
	case INT_DMATLB_MISS_DWNCL:
#endif
		is_page_fault = 1;
		break;

	case INT_DTLB_ACCESS:
#if CHIP_HAS_TILE_DMA()
	case INT_DMATLB_ACCESS:
	case INT_DMATLB_ACCESS_DWNCL:
#endif
		is_page_fault = 0;
		break;

	default:
		panic("Bad fault number %d in do_page_fault", fault_num);
	}

#if CHIP_HAS_TILE_DMA()
	if (!user_mode(regs)) {
		struct async_tlb *async;
		switch (fault_num) {
#if CHIP_HAS_TILE_DMA()
		case INT_DMATLB_MISS:
		case INT_DMATLB_ACCESS:
		case INT_DMATLB_MISS_DWNCL:
		case INT_DMATLB_ACCESS_DWNCL:
			async = &current->thread.dma_async_tlb;
			break;
#endif
		default:
			async = NULL;
		}
		if (async) {

			/*
			 * No vmalloc check required, so we can allow
			 * interrupts immediately at this point.
			 */
			local_irq_enable();

			set_thread_flag(TIF_ASYNC_TLB);
			if (async->fault_num != 0) {
				panic("Second async fault %d;"
				      " old fault was %d (%#lx/%ld)",
				      fault_num, async->fault_num,
				      address, write);
			}
			BUG_ON(fault_num == 0);
			async->fault_num = fault_num;
			async->is_fault = is_page_fault;
			async->is_write = write;
			async->address = address;
			return;
		}
	}
#endif

	handle_page_fault(regs, fault_num, is_page_fault, address, write);
}
Exemple #21
0
/*
 * We give a *copy* of the faultinfo in the regs to segv.
 * This must be done, since nesting SEGVs could overwrite
 * the info in the regs. A pointer to the info then would
 * give us bad data!
 */
unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,
                   struct uml_pt_regs *regs)
{
    struct siginfo si;
    jmp_buf *catcher;
    int err;
    int is_write = FAULT_WRITE(fi);
    unsigned long address = FAULT_ADDRESS(fi);

    if (!is_user && (address >= start_vm) && (address < end_vm)) {
        flush_tlb_kernel_vm();
        return 0;
    }
    else if (current->mm == NULL) {
        show_regs(container_of(regs, struct pt_regs, regs));
        panic("Segfault with no mm");
    }

    if (SEGV_IS_FIXABLE(&fi) || SEGV_MAYBE_FIXABLE(&fi))
        err = handle_page_fault(address, ip, is_write, is_user,
                                &si.si_code);
    else {
        err = -EFAULT;
        /*
         * A thread accessed NULL, we get a fault, but CR2 is invalid.
         * This code is used in __do_copy_from_user() of TT mode.
         * XXX tt mode is gone, so maybe this isn't needed any more
         */
        address = 0;
    }

    catcher = current->thread.fault_catcher;
    if (!err)
        return 0;
    else if (catcher != NULL) {
        current->thread.fault_addr = (void *) address;
        UML_LONGJMP(catcher, 1);
    }
    else if (current->thread.fault_addr != NULL)
        panic("fault_addr set but no fault catcher");
    else if (!is_user && arch_fixup(ip, regs))
        return 0;

    if (!is_user) {
        show_regs(container_of(regs, struct pt_regs, regs));
        panic("Kernel mode fault at addr 0x%lx, ip 0x%lx",
              address, ip);
    }

    if (err == -EACCES) {
        si.si_signo = SIGBUS;
        si.si_errno = 0;
        si.si_code = BUS_ADRERR;
        si.si_addr = (void __user *)address;
        current->thread.arch.faultinfo = fi;
        force_sig_info(SIGBUS, &si, current);
    } else if (err == -ENOMEM) {
        printk(KERN_INFO "VM: killing process %s\n", current->comm);
        do_exit(SIGKILL);
    } else {
        BUG_ON(err != -EFAULT);
        si.si_signo = SIGSEGV;
        si.si_addr = (void __user *) address;
        current->thread.arch.faultinfo = fi;
        force_sig_info(SIGSEGV, &si, current);
    }
    return 0;
}
Exemple #22
0
void handle_fault_load(trapframe_t* tf)
{
  tf->badvaddr = read_csr(sbadaddr);
  if (handle_page_fault(tf->badvaddr, PROT_READ) != 0)
    segfault(tf, tf->badvaddr, "load");
}