1
/* $Id: memobj-r0drv-solaris.c $ */
3
* IPRT - Ring-0 Memory Objects, Solaris.
7
* Copyright (C) 2006-2007 Sun Microsystems, Inc.
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.
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.
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.
26
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27
* Clara, CA 95054 USA or visit http://www.sun.com if you need
28
* additional information or have any questions.
32
/*******************************************************************************
34
*******************************************************************************/
35
#include "the-solaris-kernel.h"
37
#include <iprt/memobj.h>
40
#include <iprt/assert.h>
42
#include <iprt/param.h>
43
#include <iprt/process.h>
44
#include "internal/memobj.h"
47
/*******************************************************************************
48
* Structures and Typedefs *
49
*******************************************************************************/
51
* The Solaris version of the memory object structure.
53
typedef struct RTR0MEMOBJSOLARIS
55
/** The core structure. */
56
RTR0MEMOBJINTERNAL Core;
57
/** Pointer to kernel memory cookie. */
58
ddi_umem_cookie_t Cookie;
59
/** Shadow locked pages. */
60
page_t **ppShadowPages;
61
} RTR0MEMOBJSOLARIS, *PRTR0MEMOBJSOLARIS;
64
* Used for supplying the solaris kernel info. about memory limits
65
* during contiguous allocations (i_ddi_mem_alloc)
67
struct ddi_dma_attr g_SolarisX86PhysMemLimits =
69
DMA_ATTR_V0, /* Version Number */
70
(uint64_t)0, /* lower limit */
71
(uint64_t)0xffffffff, /* high limit (32-bit PA, 4G) */
72
(uint64_t)0xffffffff, /* counter limit */
73
(uint64_t)PAGE_SIZE, /* alignment */
74
(uint64_t)PAGE_SIZE, /* burst size */
75
(uint64_t)PAGE_SIZE, /* effective DMA size */
76
(uint64_t)0xffffffff, /* max DMA xfer size */
77
(uint64_t)0xffffffff, /* segment boundary */
78
1, /* scatter-gather list length (1 for contiguous) */
79
1, /* device granularity */
80
0 /* bus-specific flags */
84
static uint64_t rtR0MemObjSolarisVirtToPhys(struct hat* hatSpace, caddr_t virtAddr)
86
/* We could use paddr_t (more solaris-like) rather than uint64_t but paddr_t isn't defined for 64-bit */
87
pfn_t pfn = hat_getpfnum(hatSpace, virtAddr);
88
if (pfn == PFN_INVALID)
90
AssertMsgFailed(("rtR0MemObjSolarisVirtToPhys: hat_getpfnum for %p failed.\n", virtAddr));
94
uint64_t physAddr = ((uint64_t)pfn << MMU_PAGESHIFT) | ((uintptr_t)virtAddr & MMU_PAGEOFFSET);
99
int rtR0MemObjNativeFree(RTR0MEMOBJ pMem)
101
PRTR0MEMOBJSOLARIS pMemSolaris = (PRTR0MEMOBJSOLARIS)pMem;
103
switch (pMemSolaris->Core.enmType)
105
case RTR0MEMOBJTYPE_CONT:
106
i_ddi_mem_free(pMemSolaris->Core.pv, NULL);
109
case RTR0MEMOBJTYPE_PAGE:
110
ddi_umem_free(pMemSolaris->Cookie);
113
case RTR0MEMOBJTYPE_LOCK:
115
struct as *addrSpace;
116
if ((uintptr_t)pMemSolaris->Core.pv < kernelbase)
118
addrSpace = ((proc_t *)pMemSolaris->Core.u.Lock.R0Process)->p_as;
119
as_pageunlock(addrSpace, pMemSolaris->ppShadowPages, pMemSolaris->Core.pv, pMemSolaris->Core.cb, S_WRITE);
121
/* Nothing to unlock for kernel addresses. */
125
case RTR0MEMOBJTYPE_MAPPING:
127
struct hat *hatSpace;
128
struct as *addrSpace;
129
if (pMemSolaris->Core.u.Mapping.R0Process == NIL_RTR0PROCESS)
132
hatSpace = kas.a_hat;
138
proc_t *userProc = (proc_t *)pMemSolaris->Core.u.Mapping.R0Process;
139
hatSpace = userProc->p_as->a_hat;
140
addrSpace = userProc->p_as;
143
rw_enter(&addrSpace->a_lock, RW_READER);
144
hat_unload(hatSpace, pMemSolaris->Core.pv, pMemSolaris->Core.cb, HAT_UNLOAD_UNLOCK);
145
rw_exit(&addrSpace->a_lock);
146
as_unmap(addrSpace, pMemSolaris->Core.pv, pMemSolaris->Core.cb);
151
case RTR0MEMOBJTYPE_LOW:
152
case RTR0MEMOBJTYPE_PHYS:
153
case RTR0MEMOBJTYPE_RES_VIRT:
155
AssertMsgFailed(("enmType=%d\n", pMemSolaris->Core.enmType));
156
return VERR_INTERNAL_ERROR;
163
int rtR0MemObjNativeAllocPage(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
165
/* Create the object */
166
PRTR0MEMOBJSOLARIS pMemSolaris = (PRTR0MEMOBJSOLARIS)rtR0MemObjNew(sizeof(*pMemSolaris), RTR0MEMOBJTYPE_PAGE, NULL, cb);
168
return VERR_NO_MEMORY;
170
void *virtAddr = ddi_umem_alloc(cb, DDI_UMEM_SLEEP, &pMemSolaris->Cookie);
173
rtR0MemObjDelete(&pMemSolaris->Core);
174
return VERR_NO_PAGE_MEMORY;
177
pMemSolaris->Core.pv = virtAddr;
178
pMemSolaris->ppShadowPages = NULL;
179
*ppMem = &pMemSolaris->Core;
184
int rtR0MemObjNativeAllocLow(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
186
/* Try page alloc first */
187
int rc = rtR0MemObjNativeAllocPage(ppMem, cb, fExecutable);
190
size_t iPage = cb >> PAGE_SHIFT;
192
if (rtR0MemObjNativeGetPagePhysAddr(*ppMem, iPage) > (_4G - PAGE_SIZE))
194
/* Failed! Fall back to physical contiguous alloc */
195
RTR0MemObjFree(*ppMem, false);
196
rc = rtR0MemObjNativeAllocCont(ppMem, cb, fExecutable);
204
int rtR0MemObjNativeAllocCont(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
208
/* Create the object */
209
PRTR0MEMOBJSOLARIS pMemSolaris = (PRTR0MEMOBJSOLARIS)rtR0MemObjNew(sizeof(*pMemSolaris), RTR0MEMOBJTYPE_CONT, NULL, cb);
211
return VERR_NO_MEMORY;
213
/* Allocate physically contiguous page-aligned memory. */
215
int rc = i_ddi_mem_alloc(NULL, &g_SolarisX86PhysMemLimits, cb, 1, 0, NULL, &virtAddr, NULL, NULL);
216
if (rc != DDI_SUCCESS)
218
rtR0MemObjDelete(&pMemSolaris->Core);
219
return VERR_NO_CONT_MEMORY;
222
pMemSolaris->Core.pv = virtAddr;
223
pMemSolaris->Core.u.Cont.Phys = rtR0MemObjSolarisVirtToPhys(kas.a_hat, virtAddr);
224
pMemSolaris->ppShadowPages = NULL;
225
*ppMem = &pMemSolaris->Core;
230
int rtR0MemObjNativeAllocPhysNC(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, RTHCPHYS PhysHighest)
232
/** @todo rtR0MemObjNativeAllocPhysNC / solaris */
233
return VERR_NOT_SUPPORTED; /* see the RTR0MemObjAllocPhysNC specs */
237
int rtR0MemObjNativeAllocPhys(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, RTHCPHYS PhysHighest)
239
AssertMsgReturn(PhysHighest >= 16 *_1M, ("PhysHigest=%RHp\n", PhysHighest), VERR_NOT_IMPLEMENTED);
241
return rtR0MemObjNativeAllocCont(ppMem, cb, false);
245
int rtR0MemObjNativeEnterPhys(PPRTR0MEMOBJINTERNAL ppMem, RTHCPHYS Phys, size_t cb)
247
/* Create the object */
248
PRTR0MEMOBJSOLARIS pMemSolaris = (PRTR0MEMOBJSOLARIS)rtR0MemObjNew(sizeof(*pMemSolaris), RTR0MEMOBJTYPE_PHYS, NULL, cb);
250
return VERR_NO_MEMORY;
252
/* There is no allocation here, it needs to be mapped somewhere first */
253
pMemSolaris->Core.u.Phys.fAllocated = false;
254
pMemSolaris->Core.u.Phys.PhysBase = Phys;
255
*ppMem = &pMemSolaris->Core;
260
int rtR0MemObjNativeLockUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3Ptr, size_t cb, RTR0PROCESS R0Process)
262
AssertReturn(R0Process == RTR0ProcHandleSelf(), VERR_INVALID_PARAMETER);
264
/* Create the locking object */
265
PRTR0MEMOBJSOLARIS pMemSolaris = (PRTR0MEMOBJSOLARIS)rtR0MemObjNew(sizeof(*pMemSolaris), RTR0MEMOBJTYPE_LOCK, (void *)R3Ptr, cb);
267
return VERR_NO_MEMORY;
269
proc_t *userproc = (proc_t *)R0Process;
270
struct as *useras = userproc->p_as;
273
/* Lock down user pages */
276
if ((uintptr_t)R3Ptr < kernelbase)
277
rc = as_pagelock(useras, &ppl, (caddr_t)R3Ptr, cb, S_WRITE);
282
pMemSolaris->Core.u.Lock.R0Process = (RTR0PROCESS)userproc;
283
pMemSolaris->ppShadowPages = ppl;
284
*ppMem = &pMemSolaris->Core;
288
cmn_err(CE_NOTE,"rtR0MemObjNativeLockUser: as_pagelock failed rc=%d\n", rc);
289
rtR0MemObjDelete(&pMemSolaris->Core);
290
return VERR_LOCK_FAILED;
294
int rtR0MemObjNativeLockKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pv, size_t cb)
296
/* Create the locking object */
297
PRTR0MEMOBJSOLARIS pMemSolaris = (PRTR0MEMOBJSOLARIS)rtR0MemObjNew(sizeof(*pMemSolaris), RTR0MEMOBJTYPE_LOCK, pv, cb);
299
return VERR_NO_MEMORY;
301
/* Nothing to do here for kernel addresses. */
303
pMemSolaris->Core.u.Lock.R0Process = RTR0ProcHandleSelf();
304
pMemSolaris->ppShadowPages = NULL;
305
*ppMem = &pMemSolaris->Core;
310
int rtR0MemObjNativeReserveKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pvFixed, size_t cb, size_t uAlignment)
312
return VERR_NOT_IMPLEMENTED;
316
int rtR0MemObjNativeReserveUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3PtrFixed, size_t cb, size_t uAlignment, RTR0PROCESS R0Process)
318
return VERR_NOT_IMPLEMENTED;
321
int rtR0MemObjNativeMapKernel(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ pMemToMap, void *pvFixed, size_t uAlignment,
322
unsigned fProt, size_t offSub, size_t cbSub)
324
/* @todo rtR0MemObjNativeMapKernel / Solaris - Should be fairly simple alloc kernel memory and memload it. */
325
return VERR_NOT_IMPLEMENTED;
329
int rtR0MemObjNativeMapUser(PPRTR0MEMOBJINTERNAL ppMem, PRTR0MEMOBJINTERNAL pMemToMap, RTR3PTR R3PtrFixed, size_t uAlignment, unsigned fProt, RTR0PROCESS R0Process)
331
AssertMsgReturn(R3PtrFixed == (RTR3PTR)-1, ("%p\n", R3PtrFixed), VERR_NOT_SUPPORTED);
332
AssertMsgReturn(R0Process == RTR0ProcHandleSelf(), ("%p != %p\n", R0Process, RTR0ProcHandleSelf()), VERR_NOT_SUPPORTED);
334
PRTR0MEMOBJSOLARIS pMemToMapSolaris = (PRTR0MEMOBJSOLARIS)pMemToMap;
335
size_t size = pMemToMapSolaris->Core.cb;
336
proc_t *userproc = (proc_t *)R0Process;
337
struct as *useras = userproc->p_as;
338
void *pv = pMemToMapSolaris->Core.pv;
339
pgcnt_t cPages = btop(size);
344
/* Request the system for a mapping address. */
345
as_rangelock(useras);
346
map_addr(&addr, size, 0 /* offset */, 1 /* vac-align */, MAP_SHARED | MAP_ANONYMOUS);
349
as_rangeunlock(useras);
350
cmn_err(CE_NOTE, "rtR0MemObjNativeMapUser: map_addr failed\n");
351
return VERR_MAP_FAILED;
354
/* Check address against alignment, fail if it doesn't match */
355
if ((uintptr_t)addr & (uAlignment - 1))
357
as_rangeunlock(useras);
358
cmn_err(CE_NOTE, "rtR0MemObjNativeMapUser: map_addr alignment(%ld) failed.\n", uAlignment);
359
return VERR_MAP_FAILED;
362
/* Our protection masks are identical to <sys/mman.h> but we
363
* need to add PROT_USER for the pages to be accessible by user
365
struct segvn_crargs crArgs = SEGVN_ZFOD_ARGS(fProt | PROT_USER, PROT_ALL);
366
rc = as_map(useras, addr, size, segvn_create, &crArgs);
367
as_rangeunlock(useras);
370
cmn_err(CE_NOTE, "rtR0MemObjNativeMapUser: as_map failure.\n");
371
return VERR_MAP_FAILED;
374
/* Create the mapping object */
375
PRTR0MEMOBJSOLARIS pMemSolaris = (PRTR0MEMOBJSOLARIS)rtR0MemObjNew(sizeof(*pMemSolaris), RTR0MEMOBJTYPE_MAPPING, pv, size);
378
/* Undo mapping on failure. */
379
as_unmap(useras, addr, size);
380
return VERR_NO_MEMORY;
383
/* Map each page into user space */
384
rw_enter(&useras->a_lock, RW_READER);
385
caddr_t kernAddr = pv;
386
caddr_t pageAddr = addr;
387
for (iPage = 0; iPage < cPages; iPage++)
389
page_t *pp = page_numtopp_nolock(hat_getpfnum(kas.a_hat, kernAddr));
390
hat_memload(useras->a_hat, pageAddr, pp, (fProt | PROT_USER), HAT_LOAD_LOCK);
394
rw_exit(&useras->a_lock);
396
pMemSolaris->Core.u.Mapping.R0Process = (RTR0PROCESS)userproc;
397
pMemSolaris->Core.pv = addr;
398
*ppMem = &pMemSolaris->Core;
403
int rtR0MemObjNativeProtect(PRTR0MEMOBJINTERNAL pMem, size_t offSub, size_t cbSub, uint32_t fProt)
409
return VERR_NOT_SUPPORTED;
413
RTHCPHYS rtR0MemObjNativeGetPagePhysAddr(PRTR0MEMOBJINTERNAL pMem, size_t iPage)
415
PRTR0MEMOBJSOLARIS pMemSolaris = (PRTR0MEMOBJSOLARIS)pMem;
417
switch (pMemSolaris->Core.enmType)
419
case RTR0MEMOBJTYPE_PAGE:
420
case RTR0MEMOBJTYPE_LOW:
421
case RTR0MEMOBJTYPE_MAPPING:
423
uint8_t *pb = (uint8_t *)pMemSolaris->Core.pv + ((size_t)iPage << PAGE_SHIFT);
424
return rtR0MemObjSolarisVirtToPhys(kas.a_hat, pb);
427
case RTR0MEMOBJTYPE_LOCK:
429
struct hat *hatSpace;
430
if (pMemSolaris->Core.u.Lock.R0Process != NIL_RTR0PROCESS)
433
proc_t *userProc = (proc_t *)pMemSolaris->Core.u.Lock.R0Process;
434
hatSpace = userProc->p_as->a_hat;
437
hatSpace = kas.a_hat;
439
uint8_t *pb = (uint8_t *)pMemSolaris->Core.pv + ((size_t)iPage << PAGE_SHIFT);
440
return rtR0MemObjSolarisVirtToPhys(hatSpace, pb);
443
case RTR0MEMOBJTYPE_CONT:
444
return pMemSolaris->Core.u.Cont.Phys + (iPage << PAGE_SHIFT);
446
case RTR0MEMOBJTYPE_PHYS:
447
return pMemSolaris->Core.u.Phys.PhysBase + (iPage << PAGE_SHIFT);
449
case RTR0MEMOBJTYPE_PHYS_NC:
450
AssertFailed(/* not implemented */);
451
case RTR0MEMOBJTYPE_RES_VIRT: