#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.58 2023/02/25 08:30:31 skrll Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/signalvar.h>
#include <sys/buf.h>
#include <sys/vnode.h>
#include <sys/ptrace.h>
#include <sys/exec.h>
#include <sys/core.h>
#include <sys/pool.h>
#include <sys/cpu.h>
#include <machine/cpufunc.h>
#include <machine/pmap.h>
#include <machine/pcb.h>
#include <uvm/uvm.h>
extern struct pool hppa_fppl;
#include <hppa/hppa/machdep.h>
static inline void
cpu_activate_pcb(struct lwp *l)
{
struct trapframe *tf = l->l_md.md_regs;
struct pcb *pcb = lwp_getpcb(l);
#ifdef DIAGNOSTIC
vaddr_t uarea = (vaddr_t)pcb;
vaddr_t maxsp = uarea + USPACE;
KASSERT(tf == (void *)(uarea + PAGE_SIZE));
#endif
tf->tf_cr30 = (u_int)pcb->pcb_fpregs;
#ifdef DIAGNOSTIC
pmap_remove(pmap_kernel(), maxsp - PAGE_SIZE, maxsp);
pmap_update(pmap_kernel());
#endif
}
void
cpu_proc_fork(struct proc *p1, struct proc *p2)
{
p2->p_md.md_flags = p1->p_md.md_flags;
}
void
cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack, size_t stacksize,
void (*func)(void *), void *arg)
{
struct pcb *pcb1, *pcb2;
struct trapframe *tf;
register_t sp, osp;
vaddr_t uv;
KASSERT(round_page(sizeof(struct pcb)) <= PAGE_SIZE);
pcb1 = lwp_getpcb(l1);
pcb2 = lwp_getpcb(l2);
KASSERT(l2->l_md.md_astpending == 0);
KASSERT(l2->l_md.md_flags == 0);
hppa_fpu_flush(l1);
memcpy(pcb2, pcb1, sizeof(struct pcb));
pcb2->pcb_fpregs = pool_get(&hppa_fppl, PR_WAITOK);
*pcb2->pcb_fpregs = *pcb1->pcb_fpregs;
pcb2->pcb_fpregs->fpr_regs[0] =
HPPA_FPU_FORK(pcb2->pcb_fpregs->fpr_regs[0]);
pcb2->pcb_fpregs->fpr_regs[1] = 0;
pcb2->pcb_fpregs->fpr_regs[2] = 0;
pcb2->pcb_fpregs->fpr_regs[3] = 0;
l2->l_md.md_bpva = l1->l_md.md_bpva;
l2->l_md.md_bpsave[0] = l1->l_md.md_bpsave[0];
l2->l_md.md_bpsave[1] = l1->l_md.md_bpsave[1];
uv = uvm_lwp_getuarea(l2);
sp = (register_t)uv + PAGE_SIZE;
tf = l2->l_md.md_regs = (struct trapframe *)sp;
sp += sizeof(struct trapframe);
memcpy(tf, l1->l_md.md_regs, sizeof(*tf));
cpu_activate_pcb(l2);
if (__predict_true(l2->l_proc->p_vmspace != NULL)) {
hppa_setvmspace(l2);
mfctl(CR_EIEM, tf->tf_eiem);
tf->tf_ipsw = PSW_C | PSW_Q | PSW_P | PSW_D | PSW_I |
(curcpu()->ci_psw & PSW_O);
}
tf->tf_ret0 = l1->l_proc->p_pid;
tf->tf_ret1 = 1;
tf->tf_t1 = 0;
if (stack != NULL)
tf->tf_sp = (register_t)stack;
osp = sp;
sp += HPPA_FRAME_SIZE;
*(register_t *)(sp) = 0;
*(register_t *)(sp + HPPA_FRAME_PSP) = osp;
*(register_t *)(sp + HPPA_FRAME_CRP) = (register_t)lwp_trampoline;
*HPPA_FRAME_CARG(2, sp) = KERNMODE(func);
*HPPA_FRAME_CARG(3, sp) = (register_t)arg;
sp += HPPA_FRAME_SIZE + 16*4;
pcb2->pcb_ksp = sp;
fdcache(HPPA_SID_KERNEL, uv, sp - uv);
}
void
cpu_lwp_free(struct lwp *l, int proc)
{
struct pcb *pcb = lwp_getpcb(l);
hppa_fpu_flush(l);
pool_put(&hppa_fppl, pcb->pcb_fpregs);
}
void
cpu_lwp_free2(struct lwp *l)
{
(void)l;
}
int
vmapbuf(struct buf *bp, vsize_t len)
{
vaddr_t uva, kva;
paddr_t pa;
vsize_t size, off;
int npf;
struct pmap *upmap, *kpmap;
#ifdef DIAGNOSTIC
if ((bp->b_flags & B_PHYS) == 0)
panic("vmapbuf");
#endif
upmap = vm_map_pmap(&bp->b_proc->p_vmspace->vm_map);
kpmap = vm_map_pmap(phys_map);
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);
kva = uvm_km_alloc(phys_map, len, 0, UVM_KMF_VAONLY | UVM_KMF_WAITVA);
bp->b_data = (void *)(kva + off);
npf = btoc(size);
while (npf--) {
if (pmap_extract(upmap, uva, &pa) == false)
panic("vmapbuf: null page frame");
pmap_enter(kpmap, kva, pa,
VM_PROT_READ | VM_PROT_WRITE, PMAP_WIRED);
uva += PAGE_SIZE;
kva += PAGE_SIZE;
}
pmap_update(kpmap);
return 0;
}
void
vunmapbuf(struct buf *bp, vsize_t len)
{
struct pmap *pmap;
vaddr_t kva;
vsize_t off;
#ifdef DIAGNOSTIC
if ((bp->b_flags & B_PHYS) == 0)
panic("vunmapbuf");
#endif
kva = trunc_page((vaddr_t)bp->b_data);
off = (vaddr_t)bp->b_data - kva;
len = round_page(off + len);
pmap = vm_map_pmap(phys_map);
pmap_remove(pmap, kva, kva + len);
pmap_update(pmap);
uvm_km_free(phys_map, kva, len, UVM_KMF_VAONLY);
bp->b_data = bp->b_saveaddr;
bp->b_saveaddr = NULL;
}
int
cpu_lwp_setprivate(lwp_t *l, void *addr)
{
l->l_md.md_regs->tf_cr27 = (u_int)addr;
if (l == curlwp)
mtctl(addr, CR_TLS);
return 0;
}