1515package nvproxy
1616
1717import (
18+ "gvisor.dev/gvisor/pkg/abi/nvgpu"
1819 "gvisor.dev/gvisor/pkg/context"
1920 "gvisor.dev/gvisor/pkg/hostarch"
21+ "gvisor.dev/gvisor/pkg/log"
2022 "gvisor.dev/gvisor/pkg/sentry/memmap"
2123 "gvisor.dev/gvisor/pkg/sentry/vfs"
2224)
@@ -75,6 +77,13 @@ func (mf *frontendFDMemmapFile) IncRef(fr memmap.FileRange, memCgID uint32) {
7577func (mf * frontendFDMemmapFile ) DecRef (fr memmap.FileRange ) {
7678}
7779
80+ // MemoryType implements memmap.File.MemoryType.
81+ func (mf * frontendFDMemmapFile ) MemoryType () hostarch.MemoryType {
82+ mf .fd .mmapMu .Lock ()
83+ defer mf .fd .mmapMu .Unlock ()
84+ return mf .fd .mmapMemType
85+ }
86+
7887// DataFD implements memmap.File.DataFD.
7988func (mf * frontendFDMemmapFile ) DataFD (fr memmap.FileRange ) (int , error ) {
8089 return mf .FD (), nil
@@ -84,3 +93,62 @@ func (mf *frontendFDMemmapFile) DataFD(fr memmap.FileRange) (int, error) {
8493func (mf * frontendFDMemmapFile ) FD () int {
8594 return int (mf .fd .hostFD )
8695}
96+
97+ func getMemoryType (ctx context.Context , mapDev * frontendDevice , cachingType uint32 ) hostarch.MemoryType {
98+ // Compare kernel-open/nvidia/nv-mmap.c:nvidia_mmap_helper() =>
99+ // nv_encode_caching(). Each NVOS33_FLAGS_CACHING_TYPE_* corresponds
100+ // directly to a NV_MEMORY_*; this is checked by asserts in
101+ // src/nvidia/src/kernel/rmapi/mapping_cpu.c.
102+ if ! mapDev .isCtlDevice () {
103+ // NOTE(gvisor.dev/issue/11436): In the !NV_IS_CTL_DEVICE() branch of
104+ // nvidia_mmap_helper(), mmap_context->caching is only honored if
105+ // IS_FB_OFFSET() and !IS_UD_OFFSET(). We can get the information we
106+ // need for IS_FB_OFFSET() from NV_ESC_CARD_INFO, but there doesn't
107+ // seem to be any way for us to replicate IS_UD_OFFSET(). So we must
108+ // conservatively specify uncacheable, which applies in all other
109+ // cases. This is unfortunate since it prevents us from using
110+ // write-combining on framebuffer memory. Empirically, mappings of
111+ // framebuffer memory seem to be fairly common, but none of our tests
112+ // result in any IS_UD_OFFSET (USERD?) mappings.
113+ if log .IsLogging (log .Debug ) {
114+ ctx .Debugf ("nvproxy: inferred memory type %v for mapping of %s" , hostarch .MemoryTypeUncached , mapDev .basename ())
115+ }
116+ return hostarch .MemoryTypeUncached
117+ }
118+ var memType hostarch.MemoryType
119+ switch cachingType {
120+ case nvgpu .NVOS33_FLAGS_CACHING_TYPE_CACHED , nvgpu .NVOS33_FLAGS_CACHING_TYPE_WRITEBACK :
121+ // Note that nv_encode_caching() doesn't actually handle
122+ // NV_MEMORY_WRITEBACK, so this case should fail during host mmap.
123+ memType = hostarch .MemoryTypeWriteBack
124+ case nvgpu .NVOS33_FLAGS_CACHING_TYPE_WRITECOMBINED , nvgpu .NVOS33_FLAGS_CACHING_TYPE_DEFAULT :
125+ // NOTE(gvisor.dev/issue/11436): In the NV_IS_CTL_DEVICE() branch of
126+ // nvidia_mmap_helper(), memory_type is never
127+ // NV_MEMORY_TYPE_FRAMEBUFFER, so this corresponds to
128+ // kernel-open/common/inc/nv-pgprot.h:NV_PGPROT_WRITE_COMBINED(). On
129+ // ARM64, NV_PGPROT_WRITE_COMBINED() => NV_PGPROT_UNCACHED() implicitly
130+ // uses MT_NORMAL (equivalent to our MemoryTypeWriteBack) rather than
131+ // MT_NORMAL_NC when nvos_is_chipset_io_coherent() =>
132+ // PDB_PROP_CL_IS_CHIPSET_IO_COHERENT is true, which seems to be the
133+ // case on most systems. We should clarify whether this is an
134+ // optimization or required for correctness (cf. Armv8-M Architecture
135+ // Reference Manual Sec. B7.16 "Mismatched memory attributes"), and
136+ // subsequently whether to replicate it.
137+ memType = hostarch .MemoryTypeWriteCombine
138+ case nvgpu .NVOS33_FLAGS_CACHING_TYPE_UNCACHED , nvgpu .NVOS33_FLAGS_CACHING_TYPE_UNCACHED_WEAK :
139+ // NOTE(gvisor.dev/issue/11436): On ARM64, nv_encode_caching()
140+ // distinguishes between NV_PGPROT_UNCACHED() => MT_NORMAL/MT_NORMAL_NC
141+ // and NV_PGPROT_UNCACHED_DEVICE() => MT_DEVICE_nGnRnE; in context, the
142+ // former is used in the !peer_io (NV_MEMORY_TYPE_SYSTEM) case and the
143+ // latter is used in the peer_io (NV_MEMORY_TYPE_DEVICE_MMIO) case. As
144+ // above, we should clarify whether we need to replicate this behavior.
145+ memType = hostarch .MemoryTypeUncached
146+ default :
147+ ctx .Warningf ("nvproxy: unknown caching type %d" , cachingType )
148+ memType = hostarch .MemoryTypeUncached
149+ }
150+ if log .IsLogging (log .Debug ) {
151+ ctx .Debugf ("nvproxy: inferred memory type %v for caching type %d" , memType , cachingType )
152+ }
153+ return memType
154+ }
0 commit comments