VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/solaris/memobj-r0drv-solaris.c@ 78253

Last change on this file since 78253 was 78120, checked in by vboxsync, 6 years ago

IPRT: Started adding a RTR0MemObjMapUserEx function that takes offSub and cbSub. bugref:9217

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 40.4 KB
Line 
1/* $Id: memobj-r0drv-solaris.c 78120 2019-04-12 13:20:50Z vboxsync $ */
2/** @file
3 * IPRT - Ring-0 Memory Objects, Solaris.
4 */
5
6/*
7 * Copyright (C) 2006-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include "the-solaris-kernel.h"
32#include "internal/iprt.h"
33#include <iprt/memobj.h>
34
35#include <iprt/asm.h>
36#include <iprt/assert.h>
37#include <iprt/err.h>
38#include <iprt/log.h>
39#include <iprt/mem.h>
40#include <iprt/param.h>
41#include <iprt/process.h>
42#include "internal/memobj.h"
43#include "memobj-r0drv-solaris.h"
44
45
46/*********************************************************************************************************************************
47* Defined Constants And Macros *
48*********************************************************************************************************************************/
49#define SOL_IS_KRNL_ADDR(vx) ((uintptr_t)(vx) >= kernelbase)
50
51
52/*********************************************************************************************************************************
53* Structures and Typedefs *
54*********************************************************************************************************************************/
55/**
56 * The Solaris version of the memory object structure.
57 */
58typedef struct RTR0MEMOBJSOL
59{
60 /** The core structure. */
61 RTR0MEMOBJINTERNAL Core;
62 /** Pointer to kernel memory cookie. */
63 ddi_umem_cookie_t Cookie;
64 /** Shadow locked pages. */
65 void *pvHandle;
66 /** Access during locking. */
67 int fAccess;
68 /** Set if large pages are involved in an RTR0MEMOBJTYPE_PHYS
69 * allocation. */
70 bool fLargePage;
71 /** Whether we have individual pages or a kernel-mapped virtual memory block in
72 * an RTR0MEMOBJTYPE_PHYS_NC allocation. */
73 bool fIndivPages;
74} RTR0MEMOBJSOL, *PRTR0MEMOBJSOL;
75
76
77/*********************************************************************************************************************************
78* Global Variables *
79*********************************************************************************************************************************/
80static vnode_t g_PageVnode;
81static kmutex_t g_OffsetMtx;
82static u_offset_t g_offPage;
83
84static vnode_t g_LargePageVnode;
85static kmutex_t g_LargePageOffsetMtx;
86static u_offset_t g_offLargePage;
87static bool g_fLargePageNoReloc;
88
89
90/**
91 * Returns the physical address for a virtual address.
92 *
93 * @param pv The virtual address.
94 *
95 * @returns The physical address corresponding to @a pv.
96 */
97static uint64_t rtR0MemObjSolVirtToPhys(void *pv)
98{
99 struct hat *pHat = NULL;
100 pfn_t PageFrameNum = 0;
101 uintptr_t uVirtAddr = (uintptr_t)pv;
102
103 if (SOL_IS_KRNL_ADDR(pv))
104 pHat = kas.a_hat;
105 else
106 {
107 proc_t *pProcess = (proc_t *)RTR0ProcHandleSelf();
108 AssertRelease(pProcess);
109 pHat = pProcess->p_as->a_hat;
110 }
111
112 PageFrameNum = hat_getpfnum(pHat, (caddr_t)(uVirtAddr & PAGEMASK));
113 AssertReleaseMsg(PageFrameNum != PFN_INVALID, ("rtR0MemObjSolVirtToPhys failed. pv=%p\n", pv));
114 return (((uint64_t)PageFrameNum << PAGE_SHIFT) | (uVirtAddr & PAGE_OFFSET_MASK));
115}
116
117
118/**
119 * Returns the physical address for a page.
120 *
121 * @param pPage Pointer to the page.
122 *
123 * @returns The physical address for a page.
124 */
125static inline uint64_t rtR0MemObjSolPagePhys(page_t *pPage)
126{
127 AssertPtr(pPage);
128 pfn_t PageFrameNum = page_pptonum(pPage);
129 AssertReleaseMsg(PageFrameNum != PFN_INVALID, ("rtR0MemObjSolPagePhys failed pPage=%p\n"));
130 return (uint64_t)PageFrameNum << PAGE_SHIFT;
131}
132
133
134/**
135 * Allocates one page.
136 *
137 * @param virtAddr The virtual address to which this page maybe mapped in
138 * the future.
139 *
140 * @returns Pointer to the allocated page, NULL on failure.
141 */
142static page_t *rtR0MemObjSolPageAlloc(caddr_t virtAddr)
143{
144 u_offset_t offPage;
145 seg_t KernelSeg;
146
147 /*
148 * 16777215 terabytes of total memory for all VMs or
149 * restart 8000 1GB VMs 2147483 times until wraparound!
150 */
151 mutex_enter(&g_OffsetMtx);
152 AssertCompileSize(u_offset_t, sizeof(uint64_t)); NOREF(RTASSERTVAR);
153 g_offPage = RT_ALIGN_64(g_offPage, PAGE_SIZE) + PAGE_SIZE;
154 offPage = g_offPage;
155 mutex_exit(&g_OffsetMtx);
156
157 KernelSeg.s_as = &kas;
158 page_t *pPage = page_create_va(&g_PageVnode, offPage, PAGE_SIZE, PG_WAIT | PG_NORELOC, &KernelSeg, virtAddr);
159 if (RT_LIKELY(pPage))
160 {
161 /*
162 * Lock this page into memory "long term" to prevent this page from being paged out
163 * when we drop the page lock temporarily (during free). Downgrade to a shared lock
164 * to prevent page relocation.
165 */
166 page_pp_lock(pPage, 0 /* COW */, 1 /* Kernel */);
167 page_io_unlock(pPage);
168 page_downgrade(pPage);
169 Assert(PAGE_LOCKED_SE(pPage, SE_SHARED));
170 }
171
172 return pPage;
173}
174
175
176/**
177 * Destroys an allocated page.
178 *
179 * @param pPage Pointer to the page to be destroyed.
180 * @remarks This function expects page in @c pPage to be shared locked.
181 */
182static void rtR0MemObjSolPageDestroy(page_t *pPage)
183{
184 /*
185 * We need to exclusive lock the pages before freeing them, if upgrading the shared lock to exclusive fails,
186 * drop the page lock and look it up from the hash. Record the page offset before we drop the page lock as
187 * we cannot touch any page_t members once the lock is dropped.
188 */
189 AssertPtr(pPage);
190 Assert(PAGE_LOCKED_SE(pPage, SE_SHARED));
191
192 u_offset_t offPage = pPage->p_offset;
193 int rc = page_tryupgrade(pPage);
194 if (!rc)
195 {
196 page_unlock(pPage);
197 page_t *pFoundPage = page_lookup(&g_PageVnode, offPage, SE_EXCL);
198
199 /*
200 * Since we allocated the pages as PG_NORELOC we should only get back the exact page always.
201 */
202 AssertReleaseMsg(pFoundPage == pPage, ("Page lookup failed %p:%llx returned %p, expected %p\n",
203 &g_PageVnode, offPage, pFoundPage, pPage));
204 }
205 Assert(PAGE_LOCKED_SE(pPage, SE_EXCL));
206 page_pp_unlock(pPage, 0 /* COW */, 1 /* Kernel */);
207 page_destroy(pPage, 0 /* move it to the free list */);
208}
209
210
211/* Currently not used on 32-bits, define it to shut up gcc. */
212#if HC_ARCH_BITS == 64
213/**
214 * Allocates physical, non-contiguous memory of pages.
215 *
216 * @param puPhys Where to store the physical address of first page. Optional,
217 * can be NULL.
218 * @param cb The size of the allocation.
219 *
220 * @return Array of allocated pages, NULL on failure.
221 */
222static page_t **rtR0MemObjSolPagesAlloc(uint64_t *puPhys, size_t cb)
223{
224 /*
225 * VM1:
226 * The page freelist and cachelist both hold pages that are not mapped into any address space.
227 * The cachelist is not really free pages but when memory is exhausted they'll be moved to the
228 * free lists, it's the total of the free+cache list that we see on the 'free' column in vmstat.
229 *
230 * VM2:
231 * @todo Document what happens behind the scenes in VM2 regarding the free and cachelist.
232 */
233
234 /*
235 * Non-pageable memory reservation request for _4K pages, don't sleep.
236 */
237 size_t cPages = (cb + PAGE_SIZE - 1) >> PAGE_SHIFT;
238 int rc = page_resv(cPages, KM_NOSLEEP);
239 if (rc)
240 {
241 size_t cbPages = cPages * sizeof(page_t *);
242 page_t **ppPages = kmem_zalloc(cbPages, KM_SLEEP);
243 if (RT_LIKELY(ppPages))
244 {
245 /*
246 * Get pages from kseg, the 'virtAddr' here is only for colouring but unfortunately
247 * we don't yet have the 'virtAddr' to which this memory may be mapped.
248 */
249 caddr_t virtAddr = 0;
250 for (size_t i = 0; i < cPages; i++, virtAddr += PAGE_SIZE)
251 {
252 /*
253 * Get a page from the free list locked exclusively. The page will be named (hashed in)
254 * and we rely on it during free. The page we get will be shared locked to prevent the page
255 * from being relocated.
256 */
257 page_t *pPage = rtR0MemObjSolPageAlloc(virtAddr);
258 if (RT_UNLIKELY(!pPage))
259 {
260 /*
261 * No page found, release whatever pages we grabbed so far.
262 */
263 for (size_t k = 0; k < i; k++)
264 rtR0MemObjSolPageDestroy(ppPages[k]);
265 kmem_free(ppPages, cbPages);
266 page_unresv(cPages);
267 return NULL;
268 }
269
270 ppPages[i] = pPage;
271 }
272
273 if (puPhys)
274 *puPhys = rtR0MemObjSolPagePhys(ppPages[0]);
275 return ppPages;
276 }
277
278 page_unresv(cPages);
279 }
280
281 return NULL;
282}
283#endif /* HC_ARCH_BITS == 64 */
284
285
286/**
287 * Frees the allocates pages.
288 *
289 * @param ppPages Pointer to the page list.
290 * @param cbPages Size of the allocation.
291 */
292static void rtR0MemObjSolPagesFree(page_t **ppPages, size_t cb)
293{
294 size_t cPages = (cb + PAGE_SIZE - 1) >> PAGE_SHIFT;
295 size_t cbPages = cPages * sizeof(page_t *);
296 for (size_t iPage = 0; iPage < cPages; iPage++)
297 rtR0MemObjSolPageDestroy(ppPages[iPage]);
298
299 kmem_free(ppPages, cbPages);
300 page_unresv(cPages);
301}
302
303
304/**
305 * Allocates one large page.
306 *
307 * @param puPhys Where to store the physical address of the allocated
308 * page. Optional, can be NULL.
309 * @param cbLargePage Size of the large page.
310 *
311 * @returns Pointer to a list of pages that cover the large page, NULL on
312 * failure.
313 */
314static page_t **rtR0MemObjSolLargePageAlloc(uint64_t *puPhys, size_t cbLargePage)
315{
316 /*
317 * Check PG_NORELOC support for large pages. Using this helps prevent _1G page
318 * fragementation on systems that support it.
319 */
320 static bool fPageNoRelocChecked = false;
321 if (fPageNoRelocChecked == false)
322 {
323 fPageNoRelocChecked = true;
324 g_fLargePageNoReloc = false;
325 if ( g_pfnrtR0Sol_page_noreloc_supported
326 && g_pfnrtR0Sol_page_noreloc_supported(cbLargePage))
327 {
328 g_fLargePageNoReloc = true;
329 }
330 }
331
332 /*
333 * Non-pageable memory reservation request for _4K pages, don't sleep.
334 */
335 size_t cPages = (cbLargePage + PAGE_SIZE - 1) >> PAGE_SHIFT;
336 size_t cbPages = cPages * sizeof(page_t *);
337 u_offset_t offPage = 0;
338 int rc = page_resv(cPages, KM_NOSLEEP);
339 if (rc)
340 {
341 page_t **ppPages = kmem_zalloc(cbPages, KM_SLEEP);
342 if (RT_LIKELY(ppPages))
343 {
344 mutex_enter(&g_LargePageOffsetMtx);
345 AssertCompileSize(u_offset_t, sizeof(uint64_t)); NOREF(RTASSERTVAR);
346 g_offLargePage = RT_ALIGN_64(g_offLargePage, cbLargePage) + cbLargePage;
347 offPage = g_offLargePage;
348 mutex_exit(&g_LargePageOffsetMtx);
349
350 seg_t KernelSeg;
351 KernelSeg.s_as = &kas;
352 page_t *pRootPage = page_create_va_large(&g_LargePageVnode, offPage, cbLargePage,
353 PG_EXCL | (g_fLargePageNoReloc ? PG_NORELOC : 0), &KernelSeg,
354 0 /* vaddr */,NULL /* locality group */);
355 if (pRootPage)
356 {
357 /*
358 * Split it into sub-pages, downgrade each page to a shared lock to prevent page relocation.
359 */
360 page_t *pPageList = pRootPage;
361 for (size_t iPage = 0; iPage < cPages; iPage++)
362 {
363 page_t *pPage = pPageList;
364 AssertPtr(pPage);
365 AssertMsg(page_pptonum(pPage) == iPage + page_pptonum(pRootPage),
366 ("%p:%lx %lx+%lx\n", pPage, page_pptonum(pPage), iPage, page_pptonum(pRootPage)));
367 AssertMsg(pPage->p_szc == pRootPage->p_szc, ("Size code mismatch %p %d %d\n", pPage,
368 (int)pPage->p_szc, (int)pRootPage->p_szc));
369
370 /*
371 * Lock the page into memory "long term". This prevents callers of page_try_demote_pages() (such as the
372 * pageout scanner) from demoting the large page into smaller pages while we temporarily release the
373 * exclusive lock (during free). We pass "0, 1" since we've already accounted for availrmem during
374 * page_resv().
375 */
376 page_pp_lock(pPage, 0 /* COW */, 1 /* Kernel */);
377
378 page_sub(&pPageList, pPage);
379 page_io_unlock(pPage);
380 page_downgrade(pPage);
381 Assert(PAGE_LOCKED_SE(pPage, SE_SHARED));
382
383 ppPages[iPage] = pPage;
384 }
385 Assert(pPageList == NULL);
386 Assert(ppPages[0] == pRootPage);
387
388 uint64_t uPhys = rtR0MemObjSolPagePhys(pRootPage);
389 AssertMsg(!(uPhys & (cbLargePage - 1)), ("%llx %zx\n", uPhys, cbLargePage));
390 if (puPhys)
391 *puPhys = uPhys;
392 return ppPages;
393 }
394
395 /*
396 * Don't restore offPrev in case of failure (race condition), we have plenty of offset space.
397 * The offset must be unique (for the same vnode) or we'll encounter panics on page_create_va_large().
398 */
399 kmem_free(ppPages, cbPages);
400 }
401
402 page_unresv(cPages);
403 }
404 return NULL;
405}
406
407
408/**
409 * Frees the large page.
410 *
411 * @param ppPages Pointer to the list of small pages that cover the
412 * large page.
413 * @param cbLargePage Size of the allocation (i.e. size of the large
414 * page).
415 */
416static void rtR0MemObjSolLargePageFree(page_t **ppPages, size_t cbLargePage)
417{
418 Assert(ppPages);
419 Assert(cbLargePage > PAGE_SIZE);
420
421 bool fDemoted = false;
422 size_t cPages = (cbLargePage + PAGE_SIZE - 1) >> PAGE_SHIFT;
423 size_t cbPages = cPages * sizeof(page_t *);
424 page_t *pPageList = ppPages[0];
425
426 for (size_t iPage = 0; iPage < cPages; iPage++)
427 {
428 /*
429 * We need the pages exclusively locked, try upgrading the shared lock.
430 * If it fails, drop the shared page lock (cannot access any page_t members once this is done)
431 * and lookup the page from the page hash locking it exclusively.
432 */
433 page_t *pPage = ppPages[iPage];
434 u_offset_t offPage = pPage->p_offset;
435 int rc = page_tryupgrade(pPage);
436 if (!rc)
437 {
438 page_unlock(pPage);
439 page_t *pFoundPage = page_lookup(&g_LargePageVnode, offPage, SE_EXCL);
440 AssertRelease(pFoundPage);
441
442 if (g_fLargePageNoReloc)
443 {
444 /*
445 * This can only be guaranteed if PG_NORELOC is used while allocating the pages.
446 */
447 AssertReleaseMsg(pFoundPage == pPage,
448 ("lookup failed %p:%llu returned %p, expected %p\n", &g_LargePageVnode, offPage,
449 pFoundPage, pPage));
450 }
451
452 /*
453 * Check for page demotion (regardless of relocation). Some places in Solaris (e.g. VM1 page_retire())
454 * could possibly demote the large page to _4K pages between our call to page_unlock() and page_lookup().
455 */
456 if (page_get_pagecnt(pFoundPage->p_szc) == 1) /* Base size of only _4K associated with this page. */
457 fDemoted = true;
458 pPage = pFoundPage;
459 ppPages[iPage] = pFoundPage;
460 }
461 Assert(PAGE_LOCKED_SE(pPage, SE_EXCL));
462 page_pp_unlock(pPage, 0 /* COW */, 1 /* Kernel */);
463 }
464
465 if (fDemoted)
466 {
467 for (size_t iPage = 0; iPage < cPages; iPage++)
468 {
469 Assert(page_get_pagecnt(ppPages[iPage]->p_szc) == 1);
470 page_destroy(ppPages[iPage], 0 /* move it to the free list */);
471 }
472 }
473 else
474 {
475 /*
476 * Although we shred the adjacent pages in the linked list, page_destroy_pages works on
477 * adjacent pages via array increments. So this does indeed free all the pages.
478 */
479 AssertPtr(pPageList);
480 page_destroy_pages(pPageList);
481 }
482 kmem_free(ppPages, cbPages);
483 page_unresv(cPages);
484}
485
486
487/**
488 * Unmaps kernel/user-space mapped memory.
489 *
490 * @param pv Pointer to the mapped memory block.
491 * @param cb Size of the memory block.
492 */
493static void rtR0MemObjSolUnmap(void *pv, size_t cb)
494{
495 if (SOL_IS_KRNL_ADDR(pv))
496 {
497 hat_unload(kas.a_hat, pv, cb, HAT_UNLOAD | HAT_UNLOAD_UNLOCK);
498 vmem_free(heap_arena, pv, cb);
499 }
500 else
501 {
502 struct as *pAddrSpace = ((proc_t *)RTR0ProcHandleSelf())->p_as;
503 AssertPtr(pAddrSpace);
504 as_rangelock(pAddrSpace);
505 as_unmap(pAddrSpace, pv, cb);
506 as_rangeunlock(pAddrSpace);
507 }
508}
509
510
511/**
512 * Lock down memory mappings for a virtual address.
513 *
514 * @param pv Pointer to the memory to lock down.
515 * @param cb Size of the memory block.
516 * @param fAccess Page access rights (S_READ, S_WRITE, S_EXEC)
517 *
518 * @returns IPRT status code.
519 */
520static int rtR0MemObjSolLock(void *pv, size_t cb, int fPageAccess)
521{
522 /*
523 * Kernel memory mappings on x86/amd64 are always locked, only handle user-space memory.
524 */
525 if (!SOL_IS_KRNL_ADDR(pv))
526 {
527 proc_t *pProc = (proc_t *)RTR0ProcHandleSelf();
528 AssertPtr(pProc);
529 faultcode_t rc = as_fault(pProc->p_as->a_hat, pProc->p_as, (caddr_t)pv, cb, F_SOFTLOCK, fPageAccess);
530 if (rc)
531 {
532 LogRel(("rtR0MemObjSolLock failed for pv=%pv cb=%lx fPageAccess=%d rc=%d\n", pv, cb, fPageAccess, rc));
533 return VERR_LOCK_FAILED;
534 }
535 }
536 return VINF_SUCCESS;
537}
538
539
540/**
541 * Unlock memory mappings for a virtual address.
542 *
543 * @param pv Pointer to the locked memory.
544 * @param cb Size of the memory block.
545 * @param fPageAccess Page access rights (S_READ, S_WRITE, S_EXEC).
546 */
547static void rtR0MemObjSolUnlock(void *pv, size_t cb, int fPageAccess)
548{
549 if (!SOL_IS_KRNL_ADDR(pv))
550 {
551 proc_t *pProcess = (proc_t *)RTR0ProcHandleSelf();
552 AssertPtr(pProcess);
553 as_fault(pProcess->p_as->a_hat, pProcess->p_as, (caddr_t)pv, cb, F_SOFTUNLOCK, fPageAccess);
554 }
555}
556
557
558/**
559 * Maps a list of physical pages into user address space.
560 *
561 * @param pVirtAddr Where to store the virtual address of the mapping.
562 * @param fPageAccess Page access rights (PROT_READ, PROT_WRITE,
563 * PROT_EXEC)
564 * @param paPhysAddrs Array of physical addresses to pages.
565 * @param cb Size of memory being mapped.
566 *
567 * @returns IPRT status code.
568 */
569static int rtR0MemObjSolUserMap(caddr_t *pVirtAddr, unsigned fPageAccess, uint64_t *paPhysAddrs, size_t cb, size_t cbPageSize)
570{
571 struct as *pAddrSpace = ((proc_t *)RTR0ProcHandleSelf())->p_as;
572 int rc = VERR_INTERNAL_ERROR;
573 SEGVBOX_CRARGS Args;
574
575 Args.paPhysAddrs = paPhysAddrs;
576 Args.fPageAccess = fPageAccess;
577 Args.cbPageSize = cbPageSize;
578
579 as_rangelock(pAddrSpace);
580 map_addr(pVirtAddr, cb, 0 /* offset */, 0 /* vacalign */, MAP_SHARED);
581 if (*pVirtAddr != NULL)
582 rc = as_map(pAddrSpace, *pVirtAddr, cb, rtR0SegVBoxSolCreate, &Args);
583 else
584 rc = ENOMEM;
585 as_rangeunlock(pAddrSpace);
586
587 return RTErrConvertFromErrno(rc);
588}
589
590
591DECLHIDDEN(int) rtR0MemObjNativeFree(RTR0MEMOBJ pMem)
592{
593 PRTR0MEMOBJSOL pMemSolaris = (PRTR0MEMOBJSOL)pMem;
594
595 switch (pMemSolaris->Core.enmType)
596 {
597 case RTR0MEMOBJTYPE_LOW:
598 rtR0SolMemFree(pMemSolaris->Core.pv, pMemSolaris->Core.cb);
599 break;
600
601 case RTR0MEMOBJTYPE_PHYS:
602 if (pMemSolaris->Core.u.Phys.fAllocated)
603 {
604 if (pMemSolaris->fLargePage)
605 rtR0MemObjSolLargePageFree(pMemSolaris->pvHandle, pMemSolaris->Core.cb);
606 else
607 rtR0SolMemFree(pMemSolaris->Core.pv, pMemSolaris->Core.cb);
608 }
609 break;
610
611 case RTR0MEMOBJTYPE_PHYS_NC:
612 if (pMemSolaris->fIndivPages)
613 rtR0MemObjSolPagesFree(pMemSolaris->pvHandle, pMemSolaris->Core.cb);
614 else
615 rtR0SolMemFree(pMemSolaris->Core.pv, pMemSolaris->Core.cb);
616 break;
617
618 case RTR0MEMOBJTYPE_PAGE:
619 ddi_umem_free(pMemSolaris->Cookie);
620 break;
621
622 case RTR0MEMOBJTYPE_LOCK:
623 rtR0MemObjSolUnlock(pMemSolaris->Core.pv, pMemSolaris->Core.cb, pMemSolaris->fAccess);
624 break;
625
626 case RTR0MEMOBJTYPE_MAPPING:
627 rtR0MemObjSolUnmap(pMemSolaris->Core.pv, pMemSolaris->Core.cb);
628 break;
629
630 case RTR0MEMOBJTYPE_RES_VIRT:
631 {
632 if (pMemSolaris->Core.u.ResVirt.R0Process == NIL_RTR0PROCESS)
633 vmem_xfree(heap_arena, pMemSolaris->Core.pv, pMemSolaris->Core.cb);
634 else
635 AssertFailed();
636 break;
637 }
638
639 case RTR0MEMOBJTYPE_CONT: /* we don't use this type here. */
640 default:
641 AssertMsgFailed(("enmType=%d\n", pMemSolaris->Core.enmType));
642 return VERR_INTERNAL_ERROR;
643 }
644
645 return VINF_SUCCESS;
646}
647
648
649DECLHIDDEN(int) rtR0MemObjNativeAllocPage(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
650{
651 /* Create the object. */
652 PRTR0MEMOBJSOL pMemSolaris = (PRTR0MEMOBJSOL)rtR0MemObjNew(sizeof(*pMemSolaris), RTR0MEMOBJTYPE_PAGE, NULL, cb);
653 if (RT_UNLIKELY(!pMemSolaris))
654 return VERR_NO_MEMORY;
655
656 void *pvMem = ddi_umem_alloc(cb, DDI_UMEM_SLEEP, &pMemSolaris->Cookie);
657 if (RT_UNLIKELY(!pvMem))
658 {
659 rtR0MemObjDelete(&pMemSolaris->Core);
660 return VERR_NO_PAGE_MEMORY;
661 }
662
663 pMemSolaris->Core.pv = pvMem;
664 pMemSolaris->pvHandle = NULL;
665 *ppMem = &pMemSolaris->Core;
666 return VINF_SUCCESS;
667}
668
669
670DECLHIDDEN(int) rtR0MemObjNativeAllocLow(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
671{
672 NOREF(fExecutable);
673
674 /* Create the object */
675 PRTR0MEMOBJSOL pMemSolaris = (PRTR0MEMOBJSOL)rtR0MemObjNew(sizeof(*pMemSolaris), RTR0MEMOBJTYPE_LOW, NULL, cb);
676 if (!pMemSolaris)
677 return VERR_NO_MEMORY;
678
679 /* Allocate physically low page-aligned memory. */
680 uint64_t uPhysHi = _4G - 1;
681 void *pvMem = rtR0SolMemAlloc(uPhysHi, NULL /* puPhys */, cb, PAGE_SIZE, false /* fContig */);
682 if (RT_UNLIKELY(!pvMem))
683 {
684 rtR0MemObjDelete(&pMemSolaris->Core);
685 return VERR_NO_LOW_MEMORY;
686 }
687 pMemSolaris->Core.pv = pvMem;
688 pMemSolaris->pvHandle = NULL;
689 *ppMem = &pMemSolaris->Core;
690 return VINF_SUCCESS;
691}
692
693
694DECLHIDDEN(int) rtR0MemObjNativeAllocCont(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
695{
696 NOREF(fExecutable);
697 return rtR0MemObjNativeAllocPhys(ppMem, cb, _4G - 1, PAGE_SIZE /* alignment */);
698}
699
700
701DECLHIDDEN(int) rtR0MemObjNativeAllocPhysNC(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, RTHCPHYS PhysHighest)
702{
703#if HC_ARCH_BITS == 64
704 PRTR0MEMOBJSOL pMemSolaris = (PRTR0MEMOBJSOL)rtR0MemObjNew(sizeof(*pMemSolaris), RTR0MEMOBJTYPE_PHYS_NC, NULL, cb);
705 if (RT_UNLIKELY(!pMemSolaris))
706 return VERR_NO_MEMORY;
707
708 if (PhysHighest == NIL_RTHCPHYS)
709 {
710 uint64_t PhysAddr = UINT64_MAX;
711 void *pvPages = rtR0MemObjSolPagesAlloc(&PhysAddr, cb);
712 if (!pvPages)
713 {
714 LogRel(("rtR0MemObjNativeAllocPhysNC: rtR0MemObjSolPagesAlloc failed for cb=%u.\n", cb));
715 rtR0MemObjDelete(&pMemSolaris->Core);
716 return VERR_NO_MEMORY;
717 }
718 Assert(PhysAddr != UINT64_MAX);
719 Assert(!(PhysAddr & PAGE_OFFSET_MASK));
720
721 pMemSolaris->Core.pv = NULL;
722 pMemSolaris->pvHandle = pvPages;
723 pMemSolaris->fIndivPages = true;
724 *ppMem = &pMemSolaris->Core;
725 return VINF_SUCCESS;
726 }
727 else
728 {
729 /*
730 * If we must satisfy an upper limit constraint, it isn't feasible to grab individual pages.
731 * We fall back to using contig_alloc().
732 */
733 uint64_t PhysAddr = UINT64_MAX;
734 void *pvMem = rtR0SolMemAlloc(PhysHighest, &PhysAddr, cb, PAGE_SIZE, false /* fContig */);
735 if (!pvMem)
736 {
737 LogRel(("rtR0MemObjNativeAllocPhysNC: rtR0SolMemAlloc failed for cb=%u PhysHighest=%RHp.\n", cb, PhysHighest));
738 rtR0MemObjDelete(&pMemSolaris->Core);
739 return VERR_NO_MEMORY;
740 }
741 Assert(PhysAddr != UINT64_MAX);
742 Assert(!(PhysAddr & PAGE_OFFSET_MASK));
743
744 pMemSolaris->Core.pv = pvMem;
745 pMemSolaris->pvHandle = NULL;
746 pMemSolaris->fIndivPages = false;
747 *ppMem = &pMemSolaris->Core;
748 return VINF_SUCCESS;
749 }
750
751#else /* 32 bit: */
752 return VERR_NOT_SUPPORTED; /* see the RTR0MemObjAllocPhysNC specs */
753#endif
754}
755
756
757DECLHIDDEN(int) rtR0MemObjNativeAllocPhys(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, RTHCPHYS PhysHighest, size_t uAlignment)
758{
759 AssertMsgReturn(PhysHighest >= 16 *_1M, ("PhysHigest=%RHp\n", PhysHighest), VERR_NOT_SUPPORTED);
760
761 PRTR0MEMOBJSOL pMemSolaris = (PRTR0MEMOBJSOL)rtR0MemObjNew(sizeof(*pMemSolaris), RTR0MEMOBJTYPE_PHYS, NULL, cb);
762 if (RT_UNLIKELY(!pMemSolaris))
763 return VERR_NO_MEMORY;
764
765 /*
766 * Allocating one large page gets special treatment.
767 */
768 static uint32_t s_cbLargePage = UINT32_MAX;
769 if (s_cbLargePage == UINT32_MAX)
770 {
771 if (page_num_pagesizes() > 1)
772 ASMAtomicWriteU32(&s_cbLargePage, page_get_pagesize(1)); /* Page-size code 1 maps to _2M on Solaris x86/amd64. */
773 else
774 ASMAtomicWriteU32(&s_cbLargePage, 0);
775 }
776
777 uint64_t PhysAddr;
778 if ( cb == s_cbLargePage
779 && cb == uAlignment
780 && PhysHighest == NIL_RTHCPHYS)
781 {
782 /*
783 * Allocate one large page (backed by physically contiguous memory).
784 */
785 void *pvPages = rtR0MemObjSolLargePageAlloc(&PhysAddr, cb);
786 if (RT_LIKELY(pvPages))
787 {
788 AssertMsg(!(PhysAddr & (cb - 1)), ("%RHp\n", PhysAddr));
789 pMemSolaris->Core.pv = NULL;
790 pMemSolaris->Core.u.Phys.PhysBase = PhysAddr;
791 pMemSolaris->Core.u.Phys.fAllocated = true;
792 pMemSolaris->pvHandle = pvPages;
793 pMemSolaris->fLargePage = true;
794
795 *ppMem = &pMemSolaris->Core;
796 return VINF_SUCCESS;
797 }
798 }
799 else
800 {
801 /*
802 * Allocate physically contiguous memory aligned as specified.
803 */
804 AssertCompile(NIL_RTHCPHYS == UINT64_MAX); NOREF(RTASSERTVAR);
805 PhysAddr = PhysHighest;
806 void *pvMem = rtR0SolMemAlloc(PhysHighest, &PhysAddr, cb, uAlignment, true /* fContig */);
807 if (RT_LIKELY(pvMem))
808 {
809 Assert(!(PhysAddr & PAGE_OFFSET_MASK));
810 Assert(PhysAddr < PhysHighest);
811 Assert(PhysAddr + cb <= PhysHighest);
812
813 pMemSolaris->Core.pv = pvMem;
814 pMemSolaris->Core.u.Phys.PhysBase = PhysAddr;
815 pMemSolaris->Core.u.Phys.fAllocated = true;
816 pMemSolaris->pvHandle = NULL;
817 pMemSolaris->fLargePage = false;
818
819 *ppMem = &pMemSolaris->Core;
820 return VINF_SUCCESS;
821 }
822 }
823 rtR0MemObjDelete(&pMemSolaris->Core);
824 return VERR_NO_CONT_MEMORY;
825}
826
827
828DECLHIDDEN(int) rtR0MemObjNativeEnterPhys(PPRTR0MEMOBJINTERNAL ppMem, RTHCPHYS Phys, size_t cb, uint32_t uCachePolicy)
829{
830 AssertReturn(uCachePolicy == RTMEM_CACHE_POLICY_DONT_CARE, VERR_NOT_SUPPORTED);
831
832 /* Create the object. */
833 PRTR0MEMOBJSOL pMemSolaris = (PRTR0MEMOBJSOL)rtR0MemObjNew(sizeof(*pMemSolaris), RTR0MEMOBJTYPE_PHYS, NULL, cb);
834 if (!pMemSolaris)
835 return VERR_NO_MEMORY;
836
837 /* There is no allocation here, it needs to be mapped somewhere first. */
838 pMemSolaris->Core.u.Phys.fAllocated = false;
839 pMemSolaris->Core.u.Phys.PhysBase = Phys;
840 pMemSolaris->Core.u.Phys.uCachePolicy = uCachePolicy;
841 *ppMem = &pMemSolaris->Core;
842 return VINF_SUCCESS;
843}
844
845
846DECLHIDDEN(int) rtR0MemObjNativeLockUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3Ptr, size_t cb, uint32_t fAccess,
847 RTR0PROCESS R0Process)
848{
849 AssertReturn(R0Process == RTR0ProcHandleSelf(), VERR_INVALID_PARAMETER);
850 NOREF(fAccess);
851
852 /* Create the locking object */
853 PRTR0MEMOBJSOL pMemSolaris = (PRTR0MEMOBJSOL)rtR0MemObjNew(sizeof(*pMemSolaris), RTR0MEMOBJTYPE_LOCK, (void *)R3Ptr, cb);
854 if (!pMemSolaris)
855 return VERR_NO_MEMORY;
856
857 /* Lock down user pages. */
858 int fPageAccess = S_READ;
859 if (fAccess & RTMEM_PROT_WRITE)
860 fPageAccess = S_WRITE;
861 if (fAccess & RTMEM_PROT_EXEC)
862 fPageAccess = S_EXEC;
863 int rc = rtR0MemObjSolLock((void *)R3Ptr, cb, fPageAccess);
864 if (RT_FAILURE(rc))
865 {
866 LogRel(("rtR0MemObjNativeLockUser: rtR0MemObjSolLock failed rc=%d\n", rc));
867 rtR0MemObjDelete(&pMemSolaris->Core);
868 return rc;
869 }
870
871 /* Fill in the object attributes and return successfully. */
872 pMemSolaris->Core.u.Lock.R0Process = R0Process;
873 pMemSolaris->pvHandle = NULL;
874 pMemSolaris->fAccess = fPageAccess;
875 *ppMem = &pMemSolaris->Core;
876 return VINF_SUCCESS;
877}
878
879
880DECLHIDDEN(int) rtR0MemObjNativeLockKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pv, size_t cb, uint32_t fAccess)
881{
882 NOREF(fAccess);
883
884 PRTR0MEMOBJSOL pMemSolaris = (PRTR0MEMOBJSOL)rtR0MemObjNew(sizeof(*pMemSolaris), RTR0MEMOBJTYPE_LOCK, pv, cb);
885 if (!pMemSolaris)
886 return VERR_NO_MEMORY;
887
888 /* Lock down kernel pages. */
889 int fPageAccess = S_READ;
890 if (fAccess & RTMEM_PROT_WRITE)
891 fPageAccess = S_WRITE;
892 if (fAccess & RTMEM_PROT_EXEC)
893 fPageAccess = S_EXEC;
894 int rc = rtR0MemObjSolLock(pv, cb, fPageAccess);
895 if (RT_FAILURE(rc))
896 {
897 LogRel(("rtR0MemObjNativeLockKernel: rtR0MemObjSolLock failed rc=%d\n", rc));
898 rtR0MemObjDelete(&pMemSolaris->Core);
899 return rc;
900 }
901
902 /* Fill in the object attributes and return successfully. */
903 pMemSolaris->Core.u.Lock.R0Process = NIL_RTR0PROCESS;
904 pMemSolaris->pvHandle = NULL;
905 pMemSolaris->fAccess = fPageAccess;
906 *ppMem = &pMemSolaris->Core;
907 return VINF_SUCCESS;
908}
909
910
911DECLHIDDEN(int) rtR0MemObjNativeReserveKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pvFixed, size_t cb, size_t uAlignment)
912{
913 PRTR0MEMOBJSOL pMemSolaris;
914
915 /*
916 * Use xalloc.
917 */
918 void *pv = vmem_xalloc(heap_arena, cb, uAlignment, 0 /* phase */, 0 /* nocross */,
919 NULL /* minaddr */, NULL /* maxaddr */, VM_SLEEP);
920 if (RT_UNLIKELY(!pv))
921 return VERR_NO_MEMORY;
922
923 /* Create the object. */
924 pMemSolaris = (PRTR0MEMOBJSOL)rtR0MemObjNew(sizeof(*pMemSolaris), RTR0MEMOBJTYPE_RES_VIRT, pv, cb);
925 if (!pMemSolaris)
926 {
927 LogRel(("rtR0MemObjNativeReserveKernel failed to alloc memory object.\n"));
928 vmem_xfree(heap_arena, pv, cb);
929 return VERR_NO_MEMORY;
930 }
931
932 pMemSolaris->Core.u.ResVirt.R0Process = NIL_RTR0PROCESS;
933 *ppMem = &pMemSolaris->Core;
934 return VINF_SUCCESS;
935}
936
937
938DECLHIDDEN(int) rtR0MemObjNativeReserveUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3PtrFixed, size_t cb, size_t uAlignment,
939 RTR0PROCESS R0Process)
940{
941 return VERR_NOT_SUPPORTED;
942}
943
944
945DECLHIDDEN(int) rtR0MemObjNativeMapKernel(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ pMemToMap, void *pvFixed, size_t uAlignment,
946 unsigned fProt, size_t offSub, size_t cbSub)
947{
948 /* Fail if requested to do something we can't. */
949 AssertMsgReturn(pvFixed == (void *)-1, ("%p\n", pvFixed), VERR_NOT_SUPPORTED);
950 if (uAlignment > PAGE_SIZE)
951 return VERR_NOT_SUPPORTED;
952
953 /*
954 * Use xalloc to get address space.
955 */
956 if (!cbSub)
957 cbSub = pMemToMap->cb;
958 void *pv = vmem_xalloc(heap_arena, cbSub, uAlignment, 0 /* phase */, 0 /* nocross */,
959 NULL /* minaddr */, NULL /* maxaddr */, VM_SLEEP);
960 if (RT_UNLIKELY(!pv))
961 return VERR_MAP_FAILED;
962
963 /*
964 * Load the pages from the other object into it.
965 */
966 uint32_t fAttr = HAT_UNORDERED_OK | HAT_MERGING_OK | HAT_LOADCACHING_OK | HAT_STORECACHING_OK;
967 if (fProt & RTMEM_PROT_READ)
968 fAttr |= PROT_READ;
969 if (fProt & RTMEM_PROT_EXEC)
970 fAttr |= PROT_EXEC;
971 if (fProt & RTMEM_PROT_WRITE)
972 fAttr |= PROT_WRITE;
973 fAttr |= HAT_NOSYNC;
974
975 int rc = VINF_SUCCESS;
976 size_t off = 0;
977 while (off < cbSub)
978 {
979 RTHCPHYS HCPhys = RTR0MemObjGetPagePhysAddr(pMemToMap, (offSub + offSub) >> PAGE_SHIFT);
980 AssertBreakStmt(HCPhys != NIL_RTHCPHYS, rc = VERR_INTERNAL_ERROR_2);
981 pfn_t pfn = HCPhys >> PAGE_SHIFT;
982 AssertBreakStmt(((RTHCPHYS)pfn << PAGE_SHIFT) == HCPhys, rc = VERR_INTERNAL_ERROR_3);
983
984 hat_devload(kas.a_hat, (uint8_t *)pv + off, PAGE_SIZE, pfn, fAttr, HAT_LOAD_LOCK);
985
986 /* Advance. */
987 off += PAGE_SIZE;
988 }
989 if (RT_SUCCESS(rc))
990 {
991 /*
992 * Create a memory object for the mapping.
993 */
994 PRTR0MEMOBJSOL pMemSolaris = (PRTR0MEMOBJSOL)rtR0MemObjNew(sizeof(*pMemSolaris), RTR0MEMOBJTYPE_MAPPING, pv, cbSub);
995 if (pMemSolaris)
996 {
997 pMemSolaris->Core.u.Mapping.R0Process = NIL_RTR0PROCESS;
998 *ppMem = &pMemSolaris->Core;
999 return VINF_SUCCESS;
1000 }
1001
1002 LogRel(("rtR0MemObjNativeMapKernel failed to alloc memory object.\n"));
1003 rc = VERR_NO_MEMORY;
1004 }
1005
1006 if (off)
1007 hat_unload(kas.a_hat, pv, off, HAT_UNLOAD | HAT_UNLOAD_UNLOCK);
1008 vmem_xfree(heap_arena, pv, cbSub);
1009 return rc;
1010}
1011
1012
1013DECLHIDDEN(int) rtR0MemObjNativeMapUser(PPRTR0MEMOBJINTERNAL ppMem, PRTR0MEMOBJINTERNAL pMemToMap, RTR3PTR R3PtrFixed,
1014 size_t uAlignment, unsigned fProt, RTR0PROCESS R0Process, size_t offSub, size_t cbSub)
1015{
1016 /*
1017 * Fend off things we cannot do.
1018 */
1019 AssertMsgReturn(R3PtrFixed == (RTR3PTR)-1, ("%p\n", R3PtrFixed), VERR_NOT_SUPPORTED);
1020 AssertMsgReturn(R0Process == RTR0ProcHandleSelf(), ("%p != %p\n", R0Process, RTR0ProcHandleSelf()), VERR_NOT_SUPPORTED);
1021 if (uAlignment != PAGE_SIZE)
1022 return VERR_NOT_SUPPORTED;
1023 AssertMsgReturn(!offSub && !cbSub, ("%#zx %#zx\n", offSub, cbSub), VERR_NOT_SUPPORTED); /** @todo implement sub maps */
1024
1025 /*
1026 * Get parameters from the source object.
1027 */
1028 PRTR0MEMOBJSOL pMemToMapSolaris = (PRTR0MEMOBJSOL)pMemToMap;
1029 void *pv = pMemToMapSolaris->Core.pv;
1030 size_t cb = pMemToMapSolaris->Core.cb;
1031 size_t cPages = (cb + PAGE_SIZE - 1) >> PAGE_SHIFT;
1032
1033 /*
1034 * Create the mapping object
1035 */
1036 PRTR0MEMOBJSOL pMemSolaris;
1037 pMemSolaris = (PRTR0MEMOBJSOL)rtR0MemObjNew(sizeof(*pMemSolaris), RTR0MEMOBJTYPE_MAPPING, pv, cb);
1038 if (RT_UNLIKELY(!pMemSolaris))
1039 return VERR_NO_MEMORY;
1040
1041 int rc = VINF_SUCCESS;
1042 uint64_t *paPhysAddrs = kmem_zalloc(sizeof(uint64_t) * cPages, KM_SLEEP);
1043 if (RT_LIKELY(paPhysAddrs))
1044 {
1045 /*
1046 * Prepare the pages for mapping according to type.
1047 */
1048 if ( pMemToMapSolaris->Core.enmType == RTR0MEMOBJTYPE_PHYS_NC
1049 && pMemToMapSolaris->fIndivPages)
1050 {
1051 page_t **ppPages = pMemToMapSolaris->pvHandle;
1052 AssertPtr(ppPages);
1053 for (size_t iPage = 0; iPage < cPages; iPage++)
1054 paPhysAddrs[iPage] = rtR0MemObjSolPagePhys(ppPages[iPage]);
1055 }
1056 else if ( pMemToMapSolaris->Core.enmType == RTR0MEMOBJTYPE_PHYS
1057 && pMemToMapSolaris->fLargePage)
1058 {
1059 RTHCPHYS Phys = pMemToMapSolaris->Core.u.Phys.PhysBase;
1060 for (size_t iPage = 0; iPage < cPages; iPage++, Phys += PAGE_SIZE)
1061 paPhysAddrs[iPage] = Phys;
1062 }
1063 else
1064 {
1065 /*
1066 * Have kernel mapping, just translate virtual to physical.
1067 */
1068 AssertPtr(pv);
1069 rc = VINF_SUCCESS;
1070 for (size_t iPage = 0; iPage < cPages; iPage++)
1071 {
1072 paPhysAddrs[iPage] = rtR0MemObjSolVirtToPhys(pv);
1073 if (RT_UNLIKELY(paPhysAddrs[iPage] == -(uint64_t)1))
1074 {
1075 LogRel(("rtR0MemObjNativeMapUser: no page to map.\n"));
1076 rc = VERR_MAP_FAILED;
1077 break;
1078 }
1079 pv = (void *)((uintptr_t)pv + PAGE_SIZE);
1080 }
1081 }
1082 if (RT_SUCCESS(rc))
1083 {
1084 unsigned fPageAccess = PROT_READ;
1085 if (fProt & RTMEM_PROT_WRITE)
1086 fPageAccess |= PROT_WRITE;
1087 if (fProt & RTMEM_PROT_EXEC)
1088 fPageAccess |= PROT_EXEC;
1089
1090 /*
1091 * Perform the actual mapping.
1092 */
1093 caddr_t UserAddr = NULL;
1094 rc = rtR0MemObjSolUserMap(&UserAddr, fPageAccess, paPhysAddrs, cb, PAGE_SIZE);
1095 if (RT_SUCCESS(rc))
1096 {
1097 pMemSolaris->Core.u.Mapping.R0Process = R0Process;
1098 pMemSolaris->Core.pv = UserAddr;
1099
1100 *ppMem = &pMemSolaris->Core;
1101 kmem_free(paPhysAddrs, sizeof(uint64_t) * cPages);
1102 return VINF_SUCCESS;
1103 }
1104
1105 LogRel(("rtR0MemObjNativeMapUser: rtR0MemObjSolUserMap failed rc=%d.\n", rc));
1106 }
1107
1108 rc = VERR_MAP_FAILED;
1109 kmem_free(paPhysAddrs, sizeof(uint64_t) * cPages);
1110 }
1111 else
1112 rc = VERR_NO_MEMORY;
1113 rtR0MemObjDelete(&pMemSolaris->Core);
1114 return rc;
1115}
1116
1117
1118DECLHIDDEN(int) rtR0MemObjNativeProtect(PRTR0MEMOBJINTERNAL pMem, size_t offSub, size_t cbSub, uint32_t fProt)
1119{
1120 NOREF(pMem);
1121 NOREF(offSub);
1122 NOREF(cbSub);
1123 NOREF(fProt);
1124 return VERR_NOT_SUPPORTED;
1125}
1126
1127
1128DECLHIDDEN(RTHCPHYS) rtR0MemObjNativeGetPagePhysAddr(PRTR0MEMOBJINTERNAL pMem, size_t iPage)
1129{
1130 PRTR0MEMOBJSOL pMemSolaris = (PRTR0MEMOBJSOL)pMem;
1131
1132 switch (pMemSolaris->Core.enmType)
1133 {
1134 case RTR0MEMOBJTYPE_PHYS_NC:
1135 if ( pMemSolaris->Core.u.Phys.fAllocated
1136 || !pMemSolaris->fIndivPages)
1137 {
1138 uint8_t *pb = (uint8_t *)pMemSolaris->Core.pv + ((size_t)iPage << PAGE_SHIFT);
1139 return rtR0MemObjSolVirtToPhys(pb);
1140 }
1141 page_t **ppPages = pMemSolaris->pvHandle;
1142 return rtR0MemObjSolPagePhys(ppPages[iPage]);
1143
1144 case RTR0MEMOBJTYPE_PAGE:
1145 case RTR0MEMOBJTYPE_LOW:
1146 case RTR0MEMOBJTYPE_LOCK:
1147 {
1148 uint8_t *pb = (uint8_t *)pMemSolaris->Core.pv + ((size_t)iPage << PAGE_SHIFT);
1149 return rtR0MemObjSolVirtToPhys(pb);
1150 }
1151
1152 /*
1153 * Although mapping can be handled by rtR0MemObjSolVirtToPhys(offset) like the above case,
1154 * request it from the parent so that we have a clear distinction between CONT/PHYS_NC.
1155 */
1156 case RTR0MEMOBJTYPE_MAPPING:
1157 return rtR0MemObjNativeGetPagePhysAddr(pMemSolaris->Core.uRel.Child.pParent, iPage);
1158
1159 case RTR0MEMOBJTYPE_CONT:
1160 case RTR0MEMOBJTYPE_PHYS:
1161 AssertFailed(); /* handled by the caller */
1162 case RTR0MEMOBJTYPE_RES_VIRT:
1163 default:
1164 return NIL_RTHCPHYS;
1165 }
1166}
1167
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette