riscv/addrenv: Create utility function for dynamic mappings
Move the mapping functionality from up_shmat/shmdt into two generic mapping functions. This makes it possible to do other mappings besides user shared memory area mappings.
This commit is contained in:
parent
2e6d0815b2
commit
aee45c9c43
@ -67,5 +67,50 @@
|
|||||||
|
|
||||||
uintptr_t riscv_get_pgtable(arch_addrenv_t *addrenv, uintptr_t vaddr);
|
uintptr_t riscv_get_pgtable(arch_addrenv_t *addrenv, uintptr_t vaddr);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: riscv_map_pages
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Map physical pages into a continuous virtual memory block.
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* addrenv - Pointer to a structure describing the address environment.
|
||||||
|
* pages - A pointer to the first element in a array of physical address,
|
||||||
|
* each corresponding to one page of memory.
|
||||||
|
* npages - The number of pages in the list of physical pages to be mapped.
|
||||||
|
* vaddr - The virtual address corresponding to the beginning of the
|
||||||
|
* (continuous) virtual address region.
|
||||||
|
* prot - MMU flags to use.
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* Zero (OK) is returned on success; a negated errno value is returned
|
||||||
|
* on failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int riscv_map_pages(arch_addrenv_t *addrenv, uintptr_t *pages,
|
||||||
|
unsigned int npages, uintptr_t vaddr, int prot);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: riscv_unmap_pages
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Unmap a previously mapped virtual memory region.
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* addrenv - Pointer to a structure describing the address environment.
|
||||||
|
* vaddr - The virtual address corresponding to the beginning of the
|
||||||
|
* (continuous) virtual address region.
|
||||||
|
* npages - The number of pages to be unmapped
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* Zero (OK) is returned on success; a negated errno value is returned
|
||||||
|
* on failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int riscv_unmap_pages(arch_addrenv_t *addrenv, uintptr_t vaddr,
|
||||||
|
unsigned int npages);
|
||||||
|
|
||||||
#endif /* CONFIG_ARCH_ADDRENV */
|
#endif /* CONFIG_ARCH_ADDRENV */
|
||||||
#endif /* __ARCH_RISC_V_SRC_COMMON_ADDRENV_H */
|
#endif /* __ARCH_RISC_V_SRC_COMMON_ADDRENV_H */
|
||||||
|
@ -66,11 +66,8 @@
|
|||||||
|
|
||||||
int up_shmat(uintptr_t *pages, unsigned int npages, uintptr_t vaddr)
|
int up_shmat(uintptr_t *pages, unsigned int npages, uintptr_t vaddr)
|
||||||
{
|
{
|
||||||
struct tcb_s *tcb = nxsched_self();
|
struct tcb_s *tcb = nxsched_self();
|
||||||
struct arch_addrenv_s *addrenv;
|
struct arch_addrenv_s *addrenv = &tcb->addrenv_own->addrenv;
|
||||||
uintptr_t ptlast;
|
|
||||||
uintptr_t ptlevel;
|
|
||||||
uintptr_t paddr;
|
|
||||||
|
|
||||||
/* Sanity checks */
|
/* Sanity checks */
|
||||||
|
|
||||||
@ -79,33 +76,9 @@ int up_shmat(uintptr_t *pages, unsigned int npages, uintptr_t vaddr)
|
|||||||
DEBUGASSERT(vaddr >= CONFIG_ARCH_SHM_VBASE && vaddr < ARCH_SHM_VEND);
|
DEBUGASSERT(vaddr >= CONFIG_ARCH_SHM_VBASE && vaddr < ARCH_SHM_VEND);
|
||||||
DEBUGASSERT(MM_ISALIGNED(vaddr));
|
DEBUGASSERT(MM_ISALIGNED(vaddr));
|
||||||
|
|
||||||
addrenv = &tcb->addrenv_own->addrenv;
|
/* Let riscv_map_pages do the work */
|
||||||
ptlevel = RV_MMU_PT_LEVELS;
|
|
||||||
|
|
||||||
/* Add the references to pages[] into the caller's address environment */
|
return riscv_map_pages(addrenv, pages, npages, vaddr, MMU_UDATA_FLAGS);
|
||||||
|
|
||||||
for (; npages > 0; npages--)
|
|
||||||
{
|
|
||||||
/* Get the address of the last level page table */
|
|
||||||
|
|
||||||
ptlast = riscv_pgvaddr(riscv_get_pgtable(addrenv, vaddr));
|
|
||||||
if (!ptlast)
|
|
||||||
{
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Then add the reference */
|
|
||||||
|
|
||||||
paddr = *pages++;
|
|
||||||
mmu_ln_setentry(ptlevel, ptlast, paddr, vaddr, MMU_UDATA_FLAGS);
|
|
||||||
vaddr += MM_PGSIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Flush the data cache, so the changes are committed to memory */
|
|
||||||
|
|
||||||
__DMB();
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@ -127,12 +100,8 @@ int up_shmat(uintptr_t *pages, unsigned int npages, uintptr_t vaddr)
|
|||||||
|
|
||||||
int up_shmdt(uintptr_t vaddr, unsigned int npages)
|
int up_shmdt(uintptr_t vaddr, unsigned int npages)
|
||||||
{
|
{
|
||||||
struct tcb_s *tcb = nxsched_self();
|
struct tcb_s *tcb = nxsched_self();
|
||||||
struct arch_addrenv_s *addrenv;
|
struct arch_addrenv_s *addrenv = &tcb->addrenv_own->addrenv;
|
||||||
uintptr_t ptlast;
|
|
||||||
uintptr_t ptprev;
|
|
||||||
uintptr_t ptlevel;
|
|
||||||
uintptr_t paddr;
|
|
||||||
|
|
||||||
/* Sanity checks */
|
/* Sanity checks */
|
||||||
|
|
||||||
@ -141,40 +110,9 @@ int up_shmdt(uintptr_t vaddr, unsigned int npages)
|
|||||||
DEBUGASSERT(vaddr >= CONFIG_ARCH_SHM_VBASE && vaddr < ARCH_SHM_VEND);
|
DEBUGASSERT(vaddr >= CONFIG_ARCH_SHM_VBASE && vaddr < ARCH_SHM_VEND);
|
||||||
DEBUGASSERT(MM_ISALIGNED(vaddr));
|
DEBUGASSERT(MM_ISALIGNED(vaddr));
|
||||||
|
|
||||||
addrenv = &tcb->addrenv_own->addrenv;
|
/* Let riscv_unmap_pages do the work */
|
||||||
ptlevel = ARCH_SPGTS;
|
|
||||||
ptprev = riscv_pgvaddr(addrenv->spgtables[ARCH_SPGTS - 1]);
|
|
||||||
if (!ptprev)
|
|
||||||
{
|
|
||||||
/* Something is very wrong */
|
|
||||||
|
|
||||||
return -EFAULT;
|
return riscv_unmap_pages(addrenv, vaddr, npages);
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove the references from the caller's address environment */
|
|
||||||
|
|
||||||
for (; npages > 0; npages--)
|
|
||||||
{
|
|
||||||
/* Get the current final level entry corresponding to this vaddr */
|
|
||||||
|
|
||||||
paddr = mmu_pte_to_paddr(mmu_ln_getentry(ptlevel, ptprev, vaddr));
|
|
||||||
ptlast = riscv_pgvaddr(paddr);
|
|
||||||
if (!ptlast)
|
|
||||||
{
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Then wipe the reference */
|
|
||||||
|
|
||||||
mmu_ln_clear(ptlevel + 1, ptlast, vaddr);
|
|
||||||
vaddr += MM_PGSIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Flush the data cache, so the changes are committed to memory */
|
|
||||||
|
|
||||||
__DMB();
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_BUILD_KERNEL */
|
#endif /* CONFIG_BUILD_KERNEL */
|
||||||
|
@ -91,4 +91,121 @@ uintptr_t riscv_get_pgtable(arch_addrenv_t *addrenv, uintptr_t vaddr)
|
|||||||
return paddr;
|
return paddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: riscv_map_pages
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Map physical pages into a continuous virtual memory block.
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* addrenv - Pointer to a structure describing the address environment.
|
||||||
|
* pages - A pointer to the first element in a array of physical address,
|
||||||
|
* each corresponding to one page of memory.
|
||||||
|
* npages - The number of pages in the list of physical pages to be mapped.
|
||||||
|
* vaddr - The virtual address corresponding to the beginning of the
|
||||||
|
* (continuous) virtual address region.
|
||||||
|
* prot - MMU flags to use.
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* Zero (OK) is returned on success; a negated errno value is returned
|
||||||
|
* on failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int riscv_map_pages(arch_addrenv_t *addrenv, uintptr_t *pages,
|
||||||
|
unsigned int npages, uintptr_t vaddr, int prot)
|
||||||
|
{
|
||||||
|
uintptr_t ptlast;
|
||||||
|
uintptr_t ptlevel;
|
||||||
|
uintptr_t paddr;
|
||||||
|
|
||||||
|
ptlevel = RV_MMU_PT_LEVELS;
|
||||||
|
|
||||||
|
/* Add the references to pages[] into the caller's address environment */
|
||||||
|
|
||||||
|
for (; npages > 0; npages--)
|
||||||
|
{
|
||||||
|
/* Get the address of the last level page table */
|
||||||
|
|
||||||
|
ptlast = riscv_pgvaddr(riscv_get_pgtable(addrenv, vaddr));
|
||||||
|
if (!ptlast)
|
||||||
|
{
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Then add the reference */
|
||||||
|
|
||||||
|
paddr = *pages++;
|
||||||
|
mmu_ln_setentry(ptlevel, ptlast, paddr, vaddr, prot);
|
||||||
|
vaddr += MM_PGSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flush the data cache, so the changes are committed to memory */
|
||||||
|
|
||||||
|
__DMB();
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: riscv_unmap_pages
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Unmap a previously mapped virtual memory region.
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* addrenv - Pointer to a structure describing the address environment.
|
||||||
|
* vaddr - The virtual address corresponding to the beginning of the
|
||||||
|
* (continuous) virtual address region.
|
||||||
|
* npages - The number of pages to be unmapped
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* Zero (OK) is returned on success; a negated errno value is returned
|
||||||
|
* on failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int riscv_unmap_pages(arch_addrenv_t *addrenv, uintptr_t vaddr,
|
||||||
|
unsigned int npages)
|
||||||
|
{
|
||||||
|
uintptr_t ptlast;
|
||||||
|
uintptr_t ptprev;
|
||||||
|
uintptr_t ptlevel;
|
||||||
|
uintptr_t paddr;
|
||||||
|
|
||||||
|
ptlevel = ARCH_SPGTS;
|
||||||
|
ptprev = riscv_pgvaddr(addrenv->spgtables[ARCH_SPGTS - 1]);
|
||||||
|
if (!ptprev)
|
||||||
|
{
|
||||||
|
/* Something is very wrong */
|
||||||
|
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove the references from the caller's address environment */
|
||||||
|
|
||||||
|
for (; npages > 0; npages--)
|
||||||
|
{
|
||||||
|
/* Get the current final level entry corresponding to this vaddr */
|
||||||
|
|
||||||
|
paddr = mmu_pte_to_paddr(mmu_ln_getentry(ptlevel, ptprev, vaddr));
|
||||||
|
ptlast = riscv_pgvaddr(paddr);
|
||||||
|
if (!ptlast)
|
||||||
|
{
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Then wipe the reference */
|
||||||
|
|
||||||
|
mmu_ln_clear(ptlevel + 1, ptlast, vaddr);
|
||||||
|
vaddr += MM_PGSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flush the data cache, so the changes are committed to memory */
|
||||||
|
|
||||||
|
__DMB();
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_BUILD_KERNEL */
|
#endif /* CONFIG_BUILD_KERNEL */
|
||||||
|
Loading…
Reference in New Issue
Block a user