RISC OS Open
Safeguarding the past, present and future of RISC OS for everyone
ROOL
Home | News | Downloads | Bugs | Bounties | Forum | Documents | Photos | Contact us
Account

OS_Memory 19

OS SWI Calls
» OS_Memory
» OS_Memory 19

OS_Memory 19

(SWI &68)
Entry
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 input function
R4 Initial R9 value to provide to output function
R5 Pointer to output function (if bit 10 of R0 clear)
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

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/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.

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).

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.

See also

  • OS_Memory
  • OS_Memory 0
  • Service_PagesUnsafe
  • Service_PagesUnsafe64
Revised on April 29, 2021 14:49:34 by Jeffrey Lee (213) (31.49.209.212)
Edit | Back in time (4 revisions) | See changes | History | Views: Print | Source | Linked from: OS_Memory 0 Flags, OS_Memory, OS_Memory 19 Input Function, OS_Memory 19 Output Function

Search the Wiki

Social

Follow us on and

ROOL Store

Buy RISC OS Open merchandise here, including SD cards for Raspberry Pi and more.

Donate! Why?

Help ROOL make things happen – please consider donating!

RISC OS IPR

RISC OS is an Open Source operating system owned by RISC OS Developments Ltd and licensed primarily under the Apache 2.0 license.

Navigation

  • Home Page
  • All Pages
  • Recently Revised
  • Authors
  • Feeds
Site design © RISC OS Open Limited 2018 except where indicated
The RISC OS Open Instiki theme is based on Insitki's default layout

Valid XHTML 1.0  |  Valid CSS

Instiki 0.19.1(MML+)
This site runs on Rails

Hosted by Arachsys