summaryrefslogtreecommitdiff
path: root/src/VBox/VMM/VMMAll/MMAllPagePool.cpp
blob: ca64d47775457c4051e2e3cef862c5051ea2595e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
/* $Id: MMAllPagePool.cpp $ */
/** @file
 * MM - Memory Manager - Page Pool.
 *
 * @remarks     This file is NOT built for the raw-mode context.
 */

/*
 * Copyright (C) 2006-2007 Oracle Corporation
 *
 * This file is part of VirtualBox Open Source Edition (OSE), as
 * available from http://www.virtualbox.org. This file is free software;
 * you can redistribute it and/or modify it under the terms of the GNU
 * General Public License (GPL) as published by the Free Software
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 */

/*******************************************************************************
*   Header Files                                                               *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_MM_POOL
#include <VBox/mm.h>
#include <VBox/pgm.h>
#include <VBox/stam.h>
#include "MMInternal.h"
#include <VBox/vm.h>
#include <VBox/param.h>
#include <VBox/err.h>
#include <VBox/log.h>
#include <iprt/alloc.h>
#include <iprt/assert.h>
#include <iprt/string.h>
#define USE_INLINE_ASM_BIT_OPS
#ifdef USE_INLINE_ASM_BIT_OPS
# include <iprt/asm.h>
#endif


#ifndef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0

/**
 * Converts a pool physical address to a linear address.
 * The specified allocation type must match with the address.
 *
 * @returns Physical address.
 * @returns NULL if not found or eType is not matching.
 * @param   pPool       Pointer to the page pool.
 * @param   HCPhys      The address to convert.
 * @thread  The Emulation Thread.
 */
void *mmPagePoolPhys2Ptr(PMMPAGEPOOL pPool, RTHCPHYS HCPhys)
{
#if 0 /** @todo have to fix the debugger, but until then this is going on my nerves. */
#ifdef IN_RING3
    VM_ASSERT_EMT(pPool->pVM);
#endif
#endif

    /*
     * Lookup the virtual address.
     */
    PMMPPLOOKUPHCPHYS pLookup = (PMMPPLOOKUPHCPHYS)RTAvlHCPhysGet(&pPool->pLookupPhys, HCPhys & X86_PTE_PAE_PG_MASK);
    if (pLookup)
    {
        STAM_COUNTER_INC(&pPool->cToVirtCalls);
        PSUPPAGE        pPhysPage = pLookup->pPhysPage;
        PMMPAGESUBPOOL  pSubPool = (PMMPAGESUBPOOL)pPhysPage->uReserved;
        unsigned        iPage = pPhysPage - pSubPool->paPhysPages;
        return (char *)pSubPool->pvPages + (HCPhys & PAGE_OFFSET_MASK) + (iPage << PAGE_SHIFT);
    }
    return NULL;
}


/**
 * Convert physical address of a page to a HC virtual address.
 * This works for pages allocated by MMR3PageAlloc(), MMR3PageAllocPhys()
 * and MMR3PageAllocLow().
 *
 * @returns VBox status code.
 * @param   pVM         VM handle.
 * @param   HCPhysPage  The physical address of a page.
 * @param   ppvPage     Where to store the address corresponding to HCPhysPage.
 * @thread  The Emulation Thread.
 */
VMMDECL(int) MMPagePhys2PageEx(PVM pVM, RTHCPHYS HCPhysPage, void **ppvPage)
{
    void *pvPage = mmPagePoolPhys2Ptr(pVM->mm.s.CTX_SUFF(pPagePool), HCPhysPage);
    if (!pvPage)
    {
        pvPage = mmPagePoolPhys2Ptr(pVM->mm.s.CTX_SUFF(pPagePoolLow), HCPhysPage);
        if (!pvPage)
        {
            STAM_COUNTER_INC(&pVM->mm.s.CTX_SUFF(pPagePool)->cErrors);
            AssertMsg(pvPage, ("Invalid HCPhysPage=%RHp specified\n", HCPhysPage));
            return VERR_INVALID_POINTER;
        }
    }
    *ppvPage = pvPage;
    return VINF_SUCCESS;
}

#endif /* !VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0 */
#ifdef IN_RING3

/**
 * Convert physical address of a page to a HC virtual address.
 * This works for pages allocated by MMR3PageAlloc(), MMR3PageAllocPhys()
 * and MMR3PageAllocLow().
 *
 * @returns Pointer to the page at that physical address.
 * @param   pVM         VM handle.
 * @param   HCPhysPage  The physical address of a page.
 * @thread  The Emulation Thread.
 */
VMMDECL(void *) MMPagePhys2Page(PVM pVM, RTHCPHYS HCPhysPage)
{
    void *pvPage = mmPagePoolPhys2Ptr(pVM->mm.s.CTX_SUFF(pPagePool), HCPhysPage);
    if (!pvPage)
    {
        pvPage = mmPagePoolPhys2Ptr(pVM->mm.s.CTX_SUFF(pPagePoolLow), HCPhysPage);
        if (!pvPage)
        {
            STAM_COUNTER_INC(&pVM->mm.s.CTX_SUFF(pPagePool)->cErrors);
            AssertMsg(pvPage, ("Invalid HCPhysPage=%RHp specified\n", HCPhysPage));
        }
    }
    return pvPage;
}


/**
 * Try convert physical address of a page to a HC virtual address.
 * This works for pages allocated by MMR3PageAlloc(), MMR3PageAllocPhys()
 * and MMR3PageAllocLow().
 *
 * @returns VBox status code.
 * @param   pVM         VM handle.
 * @param   HCPhysPage  The physical address of a page.
 * @param   ppvPage     Where to store the address corresponding to HCPhysPage.
 * @thread  The Emulation Thread.
 */
VMMDECL(int) MMPagePhys2PageTry(PVM pVM, RTHCPHYS HCPhysPage, void **ppvPage)
{
    void *pvPage = mmPagePoolPhys2Ptr(pVM->mm.s.CTX_SUFF(pPagePool), HCPhysPage);
    if (!pvPage)
    {
        pvPage = mmPagePoolPhys2Ptr(pVM->mm.s.CTX_SUFF(pPagePoolLow), HCPhysPage);
        if (!pvPage)
            return VERR_INVALID_POINTER;
    }
    *ppvPage = pvPage;
    return VINF_SUCCESS;
}


/**
 * Converts a pool address to a physical address.
 * The specified allocation type must match with the address.
 *
 * @returns Physical address.
 * @returns NIL_RTHCPHYS if not found or eType is not matching.
 * @param   pPool   Pointer to the page pool.
 * @param   pv      The address to convert.
 * @thread  The Emulation Thread.
 */
RTHCPHYS mmPagePoolPtr2Phys(PMMPAGEPOOL pPool, void *pv)
{
#ifdef IN_RING3
    VM_ASSERT_EMT(pPool->pVM);
#endif
    /*
     * Lookup the virtual address.
     */
    PMMPPLOOKUPHCPTR pLookup = (PMMPPLOOKUPHCPTR)RTAvlPVGetBestFit(&pPool->pLookupVirt, pv, false);
    if (pLookup)
    {
        unsigned iPage = ((char *)pv - (char *)pLookup->pSubPool->pvPages) >> PAGE_SHIFT;
        if (iPage < pLookup->pSubPool->cPages)
        {
            /*
             * Convert the virtual address to a physical address.
             */
            STAM_COUNTER_INC(&pPool->cToPhysCalls);
            AssertMsg(     pLookup->pSubPool->paPhysPages[iPage].Phys
                      &&   !(pLookup->pSubPool->paPhysPages[iPage].Phys & PAGE_OFFSET_MASK),
                      ("Phys=%#x\n", pLookup->pSubPool->paPhysPages[iPage].Phys));
            AssertMsg((uintptr_t)pLookup->pSubPool == pLookup->pSubPool->paPhysPages[iPage].uReserved,
                      ("pSubPool=%p uReserved=%p\n", pLookup->pSubPool, pLookup->pSubPool->paPhysPages[iPage].uReserved));
            return pLookup->pSubPool->paPhysPages[iPage].Phys + ((uintptr_t)pv & PAGE_OFFSET_MASK);
        }
    }
    return NIL_RTHCPHYS;
}


/**
 * Convert a page in the page pool to a HC physical address.
 * This works for pages allocated by MMR3PageAlloc(), MMR3PageAllocPhys()
 * and MMR3PageAllocLow().
 *
 * @returns Physical address for the specified page table.
 * @param   pVM         VM handle.
 * @param   pvPage      Page which physical address we query.
 * @thread  The Emulation Thread.
 */
VMMDECL(RTHCPHYS) MMPage2Phys(PVM pVM, void *pvPage)
{
    RTHCPHYS HCPhys = mmPagePoolPtr2Phys(pVM->mm.s.CTX_SUFF(pPagePool), pvPage);
    if (HCPhys == NIL_RTHCPHYS)
    {
        HCPhys = mmPagePoolPtr2Phys(pVM->mm.s.CTX_SUFF(pPagePoolLow), pvPage);
        if (HCPhys == NIL_RTHCPHYS)
        {
            STAM_COUNTER_INC(&pVM->mm.s.CTX_SUFF(pPagePool)->cErrors);
            AssertMsgFailed(("Invalid pvPage=%p specified\n", pvPage));
        }
    }
    return HCPhys;
}


#endif /* IN_RING3 */