#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.9 2024/08/04 08:16:26 skrll Exp $");
#define _PMAP_PRIVATE
#include "opt_ddb.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/cpu.h>
#include <sys/vnode.h>
#include <sys/core.h>
#include <sys/exec.h>
#include <uvm/uvm.h>
#include <dev/mm.h>
#include <riscv/frame.h>
#include <riscv/locore.h>
#include <riscv/machdep.h>
void
cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack, size_t stacksize,
void (*func)(void *), void *arg)
{
struct pcb * const pcb1 = lwp_getpcb(l1);
struct pcb * const pcb2 = lwp_getpcb(l2);
struct trapframe *tf;
KASSERT(l1 == curlwp || l1 == &lwp0);
KASSERT(l2->l_md.md_astpending == 0);
*pcb2 = *pcb1;
vaddr_t ua2 = uvm_lwp_getuarea(l2);
tf = (struct trapframe *)(ua2 + USPACE) - 1;
*tf = *l1->l_md.md_utf;
#ifdef FPE
tf->tf_sr &= ~SR_FS;
#endif
if (stack != NULL) {
tf->tf_sp = stack_align((intptr_t)stack + stacksize);
}
l2->l_md.md_utf = tf;
--tf;
tf->tf_s0 = 0;
tf->tf_s1 = (intptr_t)func;
tf->tf_s2 = (intptr_t)arg;
tf->tf_ra = (intptr_t)lwp_trampoline;
l2->l_md.md_ktf = tf;
KASSERT(l2->l_md.md_astpending == 0);
}
void
cpu_proc_fork(struct proc *p1, struct proc *p2)
{
}
#ifdef _LP64
void *
cpu_uarea_alloc(bool system)
{
struct pglist pglist;
int error;
error = uvm_pglistalloc(USPACE, pmap_limits.avail_start,
pmap_limits.avail_end, USPACE_ALIGN, 0, &pglist, 1, 1);
if (error) {
return NULL;
}
const struct vm_page * const pg = TAILQ_FIRST(&pglist);
KASSERT(pg != NULL);
const paddr_t pa = VM_PAGE_TO_PHYS(pg);
KASSERTMSG(pa >= pmap_limits.avail_start,
"pa (%#"PRIxPADDR") < avail_start (%#"PRIxPADDR")",
pa, pmap_limits.avail_start);
KASSERTMSG(pa + USPACE <= pmap_limits.avail_end,
"pa (%#"PRIxPADDR") >= avail_end (%#"PRIxPADDR")",
pa, pmap_limits.avail_end);
return (void *)pmap_md_direct_map_paddr(pa);
}
bool
cpu_uarea_free(void *va)
{
if (!pmap_md_direct_mapped_vaddr_p((vaddr_t)va))
return false;
paddr_t pa = pmap_md_direct_mapped_vaddr_to_paddr((vaddr_t)va);
for (const paddr_t epa = pa + USPACE; pa < epa; pa += PAGE_SIZE) {
struct vm_page * const pg = PHYS_TO_VM_PAGE(pa);
KASSERT(pg != NULL);
uvm_pagefree(pg);
}
return true;
}
#endif
void
cpu_lwp_free(struct lwp *l, int proc)
{
(void)l;
}
vaddr_t
cpu_lwp_pc(struct lwp *l)
{
return l->l_md.md_utf->tf_pc;
}
void
cpu_lwp_free2(struct lwp *l)
{
(void)l;
}
int
vmapbuf(struct buf *bp, vsize_t len)
{
vaddr_t kva;
if ((bp->b_flags & B_PHYS) == 0)
panic("vmapbuf");
vaddr_t uva = trunc_page((vaddr_t)bp->b_data);
const vaddr_t off = (vaddr_t)bp->b_data - uva;
len = round_page(off + len);
kva = uvm_km_alloc(phys_map, len, atop(uva) & uvmexp.colormask,
UVM_KMF_VAONLY | UVM_KMF_WAITVA | UVM_KMF_COLORMATCH);
KASSERT((atop(kva ^ uva) & uvmexp.colormask) == 0);
bp->b_saveaddr = bp->b_data;
bp->b_data = (void *)(kva + off);
struct pmap * const upmap = vm_map_pmap(&bp->b_proc->p_vmspace->vm_map);
do {
paddr_t pa;
if (pmap_extract(upmap, uva, &pa) == false)
panic("vmapbuf: null page frame");
pmap_kenter_pa(kva, pa, VM_PROT_READ | VM_PROT_WRITE,
PMAP_WIRED);
uva += PAGE_SIZE;
kva += PAGE_SIZE;
len -= PAGE_SIZE;
} while (len);
pmap_update(pmap_kernel());
return 0;
}
void
vunmapbuf(struct buf *bp, vsize_t len)
{
vaddr_t kva;
KASSERT(bp->b_flags & B_PHYS);
kva = trunc_page((vaddr_t)bp->b_data);
len = round_page((vaddr_t)bp->b_data - kva + len);
pmap_kremove(kva, len);
pmap_update(pmap_kernel());
uvm_km_free(phys_map, kva, len, UVM_KMF_VAONLY);
bp->b_data = bp->b_saveaddr;
bp->b_saveaddr = NULL;
}
int
mm_md_physacc(paddr_t pa, vm_prot_t prot)
{
return (atop(pa) < physmem) ? 0 : EFAULT;
}
#ifdef __HAVE_MM_MD_DIRECT_MAPPED_PHYS
bool
mm_md_direct_mapped_phys(paddr_t pa, vaddr_t *vap)
{
if (pa >= physical_start && pa <= physical_end) {
if (*vap)
*vap = pmap_md_direct_map_paddr(pa);
return true;
}
return false;
}
#endif