#include "opt_compat_netbsd32.h"
#include "opt_ddb.h"
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.15 2023/12/20 06:13:58 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/vnode.h>
#include <sys/cpu.h>
#include <sys/buf.h>
#include <sys/exec.h>
#include <sys/syslog.h>
#include <uvm/uvm_extern.h>
#include <aarch64/pcb.h>
#include <aarch64/frame.h>
#include <aarch64/machdep.h>
#include <aarch64/armreg.h>
void
cpu_proc_fork(struct proc *p1, struct proc *p2)
{
}
void
cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack, size_t stacksize,
void (*func)(void *), void *arg)
{
const struct pcb * const pcb1 = lwp_getpcb(l1);
struct pcb * const pcb2 = lwp_getpcb(l2);
#if 0
printf("cpu_lwp_fork: lwp1=%p, lwp2=%p, curlwp=%p, lwp0=%p\n",
l1, l2, curlwp, &lwp0);
#endif
*pcb2 = *pcb1;
l2->l_md.md_cpacr = CPACR_FPEN_NONE;
KASSERT(l2->l_md.md_astpending == 0);
#ifdef ARMV83_PAC
l2->l_md.md_ia_kern[0] = (uintptr_t)l2;
l2->l_md.md_ia_kern[1] = (uintptr_t)stack;
memcpy(l2->l_md.md_ia_user, l1->l_md.md_ia_user,
sizeof(l2->l_md.md_ia_user));
memcpy(l2->l_md.md_ib_user, l1->l_md.md_ib_user,
sizeof(l2->l_md.md_ib_user));
memcpy(l2->l_md.md_da_user, l1->l_md.md_da_user,
sizeof(l2->l_md.md_da_user));
memcpy(l2->l_md.md_db_user, l1->l_md.md_db_user,
sizeof(l2->l_md.md_db_user));
memcpy(l2->l_md.md_ga_user, l1->l_md.md_ga_user,
sizeof(l2->l_md.md_ga_user));
#endif
vaddr_t uv = uvm_lwp_getuarea(l2);
#ifdef STACKCHECKS
#define PCB_END(l) ((char *)lwp_getpcb((l)) + sizeof(struct pcb))
#define UAREA_END(l) ((char *)uvm_lwp_getuarea((l)) + USPACE)
memset(PCB_END(l2), 0xdd, UAREA_END(l2) - PCB_END(l2));
printf("lwp %p: pcb=%p, stack=%p-%p\n", l2, lwp_getpcb(l2),
PCB_END(l2), UAREA_END(l2));
#endif
struct trapframe * const utf = (struct trapframe *)(uv + USPACE) - 1;
l2->l_md.md_utf = utf;
*utf = *l1->l_md.md_utf;
if (stack != NULL) {
utf->tf_sp = (vaddr_t)(stack) + stacksize;
#ifdef COMPAT_NETBSD32
if (__predict_false(l2->l_proc->p_flag & PK_32)) {
utf->tf_sp &= -8;
utf->tf_reg[13] = utf->tf_sp;
} else
#endif
utf->tf_sp &= -16;
}
struct trapframe * const ktf = utf - 1;
ktf->tf_reg[27] = (uint64_t)func;
ktf->tf_reg[28] = (uint64_t)arg;
ktf->tf_lr = (uintptr_t)lwp_trampoline;
#ifdef DDB
ktf->tf_reg[29] = (uint64_t)utf;
ktf->tf_pc = (uint64_t)&&backtrace_here;
ktf->tf_sp = 0;
backtrace_here:
#endif
pcb2->pcb_tf = ktf;
}
void
cpu_lwp_free(struct lwp *l, int proc)
{
#ifdef STACKCHECKS
u_char *stop, *sbottom, *ptr;
u_int cnt;
stop = PCB_END(l);
sbottom = UAREA_END(l);
for (cnt = 0, ptr = stop; *ptr == 0xdd && ptr <= sbottom; cnt++, ptr++)
;
log(LOG_INFO, "lwp %p: %u/%ld bytes are used for EL1 stack\n",
l, cnt, sbottom - stop);
#endif
}
void
cpu_lwp_free2(struct lwp *l)
{
}
int
vmapbuf(struct buf *bp, vsize_t len)
{
vaddr_t faddr, taddr, off;
paddr_t fpa;
if ((bp->b_flags & B_PHYS) == 0)
panic("vmapbuf");
bp->b_saveaddr = bp->b_data;
faddr = trunc_page((vaddr_t)bp->b_data);
off = (vaddr_t)bp->b_data - faddr;
len = round_page(off + len);
taddr = uvm_km_alloc(phys_map, len, atop(faddr) & uvmexp.colormask,
UVM_KMF_VAONLY | UVM_KMF_WAITVA | UVM_KMF_COLORMATCH);
bp->b_data = (void *)(taddr + off);
while (len) {
(void)pmap_extract(vm_map_pmap(&bp->b_proc->p_vmspace->vm_map),
faddr, &fpa);
pmap_enter(pmap_kernel(), taddr, fpa,
VM_PROT_READ | VM_PROT_WRITE,
VM_PROT_READ | VM_PROT_WRITE | PMAP_WIRED);
faddr += PAGE_SIZE;
taddr += PAGE_SIZE;
len -= PAGE_SIZE;
}
pmap_update(pmap_kernel());
return 0;
}
void
vunmapbuf(struct buf *bp, vsize_t len)
{
vaddr_t addr, off;
if ((bp->b_flags & B_PHYS) == 0)
panic("vunmapbuf");
addr = trunc_page((vaddr_t)bp->b_data);
off = (vaddr_t)bp->b_data - addr;
len = round_page(off + len);
pmap_remove(pmap_kernel(), addr, addr + len);
pmap_update(pmap_kernel());
uvm_km_free(phys_map, addr, len, UVM_KMF_VAONLY);
bp->b_data = bp->b_saveaddr;
bp->b_saveaddr = 0;
}