h6. [[OS SWI Calls]] h6(. » [[OS_Memory]] h6((. » OS_Memory 19 h2. OS_Memory 19 h5. (SWI &68) |_<^{width:4em}. Entry | | |/6<^. R0 |<^. 19, and flags: | |<^. Bit 8: Input function provides physical addresses (=1), else logical (=0) | |<^. Bit 9: DMA is writing to RAM | |<^. Bit 10: DMA is complete | |<^. Bit 11: Use 64 bit physical addresses (RISC OS 5.29+) | |<^. Bits 12+: Reserved (set to 0) | |<^. R1 |<^. R12 value to provide to called functions | |<^. R2 |<^. Initial R9 value to provide to input function | |<^. R3 |<^. Pointer to [[OS_Memory 19 Input Function|input function]] | |<^. R4 |<^. Initial R9 value to provide to output function | |<^. R5 |<^. Pointer to [[OS_Memory 19 Output Function|output function]] (if bit 10 of R0 clear) | |_<^{width:4em}. Exit | | |<^. R2 |<^. Updated to match last value returned by input function | |<^. R4 |<^. Updated to match last value returned by output function | |<^. - |<^. All other registers preserved | h4. Use This call performs address translation and cache maintenance operations, as necessary to allow for DMA to be performed to/from cacheable memory. It's intended to be used as a replacement for the [[OS_Memory 0]]/[[OS_Memory 64]] "Enable/disable caching" feature, since there are many issues with that approach on modern systems. As with OS_Memory 0/64, OS_Memory 19 must be called twice per DMA operation: Once at the start of the operation (with bit 10 of R0 clear), and once at the end of the operation (with bit 10 set). The same list of input addresses ranges must be provided each time. Key differences from OS_Memory 0 are as follows: * The cacheability of the memory pages involved in the transfer will not be modified. In some cases this can result in a performance boost, but the main benefits are that it avoids the problems that [[OS_Memory 0 Flags|OS_Memory 0/64 suffers from]]. * OS_Memory 19 will attempt to coalesce blocks (while retaining their ordering) so that the output list is as short as possible. Blocks will be coalesced if they are logically and physically contiguous, and have the same flags (i.e. bounce buffer usage). This is particularly useful for multi-megabyte transfers, where hundreds or thousands of pages may be involved in the transfer. * Instead of requiring the caller to prepare a page list array, a callback function is used to obtain details of regions on-demand. This is a performance/memory optimisation, to avoid the need to make a copy of your address lists in a format which OS_Memory can understand. * Similarly, address translation results are returned via a callback function rather than by filling in a pre-allocated array. h4. Operation OS_Memory 19 operates under the following principles: * DMA which reads from cacheable memory will require the corresponding cache lines to be cleaned (flushed) beforehand, so that data is written back to memory prior to the DMA reading it. * DMA which writes to cacheable memory will require the corresponding cache lines to be cleaned beforehand, so that any pending write-back data doesn't overwrite data the DMA is writing. At the end of the operation, the cache will be invalidated again, so that any data that was prefetched (or explicitly loaded) by the CPU will be discarded and the fresh data written by the DMA will be visible. ** Technically the start of the transfer only needs to perform an Invalidate operation, since if DMA is going to completely overwrite the data it doesn't matter whether the data in the cache gets written back or discarded. However by cleaning the cache, we ensure that data written by the CPU won't get lost if the DMA transfer terminates early. It also provides support for read-modify-write operations. * If DMA is writing to a cacheable area which isn't cache-line aligned, it will be forced to use a bounce buffer. This is because OS_Memory 19 doesn't assume that you have exclusive ownership of the memory. E.g. if the memory is in the RMA, a program which writes to a heap block which is located in the non-DMA part of the cache line will cause that entire cache line to be written out to memory, potentially overwriting the part of the cache line which had been updated by the DMA. Under this strategy, it's safe for programs (or other DMA controllers) to read from memory that is being accessed by a DMA read operation. Accessing cacheable memory which is being a DMA write operation is unsafe and should not be avoided (unless you're careful to perform the necessary cache maintenance yourself). h4. Notes For the 32 bit version of the call (flag bit 11 is zero), if a logical address maps to a physical address which is larger than 32 bits then that section of the transfer will be forced via a bounce buffer and the returned physical address will be undefined. To avoid this, the 64 bit version of the call should be used (flag bit 11 set). Although there's no direct way of detecting if the 64 bit version of the call is supported, [[OS_PlatformFeatures 0]] bit 21 can be used as an indicator that it's supported / necessary. [[Service_PagesUnsafe]] / [[Service_PagesUnsafe64]] is issued by the OS whenever the physical page associated with a logical address is being "transparently" replaced with another physical page. This can occur as the result of the original physical page being requested by a [[Dynamic Area PreGrow]] handler. Programs which perform DMA need to listen out for this service call so that they can pause DMA while the pages are being moved, and then resume DMA (using the new logical -> physical mapping) once the page move is complete. Because OS_Memory 0/64 don't perform any operations which might cause pages to be moved in this manner, programs which uses OS_Memory 0/64 only need to start paying attention to Service_PagesUnsafe/PagesUnsafe64 once they've received the results from the OS. But for OS_Memory 19, results are returned to your code in a piecemeal fashion. If your input or output function performs operations which may trigger page movement (e.g. allocating pages from the RMA), extra care is needed in order to deal with Service_PagesUnsafe/PagesUnsafe64 correctly. If a call to [[Service_PagesUnsafe]] / [[Service_PagesUnsafe64]] occurs during the call to OS_Memory, and it affects the pages which are involved in the OS_Memory call: * If the input function provides physical addresses, the entire OS_Memory operation should be aborted and retried. * If the input function provides logical addresses, you must either update the information for the segments which have been passed to your output function, or you must abort and restart the entire operation. If code is written to memory by a DMA operation then you must still call [[OS_SynchroniseCodeAreas]] afterwards to ensure the instruction cache has been invalidated. h4. See also * [[OS_Memory]] * [[OS_Memory 0]] * [[Service_PagesUnsafe]] * [[Service_PagesUnsafe64]]