Files
vmware-host-modules/vmmon-only/include/pgtbl.h
T

383 lines
9.1 KiB
C

/*********************************************************
* Copyright (C) 2002,2014 VMware, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
#ifndef __PGTBL_H__
# define __PGTBL_H__
#include <linux/highmem.h>
#include "compat_pgtable.h"
#include "compat_spinlock.h"
#include "compat_page.h"
/*
*-----------------------------------------------------------------------------
*
* PgtblPte2MPN --
*
* Returns the page structure associated to a Page Table Entry.
*
* This function is not allowed to schedule() because it can be called while
* holding a spinlock --hpreg
*
* Results:
* INVALID_MPN on failure
* mpn on success
*
* Side effects:
* None
*
*-----------------------------------------------------------------------------
*/
static INLINE MPN
PgtblPte2MPN(pte_t *pte) // IN
{
MPN mpn;
if (pte_present(*pte) == 0) {
return INVALID_MPN;
}
mpn = pte_pfn(*pte);
if (mpn >= INVALID_MPN) {
return INVALID_MPN;
}
return mpn;
}
/*
*-----------------------------------------------------------------------------
*
* PgtblPte2Page --
*
* Returns the page structure associated to a Page Table Entry.
*
* This function is not allowed to schedule() because it can be called while
* holding a spinlock --hpreg
*
* Results:
* The page structure if the page table entry points to a physical page
* NULL if the page table entry does not point to a physical page
*
* Side effects:
* None
*
*-----------------------------------------------------------------------------
*/
static INLINE struct page *
PgtblPte2Page(pte_t *pte) // IN
{
if (pte_present(*pte) == 0) {
return NULL;
}
return compat_pte_page(*pte);
}
/*
*-----------------------------------------------------------------------------
*
* PgtblPGD2PTELocked --
*
* Walks through the hardware page tables to try to find the pte
* associated to a virtual address.
*
* Results:
* pte. Caller must call pte_unmap if valid pte returned.
*
* Side effects:
* None
*
*-----------------------------------------------------------------------------
*/
static INLINE pte_t *
PgtblPGD2PTELocked(compat_pgd_t *pgd, // IN: PGD to start with
VA addr) // IN: Address in the virtual address
// space of that process
{
compat_pud_t *pud;
pmd_t *pmd;
pte_t *pte;
if (compat_pgd_present(*pgd) == 0) {
return NULL;
}
pud = compat_pud_offset(pgd, addr);
if (compat_pud_present(*pud) == 0) {
return NULL;
}
pmd = pmd_offset_map(pud, addr);
if (pmd_present(*pmd) == 0) {
pmd_unmap(pmd);
return NULL;
}
pte = pte_offset_map(pmd, addr);
pmd_unmap(pmd);
return pte;
}
/*
*-----------------------------------------------------------------------------
*
* PgtblVa2PTELocked --
*
* Walks through the hardware page tables to try to find the pte
* associated to a virtual address.
*
* Results:
* pte. Caller must call pte_unmap if valid pte returned.
*
* Side effects:
* None
*
*-----------------------------------------------------------------------------
*/
static INLINE pte_t *
PgtblVa2PTELocked(struct mm_struct *mm, // IN: Mm structure of a process
VA addr) // IN: Address in the virtual address
// space of that process
{
return PgtblPGD2PTELocked(compat_pgd_offset(mm, addr), addr);
}
/*
*-----------------------------------------------------------------------------
*
* PgtblVa2MPNLocked --
*
* Retrieve MPN for a given va.
*
* Caller must call pte_unmap if valid pte returned. The mm->page_table_lock
* must be held, so this function is not allowed to schedule() --hpreg
*
* Results:
* INVALID_MPN on failure
* mpn on success
*
* Side effects:
* None
*
*-----------------------------------------------------------------------------
*/
static INLINE MPN
PgtblVa2MPNLocked(struct mm_struct *mm, // IN: Mm structure of a process
VA addr) // IN: Address in the virtual address
{
pte_t *pte;
pte = PgtblVa2PTELocked(mm, addr);
if (pte != NULL) {
MPN mpn = PgtblPte2MPN(pte);
pte_unmap(pte);
return mpn;
}
return INVALID_MPN;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
/*
*-----------------------------------------------------------------------------
*
* PgtblKVa2MPNLocked --
*
* Retrieve MPN for a given kernel va.
*
* Caller must call pte_unmap if valid pte returned. The mm->page_table_lock
* must be held, so this function is not allowed to schedule() --hpreg
*
* Results:
* INVALID_MPN on failure
* mpn on success
*
* Side effects:
* None
*
*-----------------------------------------------------------------------------
*/
static INLINE MPN
PgtblKVa2MPNLocked(struct mm_struct *mm, // IN: Mm structure of a caller
VA addr) // IN: Address in the virtual address
{
pte_t *pte;
pte = PgtblPGD2PTELocked(compat_pgd_offset_k(mm, addr), addr);
if (pte != NULL) {
MPN mpn = PgtblPte2MPN(pte);
pte_unmap(pte);
return mpn;
}
return INVALID_MPN;
}
#endif
/*
*-----------------------------------------------------------------------------
*
* PgtblVa2PageLocked --
*
* Return the "page" struct for a given va.
*
* Results:
* struct page or NULL. The mm->page_table_lock must be held, so this
* function is not allowed to schedule() --hpreg
*
* Side effects:
* None
*
*-----------------------------------------------------------------------------
*/
static INLINE struct page *
PgtblVa2PageLocked(struct mm_struct *mm, // IN: Mm structure of a process
VA addr) // IN: Address in the virtual address
{
pte_t *pte;
pte = PgtblVa2PTELocked(mm, addr);
if (pte != NULL) {
struct page *page = PgtblPte2Page(pte);
pte_unmap(pte);
return page;
} else {
return NULL;
}
}
/*
*-----------------------------------------------------------------------------
*
* PgtblVa2MPN --
*
* Walks through the hardware page tables of the current process to try to
* find the page structure associated to a virtual address.
*
* Results:
* Same as PgtblVa2MPNLocked()
*
* Side effects:
* None
*
*-----------------------------------------------------------------------------
*/
static INLINE MPN
PgtblVa2MPN(VA addr) // IN
{
struct mm_struct *mm;
MPN mpn;
/* current->mm is NULL for kernel threads, so use active_mm. */
mm = current->active_mm;
if (compat_get_page_table_lock(mm)) {
spin_lock(compat_get_page_table_lock(mm));
}
mpn = PgtblVa2MPNLocked(mm, addr);
if (compat_get_page_table_lock(mm)) {
spin_unlock(compat_get_page_table_lock(mm));
}
return mpn;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
/*
*-----------------------------------------------------------------------------
*
* PgtblKVa2MPN --
*
* Walks through the hardware page tables of the current process to try to
* find the page structure associated to a virtual address.
*
* Results:
* Same as PgtblVa2MPNLocked()
*
* Side effects:
* None
*
*-----------------------------------------------------------------------------
*/
static INLINE MPN
PgtblKVa2MPN(VA addr) // IN
{
struct mm_struct *mm = current->active_mm;
MPN mpn;
if (compat_get_page_table_lock(mm)) {
spin_lock(compat_get_page_table_lock(mm));
}
mpn = PgtblKVa2MPNLocked(mm, addr);
if (compat_get_page_table_lock(mm)) {
spin_unlock(compat_get_page_table_lock(mm));
}
return mpn;
}
#endif
/*
*-----------------------------------------------------------------------------
*
* PgtblVa2Page --
*
* Walks through the hardware page tables of the current process to try to
* find the page structure associated to a virtual address.
*
* Results:
* Same as PgtblVa2PageLocked()
*
* Side effects:
* None
*
*-----------------------------------------------------------------------------
*/
static INLINE struct page *
PgtblVa2Page(VA addr) // IN
{
struct mm_struct *mm = current->active_mm;
struct page *page;
if (compat_get_page_table_lock(mm)) {
spin_lock(compat_get_page_table_lock(mm));
}
page = PgtblVa2PageLocked(mm, addr);
if (compat_get_page_table_lock(mm)) {
spin_unlock(compat_get_page_table_lock(mm));
}
return page;
}
#endif /* __PGTBL_H__ */