#pragma once // Physically contiguous memory for devices that read and write it themselves. // // kalloc() hands out 4 KB pages from a free list, in whatever order they were // released. That is exactly what a page table wants and exactly what a device // cannot use: an xHCI command ring, a NIC's descriptor array or a virtio // queue is a single physically contiguous object that the hardware walks // without any idea that paging exists. Two kalloc'd pages are adjacent in the // kernel's address space only by luck. // // So DMA memory comes from an arena carved out of the top of physical memory // before kalloc ever sees it, and is handed out contiguous and aligned. // // On x86 this memory needs no special cacheability. The PCI bus is cache // coherent: a device's write invalidates the corresponding cache line, and a // CPU write is snooped out of the store buffer before the device sees stale // data. Architectures without that guarantee need explicit cache maintenance // around every descriptor access, and porting this file is where that would // go. What is *not* free even here is ordering -- the compiler and the CPU // will happily reorder stores to a ring, so a driver still needs a barrier // between filling a descriptor and telling the device about it. // 64 MB, and the arithmetic is worth writing down because it has been got // wrong twice. // // 4 MB was one framebuffer at 1280x800, which was fine while exactly one driver // wanted one. It stopped being fine the day a display driver could be handed to // userspace (docs/architecture/devices.md): either side of that handover **both drivers // exist**, and the incoming one has to allocate its framebuffer before the // outgoing one lets go of its own. So the real requirement is two framebuffers // at once, not one. // // 16 MB was chosen for two at 1280x800 (4 MB each) and that is what it holds. // It does not hold two of anything larger, and virtio-gpu's size is **the size // of the host's window**, which the user resizes. A 1920x982 window is 7365 KB // a copy, so the handover needs 14.4 MB of a 16 MB arena and then fails on the // rings and the alignment: // // vgpud: wanted 7365 KB of DMA memory for a 1920x982 framebuffer // vgpud: not enough contiguous DMA memory // schinitd: restarting os.schos.vgpud (and again, and again) // // 64 MB is two framebuffers at 2560x1440 with room to spare, which covers any // window somebody is likely to drag out on a desktop. It is carved off the top // of physical memory at boot and never grows, so it is 64 MB this kernel cannot // use for anything else -- 6% of the 1 GB this is usually run with, against a // display driver that otherwise cannot start at all. #define DMA_ARENA_BYTES (64*1024*1024) void dma_init(void *vstart, void *vend); // Zeroed, physically contiguous, at least `align`-aligned (align must be a // power of two). Returns a kernel virtual address, or 0. void *dma_alloc(uint64 size, uint64 align); // `size` must be the size the allocation was made with, as in Linux's // dma_free_coherent(). Tracking it here would mean a second table whose only // job is to remember something the caller already knows. void dma_free(void *p, uint64 size); // The address to give the device. Kernel memory is direct-mapped, so this is // just V2P -- but drivers should say what they mean, because on a machine // with an IOMMU these stop being the same number. addr_t dma_phys(const void *p); uint64 dma_free_bytes(void); // The biggest single block still available. When an allocation fails, the // difference between this and dma_free_bytes() is the difference between a // full arena and a fragmented one -- see the message in dma_alloc(). uint64 dma_largest_bytes(void); uint64 dma_total_bytes(void);