#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/malloc.h>
#include <sys/buf.h>
#include <sys/vnode.h>
#include <sys/user.h>
#include <sys/exec.h>
#include <sys/signalvar.h>
#include <uvm/uvm_extern.h>
#include <machine/cpu.h>
#include <mips64/mips_cpu.h>
extern void proc_trampoline(void);
void
cpu_fork(struct proc *p1, struct proc *p2, void *stack, void *tcb,
void (*func)(void *), void *arg)
{
struct cpu_info *ci = curcpu();
struct pcb *pcb;
#if UPAGES == 1
paddr_t pa;
p2->p_md.md_uarea = (vaddr_t)p2->p_addr;
pmap_extract(pmap_kernel(), p2->p_md.md_uarea, &pa);
p2->p_addr = (void *)PHYS_TO_XKPHYS(pa, CCA_CACHED);
#endif
pcb = &p2->p_addr->u_pcb;
if (p1 == ci->ci_fpuproc)
save_fpu();
p2->p_md.md_flags = p1->p_md.md_flags & MDP_FORKSAVE;
#ifdef FPUEMUL
if (!CPU_HAS_FPU(ci)) {
p2->p_md.md_fppgva = p1->p_md.md_fppgva;
KASSERT((p2->p_md.md_flags & MDP_FPUSED) == 0);
}
#endif
if (p1 == curproc) {
savectx(p1->p_addr, 0);
}
#ifdef DIAGNOSTIC
else if (p1 != &proc0)
panic("cpu_fork: curproc");
#endif
*pcb = p1->p_addr->u_pcb;
p2->p_md.md_regs = &p2->p_addr->u_pcb.pcb_regs;
if (stack != NULL)
p2->p_md.md_regs->sp = (u_int64_t)stack;
p2->p_md.md_tcb = tcb != NULL ? tcb : p1->p_md.md_tcb;
if (p1 != curproc) {
pcb->pcb_context.val[11] = (pcb->pcb_regs.sr & ~SR_INT_MASK) |
(idle_mask & SR_INT_MASK);
}
pcb->pcb_context.val[10] = (register_t)proc_trampoline;
pcb->pcb_context.val[8] = (register_t)pcb +
((USPACE - sizeof(struct trapframe)) & ~_STACKALIGNBYTES);
pcb->pcb_context.val[1] = (register_t)arg;
pcb->pcb_context.val[0] = (register_t)func;
}
void
cpu_exit(struct proc *p)
{
struct cpu_info *ci = curcpu();
if (ci->ci_fpuproc == p)
ci->ci_fpuproc = NULL;
#if UPAGES == 1
p->p_addr = (void *)p->p_md.md_uarea;
#endif
}
struct kmem_va_mode kv_physwait = {
.kv_map = &phys_map,
.kv_wait = 1,
};
void
vmapbuf(struct buf *bp, vsize_t len)
{
struct kmem_dyn_mode kd_prefer = { .kd_waitok = 1 };
struct pmap *pm = vm_map_pmap(&bp->b_proc->p_vmspace->vm_map);
vaddr_t kva, uva;
vsize_t size, off;
#ifdef DIAGNOSTIC
if ((bp->b_flags & B_PHYS) == 0)
panic("vmapbuf");
#endif
bp->b_saveaddr = bp->b_data;
uva = trunc_page((vaddr_t)bp->b_data);
off = (vaddr_t)bp->b_data - uva;
size = round_page(off + len);
kd_prefer.kd_prefer = uva;
kva = (vaddr_t)km_alloc(size, &kv_physwait, &kp_none, &kd_prefer);
bp->b_data = (caddr_t)(kva + off);
while (size > 0) {
paddr_t pa;
if (pmap_extract(pm, uva, &pa) == FALSE)
panic("vmapbuf: null page frame");
else
pmap_kenter_pa(kva, pa, PROT_READ | PROT_WRITE);
uva += PAGE_SIZE;
kva += PAGE_SIZE;
size -= PAGE_SIZE;
}
pmap_update(pmap_kernel());
}
void
vunmapbuf(struct buf *bp, vsize_t len)
{
vaddr_t addr, off;
#ifdef DIAGNOSTIC
if ((bp->b_flags & B_PHYS) == 0)
panic("vunmapbuf");
#endif
addr = trunc_page((vaddr_t)bp->b_data);
off = (vaddr_t)bp->b_data - addr;
len = round_page(off + len);
pmap_kremove(addr, len);
pmap_update(pmap_kernel());
km_free((void *)addr, len, &kv_physwait, &kp_none);
bp->b_data = bp->b_saveaddr;
bp->b_saveaddr = NULL;
}