Esempio n. 1
0
/*
 * Set that machine state for performing an upcall that starts
 * the entry function with the given argument.
 */
void
cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg,
	stack_t *stack)
{
	struct trapframe *tf = td->td_frame;

	/* 32bits processes use r13 for sp */
	if (td->td_frame->tf_spsr & PSR_M_32)
		tf->tf_x[13] = STACKALIGN((uintptr_t)stack->ss_sp + stack->ss_size);
	else
		tf->tf_sp = STACKALIGN((uintptr_t)stack->ss_sp + stack->ss_size);
	tf->tf_elr = (register_t)entry;
	tf->tf_x[0] = (register_t)arg;
}
Esempio n. 2
0
File: mmu.c Progetto: Shamar/harvey
void
mmurelease(Proc* proc)
{
    Page *page, *next;

    mmuptpfree(proc, 0);

    for(page = proc->MMU.mmuptp[0]; page != nil; page = next) {
        next = page->next;
        if(--page->ref)
            panic("mmurelease: page->ref %d\n", page->ref);
        lock(&mmuptpfreelist.l);
        page->next = mmuptpfreelist.next;
        mmuptpfreelist.next = page;
        mmuptpfreelist.ref++;
        page->prev = nil;
        unlock(&mmuptpfreelist.l);
    }
    if(proc->MMU.mmuptp[0] && pga.rend.l.p)
        wakeup(&pga.rend);
    proc->MMU.mmuptp[0] = nil;

    tssrsp0(machp(), STACKALIGN(machp()->stack+MACHSTKSZ));
    cr3put(machp()->MMU.pml4->pa);
}
Esempio n. 3
0
File: mmu.c Progetto: Shamar/harvey
void
mmuswitch(Proc* proc)
{
    PTE *pte;
    Page *page;
    Mpl pl;

    pl = splhi();
    if(proc->newtlb) {
        /*
         * NIX: We cannot clear our page tables if they are going to
         * be used in the AC
         */
        if(proc->ac == nil)
            mmuptpfree(proc, 1);
        proc->newtlb = 0;
    }

    if(machp()->MMU.pml4->daddr) {
        memset(UINT2PTR(machp()->MMU.pml4->va), 0, machp()->MMU.pml4->daddr*sizeof(PTE));
        machp()->MMU.pml4->daddr = 0;
    }

    pte = UINT2PTR(machp()->MMU.pml4->va);
    for(page = proc->MMU.mmuptp[3]; page != nil; page = page->next) {
        pte[page->daddr] = PPN(page->pa)|PteU|PteRW|PteP;
        if(page->daddr >= machp()->MMU.pml4->daddr)
            machp()->MMU.pml4->daddr = page->daddr+1;
        page->prev = machp()->MMU.pml4;
    }

    tssrsp0(machp(), STACKALIGN(PTR2UINT(proc->kstack+KSTACK)));
    cr3put(machp()->MMU.pml4->pa);
    splx(pl);
}
Esempio n. 4
0
uintptr_t
sysexecstack(uintptr_t stack, int argc)
{
	uintptr_t sp;
	/*
	 * Given a current bottom-of-stack and a count
	 * of pointer arguments to be pushed onto it followed
	 * by an integer argument count, return a suitably
	 * aligned new bottom-of-stack which will satisfy any
	 * hardware stack-alignment contraints.
	 * Rounding the stack down to be aligned with the
	 * natural size of a pointer variable usually suffices,
	 * but some architectures impose further restrictions,
	 * e.g. 32-bit SPARC, where the stack must be 8-byte
	 * aligned although pointers and integers are 32-bits.
	 */
	USED(argc);

	sp = STACKALIGN(stack);
	/* but we need to align the stack to 16 bytes, not 8, once
	 * nil
	 * argv
	 * argc
	 * are pushed. So if we have odd arguments, we need an odd-8-byte
	 * aligned stack; else, an even aligned stack.
	 */
	if (argc & 1)
		sp -= sp & 8 ? 0 : 8;
	else
		sp -= sp & 8 ? 8 : 0;
	//print("For %d args, sp is now %p\n", argc, sp);
	return sp;
}
Esempio n. 5
0
static void
bootargs(uintptr base)
{
	int i;
	ulong ssize;
	char **av, *p;

	/*
	 * Push the boot args onto the stack.
	 * The initial value of the user stack must be such
	 * that the total used is larger than the maximum size
	 * of the argument list checked in syscall.
	 */
	i = oargblen+1;
	p = UINT2PTR(STACKALIGN(base + BY2PG - sizeof(Tos) - i));
	memmove(p, oargb, i);

	/*
	 * Now push the argv pointers.
	 * The code jumped to by touser in lproc.s expects arguments
	 *	main(char* argv0, ...)
	 * and calls
	 * 	startboot("/boot/boot", &argv0)
	 * not the usual (int argc, char* argv[])
	 */
	av = (char**)(p - (oargc+1)*sizeof(char*));
	ssize = base + BY2PG - PTR2UINT(av);
	for(i = 0; i < oargc; i++)
		*av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BY2PG);
	*av = nil;
	sp = USTKTOP - ssize;
}
Esempio n. 6
0
File: main.c Progetto: 99years/plan9
void
bootargs(uintptr base)
{
	int i;
	ulong ssize;
	char **av, *p;

	/*
	 * Push the boot args onto the stack.
	 * Make sure the validaddr check in syscall won't fail
	 * because there are fewer than the maximum number of
	 * args by subtracting sizeof(up->arg).
	 */
	i = oargblen+1;
	p = UINT2PTR(STACKALIGN(base + BIGPGSZ - sizeof(up->arg) - i));
	memmove(p, oargb, i);

	/*
	 * Now push argc and the argv pointers.
	 * This isn't strictly correct as the code jumped to by
	 * touser in init9.[cs] calls startboot (port/initcode.c) which
	 * expects arguments
	 * 	startboot(char* argv0, char* argv[])
	 * not the usual (int argc, char* argv[]), but argv0 is
	 * unused so it doesn't matter (at the moment...).
	 */
	av = (char**)(p - (oargc+2)*sizeof(char*));
	ssize = base + BIGPGSZ - PTR2UINT(av);
	*av++ = (char*)oargc;
	for(i = 0; i < oargc; i++)
		*av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BIGPGSZ);
	*av = nil;

	sp = USTKTOP - ssize;
}
Esempio n. 7
0
void
cpu_thread_alloc(struct thread *td)
{

	td->td_pcb = (struct pcb *)(td->td_kstack +
	    td->td_kstack_pages * PAGE_SIZE) - 1;
	td->td_frame = (struct trapframe *)STACKALIGN(
	    (caddr_t)td->td_pcb - 8 - sizeof(struct trapframe));
}
Esempio n. 8
0
void
cpu_thread_alloc(struct thread *td)
{

	td->td_pcb = (struct pcb *)(td->td_kstack +
	    td->td_kstack_pages * PAGE_SIZE) - 1;
	td->td_frame = (struct trapframe *)STACKALIGN(
	    td->td_pcb - 1);
}
Esempio n. 9
0
/*
 * Set that machine state for performing an upcall that has to
 * be done in thread_userret() so that those upcalls generated
 * in thread_userret() itself can be done as well.
 */
void
cpu_set_upcall_kse(struct thread *td, void (*entry)(void *), void *arg,
	stack_t *stack)
{
	struct trapframe *tf = td->td_frame;

	tf->tf_sp = STACKALIGN(stack->ss_sp + stack->ss_size);
	tf->tf_elr = (register_t)entry;
	tf->tf_x[0] = (register_t)arg;
}
Esempio n. 10
0
/*
 * Set that machine state for performing an upcall that has to
 * be done in thread_userret() so that those upcalls generated
 * in thread_userret() itself can be done as well.
 */
void
cpu_set_upcall_kse(struct thread *td, void (*entry)(void *), void *arg,
	stack_t *stack)
{
	struct trapframe *tf = td->td_frame;

	tf->tf_usr_sp = STACKALIGN((int)stack->ss_sp + stack->ss_size);
	tf->tf_pc = (int)entry;
	tf->tf_r0 = (int)arg;
	tf->tf_spsr = PSR_USR32_MODE;
}
Esempio n. 11
0
/*
 * Set that machine state for performing an upcall that starts
 * the entry function with the given argument.
 */
void
cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg,
	stack_t *stack)
{
	struct trapframe *tf;

	tf = td->td_frame;

	tf->tf_sp = STACKALIGN((uintptr_t)stack->ss_sp + stack->ss_size);
	tf->tf_sepc = (register_t)entry;
	tf->tf_a[0] = (register_t)arg;
}
Esempio n. 12
0
/*
 * Finish a fork operation, with process p2 nearly set up.
 * Copy and update the pcb, set up the stack so that the child
 * ready to run and return to user mode.
 */
void
cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags)
{
	struct pcb *pcb2;
	struct trapframe *tf;

	if ((flags & RFPROC) == 0)
		return;

	if (td1 == curthread) {
		/*
		 * Save the tpidr_el0 and the vfp state, these normally happen
		 * in cpu_switch, but if userland changes these then forks
		 * this may not have happened.
		 */
		td1->td_pcb->pcb_tpidr_el0 = READ_SPECIALREG(tpidr_el0);
		td1->td_pcb->pcb_tpidrro_el0 = READ_SPECIALREG(tpidrro_el0);
#ifdef VFP
		if ((td1->td_pcb->pcb_fpflags & PCB_FP_STARTED) != 0)
			vfp_save_state(td1, td1->td_pcb);
#endif
	}

	pcb2 = (struct pcb *)(td2->td_kstack +
	    td2->td_kstack_pages * PAGE_SIZE) - 1;

	td2->td_pcb = pcb2;
	bcopy(td1->td_pcb, pcb2, sizeof(*pcb2));

	td2->td_proc->p_md.md_l0addr =
	    vtophys(vmspace_pmap(td2->td_proc->p_vmspace)->pm_l0);

	tf = (struct trapframe *)STACKALIGN((struct trapframe *)pcb2 - 1);
	bcopy(td1->td_frame, tf, sizeof(*tf));
	tf->tf_x[0] = 0;
	tf->tf_x[1] = 0;
	tf->tf_spsr = td1->td_frame->tf_spsr & PSR_M_32;

	td2->td_frame = tf;

	/* Set the return value registers for fork() */
	td2->td_pcb->pcb_x[8] = (uintptr_t)fork_return;
	td2->td_pcb->pcb_x[9] = (uintptr_t)td2;
	td2->td_pcb->pcb_x[PCB_LR] = (uintptr_t)fork_trampoline;
	td2->td_pcb->pcb_sp = (uintptr_t)td2->td_frame;
	td2->td_pcb->pcb_fpusaved = &td2->td_pcb->pcb_fpustate;
	td2->td_pcb->pcb_vfpcpu = UINT_MAX;

	/* Setup to release spin count in fork_exit(). */
	td2->td_md.md_spinlock_count = 1;
	td2->td_md.md_saved_daif = td1->td_md.md_saved_daif & ~DAIF_I_MASKED;
}
Esempio n. 13
0
/*
 * Finish a fork operation, with process p2 nearly set up.
 * Copy and update the pcb, set up the stack so that the child
 * ready to run and return to user mode.
 */
void
cpu_fork(register struct thread *td1, register struct proc *p2,
         struct thread *td2, int flags)
{
    struct pcb *pcb2;
    struct trapframe *tf;
    struct switchframe *sf;
    struct mdproc *mdp2;

    if ((flags & RFPROC) == 0)
        return;
    pcb2 = (struct pcb *)(td2->td_kstack + td2->td_kstack_pages * PAGE_SIZE) - 1;
#ifdef __XSCALE__
#ifndef CPU_XSCALE_CORE3
    pmap_use_minicache(td2->td_kstack, td2->td_kstack_pages * PAGE_SIZE);
#endif
#endif
    td2->td_pcb = pcb2;
    bcopy(td1->td_pcb, pcb2, sizeof(*pcb2));
    mdp2 = &p2->p_md;
    bcopy(&td1->td_proc->p_md, mdp2, sizeof(*mdp2));
    pcb2->un_32.pcb32_sp = td2->td_kstack +
                           USPACE_SVC_STACK_TOP - sizeof(*pcb2);
    pcb2->pcb_vfpcpu = -1;
    pcb2->pcb_vfpstate.fpscr = VFPSCR_DN | VFPSCR_FZ;
    pmap_activate(td2);
    td2->td_frame = tf = (struct trapframe *)STACKALIGN(
                             pcb2->un_32.pcb32_sp - sizeof(struct trapframe));
    *tf = *td1->td_frame;
    sf = (struct switchframe *)tf - 1;
    sf->sf_r4 = (u_int)fork_return;
    sf->sf_r5 = (u_int)td2;
    sf->sf_pc = (u_int)fork_trampoline;
    tf->tf_spsr &= ~PSR_C_bit;
    tf->tf_r0 = 0;
    tf->tf_r1 = 0;
    pcb2->un_32.pcb32_sp = (u_int)sf;
    KASSERT((pcb2->un_32.pcb32_sp & 7) == 0,
            ("cpu_fork: Incorrect stack alignment"));

    /* Setup to release spin count in fork_exit(). */
    td2->td_md.md_spinlock_count = 1;
    td2->td_md.md_saved_cspr = 0;
#ifdef ARM_TP_ADDRESS
    td2->td_md.md_tp = *(register_t *)ARM_TP_ADDRESS;
#else
    td2->td_md.md_tp = (register_t) get_tls();
#endif
}
Esempio n. 14
0
void
kprocchild(Proc* p, void (*func)(void*), void* arg)
{
	/*
	 * gotolabel() needs a word on the stack in
	 * which to place the return PC used to jump
	 * to linkproc().
	 */
	p->sched.pc = PTR2UINT(linkproc);
	p->sched.sp = PTR2UINT(p->kstack+KSTACK-BY2SE);
	p->sched.sp = STACKALIGN(p->sched.sp);

	p->kpfun = func;
	p->kparg = arg;
}
Esempio n. 15
0
/*
 * Initialize machine state (pcb and trap frame) for a new thread about to
 * upcall. Put enough state in the new thread's PCB to get it to go back
 * userret(), where we can intercept it again to set the return (upcall)
 * Address and stack, along with those from upcals that are from other sources
 * such as those generated in thread_userret() itself.
 */
void
cpu_set_upcall(struct thread *td, struct thread *td0)
{

	bcopy(td0->td_frame, td->td_frame, sizeof(struct trapframe));
	bcopy(td0->td_pcb, td->td_pcb, sizeof(struct pcb));

	td->td_pcb->pcb_regs.sf_r4 = (register_t)fork_return;
	td->td_pcb->pcb_regs.sf_r5 = (register_t)td;
	td->td_pcb->pcb_regs.sf_lr = (register_t)fork_trampoline;
	td->td_pcb->pcb_regs.sf_sp = STACKALIGN(td->td_frame);

	td->td_frame->tf_spsr &= ~PSR_C;
	td->td_frame->tf_r0 = 0;

	/* Setup to release spin count in fork_exit(). */
	td->td_md.md_spinlock_count = 1;
	td->td_md.md_saved_cspr = PSR_SVC32_MODE;
}
Esempio n. 16
0
uintptr
sysexecstack(uintptr stack, int argc)
{
	/*
	 * Given a current bottom-of-stack and a count
	 * of pointer arguments to be pushed onto it followed
	 * by an integer argument count, return a suitably
	 * aligned new bottom-of-stack which will satisfy any
	 * hardware stack-alignment contraints.
	 * Rounding the stack down to be aligned with the
	 * natural size of a pointer variable usually suffices,
	 * but some architectures impose further restrictions,
	 * e.g. 32-bit SPARC, where the stack must be 8-byte
	 * aligned although pointers and integers are 32-bits.
	 */
	USED(argc);

	return STACKALIGN(stack);
}
Esempio n. 17
0
void
exec_setregs(struct thread *td, struct image_params *imgp, u_long stack)
{
	struct trapframe *tf;

	tf = td->td_frame;

	memset(tf, 0, sizeof(struct trapframe));

	/*
	 * We need to set a0 for init as it doesn't call
	 * cpu_set_syscall_retval to copy the value. We also
	 * need to set td_retval for the cases where we do.
	 */
	tf->tf_a[0] = td->td_retval[0] = stack;
	tf->tf_sp = STACKALIGN(stack);
	tf->tf_ra = imgp->entry_addr;
	tf->tf_sepc = imgp->entry_addr;
}
Esempio n. 18
0
/*
 * Finish a fork operation, with process p2 nearly set up.
 * Copy and update the pcb, set up the stack so that the child
 * ready to run and return to user mode.
 */
void
cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags)
{
	struct pcb *pcb2;
	struct trapframe *tf;

	if ((flags & RFPROC) == 0)
		return;

	pcb2 = (struct pcb *)(td2->td_kstack +
	    td2->td_kstack_pages * PAGE_SIZE) - 1;

	td2->td_pcb = pcb2;
	bcopy(td1->td_pcb, pcb2, sizeof(*pcb2));

	td2->td_pcb->pcb_l1addr =
	    vtophys(vmspace_pmap(td2->td_proc->p_vmspace)->pm_l1);

	tf = (struct trapframe *)STACKALIGN((struct trapframe *)pcb2 - 1);
	bcopy(td1->td_frame, tf, sizeof(*tf));

	/* Clear syscall error flag */
	tf->tf_t[0] = 0;

	/* Arguments for child */
	tf->tf_a[0] = 0;
	tf->tf_a[1] = 0;
	tf->tf_sstatus |= (SSTATUS_SPIE); /* Enable interrupts. */
	tf->tf_sstatus |= (SSTATUS_SUM); /* Supervisor can access userspace. */
	tf->tf_sstatus &= ~(SSTATUS_SPP); /* User mode. */

	td2->td_frame = tf;

	/* Set the return value registers for fork() */
	td2->td_pcb->pcb_s[0] = (uintptr_t)fork_return;
	td2->td_pcb->pcb_s[1] = (uintptr_t)td2;
	td2->td_pcb->pcb_ra = (uintptr_t)fork_trampoline;
	td2->td_pcb->pcb_sp = (uintptr_t)td2->td_frame;

	/* Setup to release spin count in fork_exit(). */
	td2->td_md.md_spinlock_count = 1;
	td2->td_md.md_saved_sstatus_ie = (SSTATUS_SIE);
}
Esempio n. 19
0
void
cpu_thread_alloc(struct thread *td)
{
	td->td_pcb = (struct pcb *)(td->td_kstack + td->td_kstack_pages *
	    PAGE_SIZE) - 1;
	/*
	 * Ensure td_frame is aligned to an 8 byte boundary as it will be
	 * placed into the stack pointer which must be 8 byte aligned in
	 * the ARM EABI.
	 */
	td->td_frame = (struct trapframe *)STACKALIGN((u_int)td->td_kstack +
	    USPACE_SVC_STACK_TOP - sizeof(struct pcb) -
	    sizeof(struct trapframe));
#ifdef __XSCALE__
#ifndef CPU_XSCALE_CORE3
	pmap_use_minicache(td->td_kstack, td->td_kstack_pages * PAGE_SIZE);
#endif
#endif
}
Esempio n. 20
0
static void
bootargs(uintptr base)
{
	int i;
	ulong ssize;
	char **av, *p;

	/*
	 * Push the boot args onto the stack.
	 * The initial value of the user stack must be such
	 * that the total used is larger than the maximum size
	 * of the argument list checked in syscall.
	 */
	i = oargblen+1;
	p = UINT2PTR(STACKALIGN(base + BY2PG - Ustkheadroom - i));
	memmove(p, oargb, i);

	/*
	 * Now push argc and the argv pointers.
	 * This isn't strictly correct as the code jumped to by
	 * touser in init9.s calls startboot (port/initcode.c) which
	 * expects arguments
	 * 	startboot(char *argv0, char **argv)
	 * not the usual (int argc, char* argv[]), but argv0 is
	 * unused so it doesn't matter (at the moment...).
	 */
	av = (char**)(p - (oargc+2)*sizeof(char*));
	ssize = base + BY2PG - PTR2UINT(av);
	*av++ = (char*)oargc;
	for(i = 0; i < oargc; i++)
		*av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BY2PG);
	*av = nil;

	/*
	 * Leave space for the return PC of the
	 * caller of initcode.
	 */
	sp = USTKTOP - ssize - sizeof(void*);
}
Esempio n. 21
0
File: main.c Progetto: 99years/plan9
void
userinit(void)
{
	Proc *p;
	Segment *s;
	KMap *k;
	Page *pg;

	p = newproc();
	p->pgrp = newpgrp();
	p->egrp = smalloc(sizeof(Egrp));
	p->egrp->ref = 1;
	p->fgrp = dupfgrp(nil);
	p->rgrp = newrgrp();
	p->procmode = 0640;

	kstrdup(&eve, "");
	kstrdup(&p->text, "*init*");
	kstrdup(&p->user, eve);

	/*
	 * Kernel Stack
	 *
	 * N.B. make sure there's enough space for syscall to check
	 *	for valid args and
	 *	space for gotolabel's return PC
	 * AMD64 stack must be quad-aligned.
	 */
	p->sched.pc = PTR2UINT(init0);
	p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(up->arg)-sizeof(uintptr));
	p->sched.sp = STACKALIGN(p->sched.sp);

	/*
	 * User Stack
	 *
	 * Technically, newpage can't be called here because it
	 * should only be called when in a user context as it may
	 * try to sleep if there are no pages available, but that
	 * shouldn't be the case here.
	 */
	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BIGPGSZ);
	p->seg[SSEG] = s;

	pg = newpage(1, 0, USTKTOP-BIGPGSZ, BIGPGSZ, -1);
	segpage(s, pg);
	k = kmap(pg);
	bootargs(VA(k));
	kunmap(k);

	/*
	 * Text
	 */
	s = newseg(SG_TEXT, UTZERO, 1);
	s->flushme++;
	p->seg[TSEG] = s;
	pg = newpage(1, 0, UTZERO, BIGPGSZ, -1);
	memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
	segpage(s, pg);
	k = kmap(s->map[0]->pages[0]);
	memmove(UINT2PTR(VA(k)), initcode, sizeof initcode);
	kunmap(k);

	ready(p);
}
Esempio n. 22
0
void
userinit(void)
{
	Mach *m = machp();
	Proc *p;
	Segment *s;
	KMap *k;
	Page *pg;
	int sno;

	p = newproc();
	p->pgrp = newpgrp();
	p->egrp = smalloc(sizeof(Egrp));
	p->egrp->ref = 1;
	p->fgrp = dupfgrp(nil);
	p->rgrp = newrgrp();
	p->procmode = 0640;

	kstrdup(&eve, "");
	kstrdup(&p->text, "*init*");
	kstrdup(&p->user, eve);

	/*
	 * Kernel Stack
	 *
	 * N.B. make sure there's enough space for syscall to check
	 *	for valid args and
	 *	space for gotolabel's return PC
	 * AMD64 stack must be quad-aligned.
	 */
	p->sched.pc = PTR2UINT(init0);
	p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(m->externup->arg)-sizeof(uintptr_t));
	p->sched.sp = STACKALIGN(p->sched.sp);

	/*
	 * User Stack
	 *
	 * Technically, newpage can't be called here because it
	 * should only be called when in a user context as it may
	 * try to sleep if there are no pages available, but that
	 * shouldn't be the case here.
	 */
	sno = 0;
	s = newseg(SG_STACK|SG_READ|SG_WRITE, USTKTOP-USTKSIZE, USTKSIZE/ BIGPGSZ);
	p->seg[sno++] = s;
	pg = newpage(1, 0, USTKTOP-BIGPGSZ, BIGPGSZ, -1);
	segpage(s, pg);
	k = kmap(pg);
	bootargs(VA(k));
	kunmap(k);

	/*
	 * Text
	 */
	s = newseg(SG_TEXT|SG_READ|SG_EXEC, UTZERO, 1);
	s->flushme++;
	p->seg[sno++] = s;
	pg = newpage(1, 0, UTZERO, BIGPGSZ, -1);
	memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
	segpage(s, pg);
	k = kmap(s->map[0]->pages[0]);
	/* UTZERO is only needed until we make init not have 2M block of zeros at the front. */
	memmove(UINT2PTR(VA(k) + init_code_start - UTZERO), init_code_out, sizeof(init_code_out));
	kunmap(k);

	/*
	 * Data
	 */
	s = newseg(SG_DATA|SG_READ|SG_WRITE, UTZERO + BIGPGSZ, 1);
	s->flushme++;
	p->seg[sno++] = s;
	pg = newpage(1, 0, UTZERO + BIGPGSZ, BIGPGSZ, -1);
	memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
	segpage(s, pg);
	k = kmap(s->map[0]->pages[0]);
	/* This depends on init having a text segment < 2M. */
	memmove(UINT2PTR(VA(k) + init_data_start - (UTZERO + BIGPGSZ)), init_data_out, sizeof(init_data_out));
	kunmap(k);
	ready(p);
}
Esempio n. 23
0
/*
 * Finish a fork operation, with process p2 nearly set up.
 * Copy and update the pcb, set up the stack so that the child
 * ready to run and return to user mode.
 */
void
cpu_fork(register struct thread *td1, register struct proc *p2,
    struct thread *td2, int flags)
{
	struct pcb *pcb2;
	struct trapframe *tf;
	struct mdproc *mdp2;

	if ((flags & RFPROC) == 0)
		return;

	/* Point the pcb to the top of the stack */
	pcb2 = (struct pcb *)
	    (td2->td_kstack + td2->td_kstack_pages * PAGE_SIZE) - 1;
#ifdef __XSCALE__
#ifndef CPU_XSCALE_CORE3
	pmap_use_minicache(td2->td_kstack, td2->td_kstack_pages * PAGE_SIZE);
#endif
#endif
	td2->td_pcb = pcb2;
	
	/* Clone td1's pcb */
	bcopy(td1->td_pcb, pcb2, sizeof(*pcb2));
	
	/* Point to mdproc and then copy over td1's contents */
	mdp2 = &p2->p_md;
	bcopy(&td1->td_proc->p_md, mdp2, sizeof(*mdp2));

	/* Point the frame to the stack in front of pcb and copy td1's frame */
	td2->td_frame = (struct trapframe *)pcb2 - 1;
	*td2->td_frame = *td1->td_frame;

	/*
	 * Create a new fresh stack for the new process.
	 * Copy the trap frame for the return to user mode as if from a
	 * syscall.  This copies most of the user mode register values.
	 */
	pmap_set_pcb_pagedir(vmspace_pmap(p2->p_vmspace), pcb2);
	pcb2->pcb_regs.sf_r4 = (register_t)fork_return;
	pcb2->pcb_regs.sf_r5 = (register_t)td2;
	pcb2->pcb_regs.sf_lr = (register_t)fork_trampoline;
	pcb2->pcb_regs.sf_sp = STACKALIGN(td2->td_frame);

	pcb2->pcb_vfpcpu = -1;
	pcb2->pcb_vfpstate.fpscr = VFPSCR_DN | VFPSCR_FZ;
	
	tf = td2->td_frame;
	tf->tf_spsr &= ~PSR_C;
	tf->tf_r0 = 0;
	tf->tf_r1 = 0;


	/* Setup to release spin count in fork_exit(). */
	td2->td_md.md_spinlock_count = 1;
	td2->td_md.md_saved_cspr = PSR_SVC32_MODE;;
#ifdef ARM_TP_ADDRESS
	td2->td_md.md_tp = *(register_t *)ARM_TP_ADDRESS;
#else
	td2->td_md.md_tp = td1->td_md.md_tp;
#endif
}
Esempio n. 24
0
void
sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
{
	struct thread *td;
	struct proc *p;
	struct trapframe *tf;
	struct sigframe *fp, frame;
	struct sigacts *psp;
	int code, onstack, sig;

	td = curthread;
	p = td->td_proc;
	PROC_LOCK_ASSERT(p, MA_OWNED);

	sig = ksi->ksi_signo;
	code = ksi->ksi_code;
	psp = p->p_sigacts;
	mtx_assert(&psp->ps_mtx, MA_OWNED);

	tf = td->td_frame;
	onstack = sigonstack(tf->tf_sp);

	CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm,
	    catcher, sig);

	/* Allocate and validate space for the signal handler context. */
	if ((td->td_pflags & TDP_ALTSTACK) != 0 && !onstack &&
	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
		fp = (struct sigframe *)(td->td_sigstk.ss_sp +
		    td->td_sigstk.ss_size);
#if defined(COMPAT_43)
		td->td_sigstk.ss_flags |= SS_ONSTACK;
#endif
	} else {
		fp = (struct sigframe *)td->td_frame->tf_sp;
	}

	/* Make room, keeping the stack aligned */
	fp--;
	fp = (struct sigframe *)STACKALIGN(fp);

	/* Fill in the frame to copy out */
	get_mcontext(td, &frame.sf_uc.uc_mcontext, 0);
	get_fpcontext(td, &frame.sf_uc.uc_mcontext);
	frame.sf_si = ksi->ksi_info;
	frame.sf_uc.uc_sigmask = *mask;
	frame.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) ?
	    ((onstack) ? SS_ONSTACK : 0) : SS_DISABLE;
	frame.sf_uc.uc_stack = td->td_sigstk;
	mtx_unlock(&psp->ps_mtx);
	PROC_UNLOCK(td->td_proc);

	/* Copy the sigframe out to the user's stack. */
	if (copyout(&frame, fp, sizeof(*fp)) != 0) {
		/* Process has trashed its stack. Kill it. */
		CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp);
		PROC_LOCK(p);
		sigexit(td, SIGILL);
	}

	tf->tf_x[0]= sig;
	tf->tf_x[1] = (register_t)&fp->sf_si;
	tf->tf_x[2] = (register_t)&fp->sf_uc;

	tf->tf_elr = (register_t)catcher;
	tf->tf_sp = (register_t)fp;
	tf->tf_lr = (register_t)(PS_STRINGS - *(p->p_sysent->sv_szsigcode));

	CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_elr,
	    tf->tf_sp);

	PROC_LOCK(p);
	mtx_lock(&psp->ps_mtx);
}
Esempio n. 25
0
/*
 * Send an interrupt to process.
 *
 * Stack is set up to allow sigcode stored
 * in u. to call routine, followed by kcall
 * to sigreturn routine below.  After sigreturn
 * resets the signal mask, the stack, and the
 * frame pointer, it returns to the user specified pc.
 */
void
sendsig(sig_t catcher, int sig, int returnmask, u_long code, int type,
   union sigval val)
{
	struct proc *p = curproc;
	struct trapframe *tf;
	struct sigframe *fp, frame;
	struct sigacts *psp = p->p_sigacts;
	int oonstack = psp->ps_sigstk.ss_flags & SS_ONSTACK;
	int onstack = 0;

	tf = process_frame(p);

	/* Do we need to jump onto the signal stack? */

	/* Allocate space for the signal handler context. */
	if ((psp->ps_flags & SAS_ALTSTACK) && !oonstack &&
	    (psp->ps_sigonstack & sigmask(sig))) {
		onstack = 1;
		fp = (struct sigframe *)((caddr_t)psp->ps_sigstk.ss_sp +
		    psp->ps_sigstk.ss_size);
	} else
		fp = (struct sigframe *)tf->tf_usr_sp;
	/* make room on the stack */
	fp--;

	/* make the stack aligned */
	fp = (void *)STACKALIGN(fp);

	/* Build stack frame for signal trampoline. */
	frame.sf_signum = sig;
	frame.sf_sip = NULL;
	frame.sf_scp = &fp->sf_sc;
	frame.sf_handler = catcher;

	/* Save register context. */
	frame.sf_sc.sc_r0     = tf->tf_r0;
	frame.sf_sc.sc_r1     = tf->tf_r1;
	frame.sf_sc.sc_r2     = tf->tf_r2;
	frame.sf_sc.sc_r3     = tf->tf_r3;
	frame.sf_sc.sc_r4     = tf->tf_r4;
	frame.sf_sc.sc_r5     = tf->tf_r5;
	frame.sf_sc.sc_r6     = tf->tf_r6;
	frame.sf_sc.sc_r7     = tf->tf_r7;
	frame.sf_sc.sc_r8     = tf->tf_r8;
	frame.sf_sc.sc_r9     = tf->tf_r9;
	frame.sf_sc.sc_r10    = tf->tf_r10;
	frame.sf_sc.sc_r11    = tf->tf_r11;
	frame.sf_sc.sc_r12    = tf->tf_r12;
	frame.sf_sc.sc_usr_sp = tf->tf_usr_sp;
	frame.sf_sc.sc_usr_lr = tf->tf_usr_lr;
	frame.sf_sc.sc_svc_lr = tf->tf_svc_lr;
	frame.sf_sc.sc_pc     = tf->tf_pc;
	frame.sf_sc.sc_spsr   = tf->tf_spsr;

	/* Save signal stack. */
	frame.sf_sc.sc_onstack = psp->ps_sigstk.ss_flags & SS_ONSTACK;

	/* Save signal mask. */
	frame.sf_sc.sc_mask = returnmask;

	if (psp->ps_siginfo & sigmask(sig)) {
		frame.sf_sip = &fp->sf_si;
		initsiginfo(&frame.sf_si, sig, code, type, val);
	}

	if (copyout(&frame, fp, sizeof(frame)) != 0) {
		/*
		 * Process has trashed its stack; give it an illegal
		 * instruction to halt it in its tracks.
		 */
		sigexit(p, SIGILL);
		/* NOTREACHED */
	}

	/*
	 * Build context to run handler in.  We invoke the handler
	 * directly, only returning via the trampoline.  Note the
	 * trampoline version numbers are coordinated with machine-
	 * dependent code in libc.
	 */

	/*
	 * this was all in the switch below, seemed daft to duplicate it, if
	 * we do a new trampoline version it might change then
	 */
	tf->tf_r0 = sig;
	tf->tf_r1 = (int)frame.sf_sip;
	tf->tf_r2 = (int)frame.sf_scp;
	tf->tf_pc = (int)frame.sf_handler;
	tf->tf_usr_sp = (int)fp;
	
	tf->tf_usr_lr = (int)p->p_sigcode;
	/* XXX This should not be needed. */
	cpu_icache_sync_all();

	/* Remember that we're now on the signal stack. */
	if (onstack)
		psp->ps_sigstk.ss_flags |= SS_ONSTACK;
}
Esempio n. 26
0
/*
 *  create the first process
 */
void
userinit(void)
{
	Proc *p;
	Segment *s;
	KMap *k;
	Page *pg;

	/* no processes yet */
	up = nil;

	p = newproc();
	p->pgrp = newpgrp();
	p->egrp = smalloc(sizeof(Egrp));
	p->egrp->ref = 1;
	p->fgrp = dupfgrp(nil);
	p->rgrp = newrgrp();
	p->procmode = 0640;

	kstrdup(&eve, "");
	kstrdup(&p->text, "*init*");
	kstrdup(&p->user, eve);

	/*
	 * Kernel Stack
	 */
	p->sched.pc = PTR2UINT(init0);
	p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(up->s.args)-sizeof(uintptr));
	p->sched.sp = STACKALIGN(p->sched.sp);

	/*
	 * User Stack
	 *
	 * Technically, newpage can't be called here because it
	 * should only be called when in a user context as it may
	 * try to sleep if there are no pages available, but that
	 * shouldn't be the case here.
	 */
	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
	p->seg[SSEG] = s;
	pg = newpage(1, 0, USTKTOP-BY2PG);
	segpage(s, pg);
	k = kmap(pg);
	bootargs(VA(k));
	kunmap(k);

	/*
	 * Text
	 */
	s = newseg(SG_TEXT, UTZERO, 1);
	s->flushme++;
	p->seg[TSEG] = s;
	pg = newpage(1, 0, UTZERO);
	memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
	segpage(s, pg);
	k = kmap(s->map[0]->pages[0]);
	memmove(UINT2PTR(VA(k)), initcode, sizeof initcode);
	kunmap(k);

	ready(p);
}
Esempio n. 27
0
void
kforkexecac(Proc *p, int core, char *ufile, char **argv)
{
	Mach *m = machp();
	Khdr hdr;
	Tos *tos;
	Chan *chan;
	int argc, i, n, sno;
	char *a, *elem, *file, *args;
	int32_t hdrsz, magic, textsz, datasz, bsssz;
	uintptr_t textlim, datalim, bsslim, entry, tbase, tsize, dbase, dsize, bbase, bsize, sbase, ssize, stack;
	Mach *mp;
	//	static Pgrp *kpgrp;

	panic("kexec not done\n");
	// XXX: since this is kernel code we can't do attachimage,
	// we should be reading the file into kernel memory.
	// this only matters if we are using ufile.
	// YYY: look at dev reboot for help.

	file = nil;
	elem = nil;
	chan = nil;
	mp = nil;

	USED(chan);

	if(waserror()){
		DBG("kforkexecac: failing: %s\n", m->externup->errstr);
		if(file)
			free(file);
		if(elem)
			free(elem);
		if(chan)
			cclose(chan);
		if(core > 0 && mp != nil)
			mp->proc = nil;
		if(core != 0)
			p->ac = nil;
		nexterror();
	}

	if(core != 0)
		p->ac = getac(p, core);

	argc = 0;
	if(ufile != nil){
		panic("ufile not implemented yet");
		file = validnamedup(ufile, 1);
		DBG("kforkexecac: up %#p file %s\n", m->externup, file);
		chan = namec(file, Aopen, OEXEC, 0);
		kstrdup(&elem, m->externup->genbuf);

		hdrsz = chan->dev->read(chan, &hdr, sizeof(Khdr), 0);
		DBG("wrote ufile\n");

		if(hdrsz < 2)
			error(Ebadexec);
	}else{
		/* somebody already wrote in our text segment */
		for(sno = 0; sno < NSEG; sno++)
			if(p->seg[sno] != nil)
				if((p->seg[sno]->type & SG_EXEC) != 0)
					break;
		if(sno == NSEG)
			error("kforkexecac: no text segment!");
		hdr = *(Khdr*)p->seg[sno]->base;
		hdrsz = sizeof(Khdr);
	}

//	p = (char*)&hdr;
	magic = l2be(hdr.magic);
	DBG("badexec3\n");

	if(hdrsz != sizeof(Khdr) || magic != AOUT_MAGIC)
		error(Ebadexec);
	if(magic & HDR_MAGIC){
		entry = vl2be(hdr.hdr[0]);
		hdrsz = sizeof(Khdr);
	}
	else{
		entry = l2be(hdr.entry);
		hdrsz = sizeof(Exec);
	}

	textsz = l2be(hdr.text);
	datasz = l2be(hdr.data);
	bsssz = l2be(hdr.bss);

	panic("aki broke it before it even got working.");
/* TODO(aki): figure out what to do with this.
	tbase = p->seg[TSEG]->base;
	tsize = tbase - p->seg[TSEG]->top;
	dbase = p->seg[DSEG]->base;
	dsize = dbase - p->seg[DSEG]->top;
	bbase = p->seg[BSEG]->base;
	bsize = bbase - p->seg[BSEG]->top;
	sbase = p->seg[SSEG]->base;
	ssize = sbase - p->seg[SSEG]->top;
*/

	// XXX: we are no longer contiguous.
	textlim = ROUNDUP(hdrsz+textsz, BIGPGSZ);
	// XXX: we are going to be at least two pages here.
	datalim = BIGPGROUND(datasz);
	bsslim = BIGPGROUND(datalim+bsssz);

	// XXX: this is pretty fragile
	memmove((void*)dbase, (void*)(entry+textsz), datasz);
	DBG("writing data dbase %#p tbase %#p textsz %ld datasz %ld\n", dbase, tbase, textsz, datasz);
//	memmove((void*)dbase, (void*)"testing data", 13);
	/*
	 * Check the binary header for consistency,
	 * e.g. the entry point is within the text segment and
	 * the segments don't overlap each other.
	 */
	// XXX: max instruction size on amd64 is 15 bytes provide a check for consistency.
	DBG("kexec: entry %#p tbase %#p hdrsz %ld  textsz %ld\n", entry, tbase, hdrsz, textsz);
	if(entry < tbase+hdrsz || entry >= tbase+hdrsz+textsz)
		error(Ebadexec);
	// XXX: what about the kernel stack we are making here?
	DBG("kexec: testing if sizes overflow limits\n");
	if(textsz >= textlim || datasz > datalim || bsssz > bsslim)
		error(Ebadexec);
	DBG("kexec: do the top of the segments overflow limits?\n");
	if(textlim >= tbase+tsize || datalim >= dbase+dsize || bsslim >= bbase+bsize)
		error(Ebadexec);

	DBG("kexec: is bss below data?\n");
	if(bsslim < datalim)
		error(Ebadexec);
	/*
	Interesting thought, the previously allocated segments for
	data and text are shared and constant.  The BSS and the stack
	are not.  What you really want is the ability to make an
	executable text and data and then create child executables on
	top of that.  This will lower external fragmentation and allow
	a bunch of communicating shared memory processes (ie.  go) in
	kernel space.

	Fundamentally this means that the allocation of the text and
	the data should be separate from the bss and the stack.  This
	will require that you change the linkers as well to allow the
	separation of data and bss sections.
	*/

	/*
	 * Stack is a pointer into the temporary stack
	 * segment, and will move as items are pushed.
	 */

	 // need to work something out here with the stack.
	stack = sbase+ssize-sizeof(Tos);


	 /*
	  * XXX: When we are linking this how do we set the tos? We will need to change trap right?
	  */
	tos = (Tos*)stack;
	tos->cyclefreq = m->cyclefreq;
	cycles((uint64_t*)&tos->pcycles);
	tos->pcycles = -tos->pcycles;
	tos->kcycles = tos->pcycles;
	tos->clock = 0;

	DBG("kexec: argument processing\n");
	if(0)
	for(i = 0;; i++, argv++){
		a = *(char**)validaddr(argv, sizeof(char**), 0);
		if(a == nil)
			break;
		a = validaddr(a, 1, 0);
		n = ((char*)vmemchr(a, 0, 0x7fffffff) - a) + 1;

		if(argc > 0 && i == 0)
			continue;

		stack -= n;
		if(stack < sbase+ssize-4096)
			error(Enovmem);
		args = UINT2PTR(stack);
		memmove(args, a, n);
		args[n-1] = 0;
		argc++;
	}
	// DBG("kexec: ensuring we have argc\n");
	if(0)
	if(argc < 1)
		error(Ebadexec);

	a = args = UINT2PTR(stack);
	stack = sysexecstack(stack, argc);
	// XXX: look through math on this. look at ../../9/port/ exec.c
	// YYY: this looks like a Jimism for 9k.
	// DBG("kexec: ensuring the stack \n");
	if(0)
	if(stack-(argc+1)*sizeof(char**)-BIGPGSZ < sbase+ssize-4096)
		error(Ebadexec);

	argv = (char**)stack;
	*--argv = nil;
	// XXX: replace USTKTOP with a new variable representing the top of stack.
	if(0)
	for(i = 0; i < argc; i++){
		*--argv = args + (USTKTOP-sbase+ssize);
		args += strlen(args) + 1;
	}

	DBG("argsing\n");
	n = args - a;
	if(0)
	if(n <= 0)
		error(Egreg);
	if(n > 128)
		n = 128;
	DBG("kexec: allocating args\n");
	// XXX: hangs in smalloc, not sure why.
//	args = smalloc(n);
//	if(waserror()){
//		DBG("erroring\n");
//		free(args);
//		nexterror();
//	}
//	DBG("kexec: moving args\n");
//	memmove(args, a, n);
//	if(0)
//	while(n > 0 && (args[n-1] & 0xc0) == 0x80)
//		n--;
//	args[n-1] = '\0';

	kstrdup(&p->text, "kexecproc");
	p->args = nil;
	//elem;
//	elem = nil;
//	p->args = args;
//	p->nargs = n;
	poperror();				/* p (m->externup->args) */





/*
	qlock(&p->debug);

	sysprocsetup(p);
	qunlock(&p->debug);
*/

	// why is this sched and not ureg?
	p->sched.pc = entry;
	// the real question here is how do you set up the stack?
	p->sched.sp = PTR2UINT(stack-BY2SE);
	p->sched.sp = STACKALIGN(p->sched.sp);


	// XXX: what does it imply if you have a kproc that runs on an ac?
	if(core > 0){
		DBG("kexec: coring %d\n", core);
		mp = p->ac;
		mp->icc->flushtlb = 1;
		mp->icc->rc = ICCOK;

		DBG("kexec: exotic proc on cpu%d\n", mp->machno);
		qlock(&p->debug);
		if(waserror()){
			DBG("kexec: had error");
			qunlock(&p->debug);
			nexterror();
		}
		p->nicc++;
		p->state = Exotic;
		p->psstate = 0;
		DBG("kexec: unlocking");
		qunlock(&p->debug);
		poperror();
		mfence();
		mp->icc->fn = (void*)entry;
		sched();
	}else{
		DBG("kexec: readying\n");
		ready(p);
		p->newtlb = 1;
		mmuflush();
	}
	DBG("kforkexecac up %#p done\n"
		"textsz %lx datasz %lx bsssz %lx hdrsz %lx\n"
		"textlim %ullx datalim %ullx bsslim %ullx\n", m->externup,
		textsz, datasz, bsssz, hdrsz, textlim, datalim, bsslim);
}