Skip to content

Commit d0c6574

Browse files
xaionaro@dx.centerxaionaro@dx.center
authored andcommitted
fix: use MMIO-safe copy for goldfish gralloc writes and prefer RW mmap
The AVC encode test crashed with SIGSEGV when writing to goldfish address space memory via Go's copy(), which emits AVX2 VMOVDQU instructions that fault on uncacheable PCI BAR (MMIO) memory. Two fixes: - Add CopyToMMIO for scalar writes to MMIO regions (matching the existing copyFromMMIO for reads) - Reorder mmap strategies to try PROT_READ|PROT_WRITE before PROT_READ, so buffers are writable when the kernel allows it
1 parent 2f783c8 commit d0c6574

2 files changed

Lines changed: 31 additions & 8 deletions

File tree

gralloc/buffer.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,10 @@ type mmapAttempt struct {
6666
// - Some gralloc FDs require PROT_READ|PROT_WRITE
6767
// - Some FDs only support MAP_PRIVATE
6868
var mmapStrategies = []mmapAttempt{
69-
{unix.PROT_READ, unix.MAP_SHARED, "PROT_READ|MAP_SHARED"},
7069
{unix.PROT_READ | unix.PROT_WRITE, unix.MAP_SHARED, "PROT_READ|PROT_WRITE|MAP_SHARED"},
71-
{unix.PROT_READ, unix.MAP_PRIVATE, "PROT_READ|MAP_PRIVATE"},
70+
{unix.PROT_READ, unix.MAP_SHARED, "PROT_READ|MAP_SHARED"},
7271
{unix.PROT_READ | unix.PROT_WRITE, unix.MAP_PRIVATE, "PROT_READ|PROT_WRITE|MAP_PRIVATE"},
72+
{unix.PROT_READ, unix.MAP_PRIVATE, "PROT_READ|MAP_PRIVATE"},
7373
}
7474

7575
// DMA-BUF sync ioctl constants. On kernel 6.6+ the DMA-BUF subsystem
@@ -340,6 +340,30 @@ func copyFromMMIO(src []byte) []byte {
340340
return dst
341341
}
342342

343+
// CopyToMMIO copies src into a goldfish address space mmap region dst.
344+
// Like copyFromMMIO, this avoids Go's runtime.memmove which uses AVX2
345+
// VMOVDQU instructions that crash on UC (uncacheable) PCI BAR memory.
346+
// Only min(len(src), len(dst)) bytes are copied; the count is returned.
347+
//
348+
//go:noinline
349+
func CopyToMMIO(dst []byte, src []byte) int {
350+
n := len(src)
351+
if len(dst) < n {
352+
n = len(dst)
353+
}
354+
355+
i := 0
356+
for ; i+8 <= n; i += 8 {
357+
v := *(*uint64)(unsafe.Pointer(&src[i]))
358+
*(*uint64)(unsafe.Pointer(&dst[i])) = v
359+
}
360+
for ; i < n; i++ {
361+
dst[i] = src[i]
362+
}
363+
364+
return n
365+
}
366+
343367
// isGoldfishFD checks if an FD points to the goldfish emulator's
344368
// address space device.
345369
func isGoldfishFD(fd int) bool {

tests/e2e/codec2_test.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -914,12 +914,11 @@ func testCodec2HIDL_EncodeAVC(t *testing.T) {
914914
t.Logf("AVC gralloc mmap failed (expected on goldfish): %v", mmapErr)
915915
} else {
916916
grayFrame := makeGrayYUVFrame(encWidth, encHeight)
917-
copyLen := len(grayFrame)
918-
if copyLen > len(buf.MmapData) {
919-
copyLen = len(buf.MmapData)
920-
}
921-
copy(buf.MmapData[:copyLen], grayFrame[:copyLen])
922-
t.Logf("AVC: wrote %d bytes of gray YUV to gralloc buffer", copyLen)
917+
// Use CopyToMMIO instead of copy(): goldfish address space is
918+
// backed by a PCI BAR (UC MMIO), and Go's copy() emits AVX2
919+
// VMOVDQU instructions that cause SIGSEGV on UC memory.
920+
n := gralloc.CopyToMMIO(buf.MmapData, grayFrame)
921+
t.Logf("AVC: wrote %d bytes of gray YUV to gralloc buffer", n)
923922
}
924923

925924
// Register listener and create component.

0 commit comments

Comments
 (0)