
Copyright (C) Acorn Computers Ltd. 1993       0197,276/FS Issue 2 **Live**

              Medusa Memory Management Software Functional Specification
              ==========================================================

                   -----------------------------------------
                   | Drawing No : 0197,276/FS              |
                   |      Issue : 2 **Live**               |
                   |       Date : 15th April 1993          |
                   |     Author : Tim Dobson               |
                   |     Sheets : n                        |
                   |  Last Issue: ?                        |
                   -----------------------------------------

 Contents
 ========

 1 History

 2 Outstanding Issues

 3 Overview

 4 Technical Background

 5 User Interface
        5.1 TaskManager and large RAM sizes

 6 Programmer Interface
        6.1 Logical memory map
        6.2 Free pool
        6.3 New SWI: OS_DynamicArea
            6.3.1 Reason codes
                6.3.1.1 Create dynamic area
                6.3.1.2 Remove dynamic area
                6.3.1.3 Return information on dynamic area
                6.3.1.4 Enumerate dynamic areas
                6.3.1.5 Renumber dynamic area
            6.3.2 Dynamic area handler routine
                6.3.2.1 PreGrow
                6.3.2.2 PostGrow
                6.3.2.3 PreShrink
                6.3.2.4 PostShrink
            6.3.3 Sequence Of Actions When OS_ChangeDynamicArea Is Called
                6.3.3.1 Service_PagesUnsafe
                6.3.3.2 Service_PagesSafe
            6.3.4 Implementation Notes for OS_ChangeDynamicArea
            6.3.5 OS_DynamicArea Service Calls
                6.3.5.1 Service_DynamicAreaCreate (&90)
                6.3.5.2 Service_DynamicAreaRemove (&91)
                6.3.5.2 Service_DynamicAreaRenumber (&92)
        6.4 New SWI: OS_Memory
            6.4.1 OS_Memory Reasons 0-5: Convert Memory Address
            6.4.2 OS_Memory Reasons 6-8: Physical Memory
                6.4.2.1 Read Physical Memory Arrangement Table Size
                6.4.2.2 Read Physical Memory Arrangement Table
                6.4.2.3 Read Amounts Of Various Sorts Of Memory
            6.4.3 I/O Space Information
                6.4.3.1 Read Controller Presence
        6.5 Old SWI OS_SetMemMapEntries (&53)
        6.6 Old SWI OS_ReadDynamicArea (&5C)
        6.7 New SWI OS_ClaimProcessorVector

 7 External Dependancies

 8 Development Test Strategy

 9 Organisation

 10 Future Enhancements
        10.1 Abort trappping
            10.1.1 Technical background
            10.1.2 New SWI: OS_AbortTrap
                10.1.2.1 Add abort trap
                10.1.2.2 Remove abort trap


 1. History
 ==========

             TMD 05-Nov-92   Started initial draft
             TMD 08-Mar-93   More detail added
     Issue A TMD 21-Apr-93   Released for initial review
             JSR 11-May-93   Input from review entered
             JSR 24-May-93   Adjustments to area grow and deletion
                             behaviour.
                             Add 2 controllers to list: VIDC1 and VIDC20 to
                             allow ScreenTricks module to operate.
             JSR 02-Jun-93   Added section to development test strategy for
                             Wimp and Switcher testing.
             JSR 04-Jun-93   Comments on Issue 1 spec from DLowdell.

 2. Outstanding Issues
 =====================

 What if anything should be done to the task manager's task display to cope
 with large memory sizes?

 The handling of Wimp_ClaimFreeMemory. This SWI claims the free pool making
 it available for data transfers. The Wimp used to implement this by putting
 the free memory on the end of the current task. This is no longer
 necessarily going to work as there may not be any free space beyond the end
 of the current task's memory. Also, it is quite likely that there won't be
 enough space for all the free memory.


 3. Overview
 ===========

 This specification covers changes to the memory management system in RISC
 OS for Medusa platforms.

 The main features of Medusa platforms which require changes to RISC OS's
 memory management are as follows:-

  1) Ability to cope with RAM sizes up to 256+2Mbytes, rather than the
     current maximum of 16Mbytes;

  2) Ability to control DMA;

  3) Requirements for second processor card drivers to claim memory;

  4) Physical RAM no longer contiguous;

  5) ARM600 MMU requires page table allocation;

  6) Logical memory map expansion due to 32-bit address space.

  7*) Changes to support emulation of VIDC1;

  8*) Changes to support line-doubling;

 Note: The implementation of the starred items above (VIDC1 emulation,
 line-doubling) are not part of the Medusa project; however it is an aim of
 the memory management work that it should be possible to implement these in
 a soft-loaded module at a later date.

 4. Technical Background
 =======================

In RISC OS 2 and 3 (version 3.10) the memory management task was divided
between the kernel and the wimp. The kernel ordered the memory into dynamic
areas and an application space, and the wimp then bludgeoned the kernel into
not getting in the way of the wimp's model of having a free pool and
multiple application spaces, rather than just the one application space
which had all spare memory in it. For Medusa the free pool management will
be moved into the kernel so that there isn't such a wrestling match between
the kernel and the wimp. The wimp will still manage the multiple application
spaces - it being the module responsible for constructing and managing tasks
in the desktop. The main kernel interface for memory management was
OS_ChangeDynamicArea which simply allowed the resizing of dynamic areas.
This has been added to for Medusa with the OS_DynamicArea SWI for the
control, creation and deletion of dynamic areas.

The dynamic area management in RISC OS 2 and 3 (version 3.10) was somewhat
tied together with the dynamic area clients. The change dynamic area SWI
specifically called other modules depending on which dynamic area was being
resized. The result was that there was no flexibility with how dynamic areas
were used.

Other memory related services were not available. For example it was not
possible to find out what memory or hardware was available on the system
without knowing a great deal about the platform.

Memory is referred to in three ways: physcial address, logical address and
physical page number. The first two refer to the address of the memory in
the physical address space (what IOMD presents to ARM) and logical address
space (what the ARM memory manager presents to the ARM core) respectively.
The physical page number is an arbitrary number assigned to RAM pages. It is
necessary to have this last abstraction to save space. If it weren't there
then the storage and management overheads would be prohibitive on a small
memory machine, which, as Medusa is targetted at under 1000 pounds, is
likely to be a majority of users. The way physical page numbers are
allocated is that all the contiguous RAM section in physical address space
are bunched together and the page numbers allocated from 0 upwards.

There are several interfaces described here which use Page blocks. These are
tables of 3-word records:
        word    use
        0       Physical page number
        1       logical address
        2       physical address
That is, a block of memory 12*N bytes big where N is the number of records
in the block. They are used to pass round lists of addresses or pages.


 5. User Interface
 =================

 5.1 TaskManager and large RAM sizes
 -----------------------------------

 The TaskManager module's 'Task display' window does not cope well in this
area at present. The combination of a 16-fold increase in maximum RAM size
and an 8-fold decrease in page size means that the existing linear 1
pixel-per-page model will not be practical on large memory machines. A
number of options are possible:-

  a) Do nothing. It is rare that anyone will want to manually drag an area's
size to anything particularly big. Most big programs will set their own
Wimp slot size;

  b) Allow the user to click in the number fields and enter a number
(presumably still in K);

  c) Make the scale exponential (ie at the small sizes it goes in units of
4K, but when the area gets bigger go in larger and larger steps).

  d) Make the scale a modified exponential (1+log(x)/c).


 5.2 *-Command *Cache On/Off
 ---------------------------

 A module will be provided to give this functionality. It will switch both
caching and write-buffering on and off. The corresponding SWIs will not be
supplied as they are inapplicable to an ARM600/700 based system.


 6. Programmer Interface
 =======================

 6.1 Logical Memory Map
 ----------------------

        Address         Size    Use                             Public?

        00000000        16k     System workspace                Private
        00004000        16k     Scratch space                   Public(1)
        00008000        28M-32k Application space               Public
        01C00000        8k      SVC stack                       Public(2)
        01C02000        2M-8k   System heap                     Private
        01E00000        8k      Undefined stack                 Public(2)
        01E02000        1M-8k   Soft CAM map                    Private
        01F00000        32k     Cursor/sound etc                Private
        01F08000        32k     "nowhere"                       Private
        01F10000        1M-64k  Reserved for fake screen (480k) Private
        02000000        12M     RMA                             Public(3)
        02C00000        4M      Level 2 page tables             Private
        03000000        4M      I/O space                       Private(4)
        03400000        1M      Reserved for VIDC1 emulation    Private
        03500000        1M      VIDC20                          Private
        03600000        1M      Reserved for Vinit &c emulation Private
        03700000        1M      Reserved for 2nd Proc ctrl regs Private
        03800000        8M      ROM                             Private
        04000000        2G-64M  Dynamic areas                   Public(5)
        80000000        512M    Copy of physical space          Private
        A0000000        1 1/2 G More dynamic areas              Public(5)

Notes:
1) This may be used by any module. The rules for its use are:
        Not in an IRQ routine
        Not if you're going to call something which might use it while you
                are
Example clients are: FileCore to hold structures whilst working out how to
allocate some free space; Filer to hold structures for OS_HeapSort.
2) It may be assumed that these end on a 1M boundary and will exception if
accessed beyond that end. However, the exact location of these stacks should
not be assumed.
3) The location of RMA and its maximum size may not be assumed. However, it
is guaranteed that it will be in low 64MBytes (ie can execute 26 bit code).
4) Except where particular device drivers export hardware addresses.
5) Only in so far as a client may make its own dynamic area.


 6.2 Free pool
 -------------

 Large RAM sizes pose a problem for RISC OS, because the existing metaphor
 that all spare memory lives in application space breaks down. The current
 limit on application space size is 16MB, whereas the maximum RAM size on
 Medusa platforms is 258MB. Although this limit can be moved up a little by
 moving other areas out of the way, it is not possible to extend it enough
 (eg I/O still has to live at &03000000 onwards).

 To cope with this a new dynamic area is created, known as the "free pool"
 (area number 6). The operation of SWI OS_ChangeDynamicArea is modified as
 follows:-

  a) When an area (other than the free pool) is grown, memory is taken from
     the free pool, if any exists (the current application is not notified
     of this).

     If having shrunk the free pool to zero size, there is still not enough
     memory for the growth, the kernel attempts to remove pages from the
     application space as it does under existing versions of RISC OS.

  b) When an area (other than the free pool) is shrunk, the pages recovered
     are added to the free pool. The current application is not consulted.

  c) If the free pool itself is grown, pages are taken from application
     space to put in it (and the application consulted beforehand).

  d) If the free pool is shrunk, the recovered pages are added to
     application space (the application is consulted beforehand).

 The WindowManager module also changes, to take this into account. In some
 ways its operation is simplified, as it no longer needs to maintain its own
 free pool. However the implementation of the following SWIs needs to
 change:-

  Wimp_TransferBlock at present puts all used task memory into application
  space, and then copies the relevant bits over. It cannot do this any more,
  as the total used task memory may not fit into application space. Instead
  it must do the following:-

   Split the transfer into chunks of no more than half of the maximum
   application memory size. For each chunk, put the appropriate pages of the
   source block in at the start of application space, and the appropriate
   pages of the destination block above these, then perform the transfer.
   After all chunks have been done, restore the current task's pages in
   application space.

  Wimp_ClaimFreeMemory needs to be modified, because the Wimp no longer
  maintains control of the free pool.


 6.3 New SWI: OS_DynamicArea (&66)
 ---------------------------------

 This SWI performs miscellaneous operations on dynamic areas.

 On entry, r0 provides a reason code which determines which operation is
 performed.

 Note that as all operations on dynamic areas work in physical page numbers
 it is not possible to map anything other than RAM pages (DRAM and VRAM)
 into a dynamic area. In particular EASI space cannot be mapped in.

  6.3.1 Reason codes
  ------------------

    6.3.1.1 Create dynamic area
    ---------------------------

    This call creates a new dynamic area.

    On entry:   r0 = 0 (reason code)
                r1 = new area number (-1 => RISC OS should allocate number)
                        (must not be 128-255 - see section 6.6)
                r2 = initial size of area (in bytes)
                r3 = base logical address of area (-1 => OS should allocate
                      base address)
                r4 = area flags
                        bits 0..3 = access privileges to be given to each page
                                     in the area (same format as for
                                     OS_Read/SetMemMapEntries)

                        bit  4    = 0 => area is singly mapped
                                  = 1 => area is doubly mapped

                        bits 5..31 must be zero

                r5 = maximum size of area, or -1 if the area should be
                      capable of growing to the total RAM size of the
                      machine
                r6 -> area handler routine, or 0 for no routine
                r7 = workspace pointer to be passed in r12 on entry to
                      area handler (should be 0 if r6=0)
                r8 -> area description string (null terminated), eg
                       "Font cache". This string will be displayed in the
                       TaskManager window.

    On exit:    r1 = allocated area number
                r3 = specified or allocated base address of area
                r5 = specified or allocated maximum size of area
                r0,r2,r4,r6-r8 preserved

    An error will be returned if:

    * the given area number clashes with an existing area, or

    * the logical address space occupied by the area at maximum size would
       intersect with any other area at maximum size, or

    * there is not enough contiguous logical address space to create the
       area, or

    * there is not enough memory in the free pool to allocate level 2 page
       tables to cover the area at maximum size.

    If r1 is -1 on entry the RISC OS will allocate an area number itself.
    This will be greater than or equal to 256. This means (see section 6.6)
    that OS_ReadDynamicArea on these areas will always return with r2
    being the maximum area size.

    For singly mapped areas the base logical address is the lowest logical
    address used by that area. The area grows by adding pages at the high
    address end.

    For doubly mapped areas the base logical address is the (fixed) boundary
    between the two mappings: the first mapping ends at r3-1, and the second
    starts at r3. When one of these areas grows the pages in the first copy
    move down to accommodate the new pages at the end, and the second copy
    simply grows at the end.

    On entry, r6 points to the area handler routine which gets called with
    various reason codes when an an area is grown or shrunk. If zero is
    passed in, then no routine will be called, and any shrink or growth will
    be allowed.

    Details of the entry and exit conditions for this routine are given
    in section 6.3.2 below.

    The area is created initially with size zero (ie no pages assigned to
    it), and is then grown to the size specified in size r2, which involves
    the area handler being called in the same way as if   
    OS_ChangeDynamicArea was called to grow the area.

    The area is created with a maximum size equal to either the amount given
    in r5 on entry, or the total RAM size of the machine, if this is
    smaller. If r5 is -1 on entry, then the maximum size will be set to the
    total RAM size of the machine.

    If r3 on entry is -1, then RISC OS allocates a free area of logical
    address space which is big enough for the maximum size of the area.

    Once the area has been created Service_DynamicAreaCreate will be issued
    to inform the rest of the system about this change.

    Notes for application writers
    -----------------------------

    The following facilities:

     * the ability to create areas with specific area numbers
     * the ability to create areas at specific logical addresses
     * the ability to create doubly-mapped areas

    are intended for internal system use only.

    Applications should in general create only singly-mapped areas, and
    request that RISC OS allocate area numbers and logical addresses.

    This will prevent clashes of area numbers or addresses.

    6.3.1.2 Remove dynamic area
    ---------------------------

    This call removes a previously created dynamic area.

    On entry:   r0 = 1 (reason code)
                r1 = area number

    On exit:    All registers preserved

    An error is returned if the area was not removed for any reason.

    Before the area is removed, RISC OS attempts to shrink it to zero size.
    This is done using ChangeDynamicArea. If the ChangeDynamicArea returns
    an error then the area will be grown back to its original size using
    ChangeDynamicArea and the remove dynamic area call will return with an
    error. If the ChangeDynamicArea to reduce the area to 0 size worked then
    the area will be removed.

    Once the area has been removed Service_DynamicAreaRemove will be issued
    to inform the rest of the system about this change.


    6.3.1.3 Return information on dynamic area
    ------------------------------------------

    This call returns various information on a dynamic area.

    On entry:   r0 = 2 (reason code)
                r1 = area number

    On exit:    r2 = current size of area (in bytes)
                r3 = base logical address of area
                r4 = area flags
                r5 = maximum size of area
                r6 -> area handler routine
                r7 = workspace pointer for area handler
                r8 -> area description string (null terminated)

    Note that for doubly-mapped areas, r3 on exit from this call returns the
    address of the boundary between the first and second copies of the area,
    whereas OS_ReadDynamicArea returns the start address of the first copy
    (for backwards compatibility).

    6.3.1.4 Enumerate dynamic areas
    -------------------------------

    On entry:   r0 = 3 (reason code)
                r1 = area number or -1

    On exit:    r1 = next area number or -1

    This allows an application to find out what dynamic areas are defined.
    -1 is used to start the enumeration and -1 indicates that the
    enumeration has finished.


    6.3.1.5 Renumber dynamic area
    -----------------------------

    This call renumbers a dynamic area.

    On entry:   r0 = 4 (reason code)
                r1 = old area number
                r2 = new area number

    On exit:    All registers preserved

    An error is returned if the area specified by the old area number does
    not exist or if the new number clashes with an existing area.

    This call is intended for system use only.

    Once the dynamic area has been renumbered Service_DynamicAreaRenumber
    will be issued to inform the rest of the system about this change.


    6.3.1.6 Read size of application space
    --------------------------------------

    This call returns the maximum size of application space

    On entry:   r0 = 5 (reason code)

    On exit:    r5 = maximum size of application space

    This call is intended for system use only.



  6.3.2 Dynamic area handler routine
  ----------------------------------

  This section describes the reason codes passed to the dynamic area handler
  routine, with their entry and exit conditions.

  This routine is called when the size of an area is being changed.

  On entry, r0 contains a reason code, which describes what is happening.

  It should be noted that when called, OS_ChangeDynamicArea is currently at
  work and will reject requests to resize dynamic areas. As a consequence
  any SWIs which might resize a dynamic area should be avoided. Such things
  as OS_Module to claim some workspace are an example, and hence most file
  operations should be avoided (although I/O on an existing file is more
  safe than other operations).

  The reason codes are as follows:-

    6.3.2.1 PreGrow (0)
    -------------------

    This reason code is issued when a call to OS_ChangeDynamicArea results
    in an area growing. It is called before any pages are actually moved. It
    allows the handler to specify particular physical pages if it needs them
    (eg for the screen area), or to object to the size change.

    On entry:   r0 = 0 (reason code)
                r1 -> Page block
                        The physical page number entries will be set to -1
                r2 = number of entries in Page block (= number of pages
                      area is growing by)
                r3 = number of bytes area is growing by (= r2 * pagesize)
                r4 = current size of area (bytes)
                r5 = page size
                r12 -> workspace

    On exit:    If the growth is OK, then
                  r0 is preserved
                  If particular physical page numbers are required then all
                   the physical page number entries must be filled in with
                   the required pages. The other entries must be left alone.
                  V = 0
                else
                  r0 -> error to return, or zero to return generic error
                  V = 1
                endif
                All other registers preseved

    This call permits the dynamic area handler to request that specific
    pages be used for growing the area. If this is the case then all pages
    must be specified. The correspondence between the Page block and memory
    is that the first entry in the page block corresponds to the lowest
    memory address of the extension, and the last entry in the Page block
    the highest memory address.

    If an error is returned, then the area will not change size.

    6.3.2.2 PostGrow (1)
    --------------------

    This reason code is issued when a call to OS_ChangeDynamicArea results
    in an area growing. It is called after the PreGrow reason code has been
    issued successfully and the memory pages have been moved. It provides
    the handler with a list of which physical pages have been moved into the
    area.

    On entry:   r0 = 1 (reason code)
                r1 -> Page block
                       Only the physical page number entries are defined
                r2 = number of entries in Page block (= number of pages
                      area grew by)
                r3 = number of bytes area grew by
                r4 = new size of area (bytes)
                r5 = page size
                r12 -> workspace

    On exit:    All registers preserved

    6.3.2.3 PreShrink (2)
    ---------------------

    This reason code is issued when a call to OS_ChangeDynamicArea results
    in an area shrinking. It is called before any pages are moved. It allows
    the handler to limit the amount of memory moved out of the area, or to
    object to the size change altogether. The shrink amount alowed as
    returned by this reason code is permitted to be a non-page multiple. The
    ChangeDynamicArea code will ensure the shrink permitted is rounded down
    to a page multiple before it is actioned.

    On entry:   r0 = 2 (reason code)
                r3 = number of bytes area is shrinking by
                r4 = current size of area (bytes)
                r5 = page size
                r12 -> workspace

    On exit:    If shrink (even by reduced amount) is OK, then
                  r0 preserved
                  r3 = number of bytes area can shrink by. This must be less
                        than or equal to r3 on entry.
                  V = 0
                else
                  r0 -> error block, or zero to return generic error
                  r3 = 0
                  V = 1
                endif
                All other registers preserved

    6.3.2.4 PostShrink (3)
    ----------------------

    This reason code is issued when a call to OS_ChangeDynamicArea results
    in an area shrinking. It is always called after the PreShrink reason
    code has been issued successfully even if the memory pages can't be
    moved.

    On entry:   r0 = 3 (reason code)
                r3 = number of bytes area shrunk by
                r4 = new size of area (bytes)
                r5 = page size
                r12 -> workspace

    On exit:    All registers preserved


  6.3.3 Sequence Of Actions When OS_ChangeDynamicArea Is Called
  -------------------------------------------------------------

  This section has been provided to give an overview of what happens when a
  dynamic area's size is changed. This is presented as pseudo-code for
  clarity.

  Check IRQSemaphore - reject CDA if set

  Growing free pool:
  (no check for page availability - do as much as possible!)
  Application space being shrunk - confirm it's OK:
      If CAO in application space then
          UpCall_MovingMemory (asks application if it consents to
                memory move)
          If UpCall *not* claimed Then reject CDA
      Else
          Service_Memory (asks modules for objectors to the memory
                move)
          If Service *is* claimed then reject CDA
      EndIf
  Move pages from application space end to free pool

  Growing other dynamic area:
      Check for page availability - if not enough available bounce CDA with
          error
      Table of pages prepared:
          Allocates memory
          Fills in -1s for 'any page'
      PreGrow is called:
          replaces -1s if it wants
          objects about resize amount perhaps
      Check for unavailable pages:
          If there is a non -1 which can't be grabbed then reject CDA
      Check for application space resizing:
          If free pool < amount needed then
              If CAO in application space then
                  UpCall_MovingMemory (asks application if it consents to
                        memory move)
                  If UpCall *not* claimed Then reject CDA
              Else
                  Service_Memory (asks modules for objectors to the memory
                        move)
                  If Service *is* claimed then reject CDA
              EndIf
          EndIf
      Page replacements determined:
          Work out swap sequences on all non -1s
          Replace all -1s with actual pages
          Pages get grabbed first from the free pool, then underflowing into
          the application space
      Issue Service_PagesUnsafe (only if PreGrow specified pages)
      Pages get moved around:
          Do the page moving/swapping (don't swap if pages requested are in
                free pool)
      Issue Service_PagesSafe (only if PreGrow specified pages)
      PostGrow is called:
          Sorts out structures for the new size

  Shrinking free pool:
  Check if application space OK to grow:
      If application space < maximum then
          If CAO in application space then
              UpCall_MovingMemory (asks application if it consents to
                    memory move)
              If UpCall *not* claimed Then reject CDA
          Else
              Service_Memory (asks modules for objectors to the memory
                    move)
              If Service *is* claimed then reject CDA
          EndIf
      EndIf
  Move pages from free pool to application space

  Shrinking other dynamic area:
      PreShrink is called:
          objects about resize amount perhaps, or gives larger allowed size
          Sorts out structures for the new smaller size as the shrink
                  will definitely go ahead.
      Pages get moved around:
          Move pages from dynamic area to free pool
      PostShrink is called:
          Keep subsystem informed.



  It should be noted that the system stack is used for the page structure
  passed to the PreGrow routine. As a consequence there is a limit to the
  amount that an area can be grown by at one time. To get round this problem
  an area grow request of a large amount will be performed in several
  steps. If one of these steps fails then the grow will terminate early with
  the area grown by however much was achieved, but not by the full amount
  requested.

  You will notice two new service calls were used here:
  Service_PagesUnsafe
  Service_PagesSafe
  which are issued around page swapping to inform any DMA subsystems (eg
  IOMD DMA or second processor) that some pages are being swapped around.
  Here is the detailed description of these service calls:

    6.3.3.1 Service_PagesUnsafe
    ---------------------------

    On entry:   r1 = Service_PagesUnsafe
                r2 = Page block filled in by the PreGrow routine with the
                        two address fields filled in too.
                r3 = number of entries in Page block

    On exit:    All registers preserved

    The recipient of this service call is being told that the pages
    specified are about to be swapped around. Direct memory access
    activities involving the specified pages should be suspended until
    Service_PagesSafe has been received indicating the pages are safe.


    6.3.3.2 Service_PagesSafe
    -------------------------

    On entry:   r1 = Service_PagesSafe (&8F)
                r2 = Number of entries in each Page block
                r3 -> Page block before move
                r4 -> Page block after move

    On exit:    All registers preserved

    The recipient of this service call is being told that the pages
    specified have been swapped for different pages and what those different
    pages are. Note that the logical addresses in both Page blocks will
    match. The 'before' Page block will contain the physical page numbers
    and physical addresses of the pages which were replaced, and the 'after'
    block the page numbers and physical addresses of the pages which
    replaced them.

 6.3.4 Implementation Notes for OS_ChangeDynamicArea
 ---------------------------------------------------

There is an issue with OS_ChangeDynamicArea when a particular page is
requested by the growing dynamic area which is currently in use by the page
tables. The problem is that moving pages that themselves control where the
pages are is a tricky operation. This is exacerbated on level 1 page tables
even more because these are 16k (4 pages) big and must be 16k aligned. This
means that if a level 1 page table needs moving then another 4 page block
needs to be found - potentially resulting in more page swapping to make such
a gap. Level 2 page tables don't have this problem as they're 4k (1 page)
big.

Having said this, unless some mobility is permitted the minimum
configuration which would permit a '486 second processor to work would be
4MBytes. In a 2MByte machine 1M is left free of page tables to allow the
screen to grow, and the 2nd MByte would, as a consequence, be 'contaminated'
with page tables and so would be unavailable for the 2nd processor. If the
page tables could be moved they could reside in the 'screen' MByte as they
could be moved freely about if the screen needed to grow.

 6.3.5 OS_DynamicArea Service Calls
 ----------------------------------

  These service calls are designed to keep the rest of the system informed
  about changes to the dynamic areas. Their primary customer is the task
  manager, although other modules could make use of them.

  6.3.5.1 Service_DynamicAreaCreate (&90)
  ---------------------------------------

  On entry:      r1 = Service_DynamicAreaCreate (&90)
                 r2 = area number of area just created

  On exit:       All registers preserved
                 This service must not be claimed

  This service is issued just after the successful creation of a dynamic
  area.


  6.3.5.2 Service_DynamicAreaRemove (&91)
  ---------------------------------------

  On entry:      r1 = Service_DynamicAreaRemove (&91)
                 r2 = area number of area about to be removed

  On exit:       All registers preserved
                 This service must not be claimed

  This service is issued just before the removal of a dynamic
  area. It is issued during a call to OS_DynamicArea(1), after the area has
  been successfully reduced to zero size, but before it has been removed
  completely.


  6.3.5.2 Service_DynamicAreaRenumber (&92)
  -----------------------------------------

  On entry:      r1 = Service_DynamicAreaRenumber (&92)
                 r2 = old area number
                 r3 = new area number

  On exit:       All registers preserved
                 This service must not be claimed

  This service is issued during a call to OS_DynamicArea(2), ie when an area
  is being renumbered.


 6.4 New SWI: OS_Memory
 ----------------------

This SWI performs miscellaneous operations for memory management.

On entry:   r0 = reason code and flags. Bits o-7 are the reason code, bits
                8-31 are the flags which may be specific to the reason code.
            The other registers are specific to the reason code.

On exit:    The returned values are specific to the reason codes.

Here are the defined reason codes:

0-5: Page block Operations
0 - General Page block Operation
1-5 - reserved

6-8 - physical memory:
6 - read physical memory arrangement table size
7 - read physical memory arrangement table
8 - read amounts of various sorts of memory

9-? - I/O space information:
9 - read controller presence

The details of these are given below.

   6.4.1 OS_Memory Reason 0: General Page block Operation
   ------------------------------------------------------

   This reason code is used to convert between representations of memory
   addresses. The different memory spaces are logical memory, physical
   memory and physical pages.

   On entry:   r0 = flags:
                    bit     meaning
                    0-7     reason code (0-5)
                    8-9     which entry is defined in the Page block:
                            0 - Physical page number
                            1 - Logcial address
                            2 - Physical address
                    10      Physical page number will be filled in when set
                    11      Logical address will be filled in when set
                    12      Physical address will be filled in when set
                    13-14   Cachability control:
                            0 - no change
                            1 - no change
                            2 - disable caching on these pages
                            3 - enable caching on these pages
                    15-31   reserved - set to 0
               r1 -> Page block
               r2 = number of entries in page block

   On exit:    Page block updated as necessary

   The Page block will be scanned and the specified operations applied to
   it. It is possible to do address conversions and control the cachability
   on a per-page basis. If any page is found to be unconvertable or
   non-existent then an error will be returned and the cachability will be
   unaffected. Cachability is accumulated for each page. So, for example, if
   there are 5 clients which need caching turned off on a page then each of
   them must turn caching back on individually for that page actually to
   become cached again.

   Where an ambiguity may occur, for example in doubly-mapped areas such as
   the screen, one of the possible results will be chosen and filled in.

   This will only handle RAM addresses. The address fields may be non-page
   aligned.

   6.4.2 OS_Memory Reasons 6-8: Physical Memory
   --------------------------------------------

   These are provided to enable a program to find out what physical
   memory there is and its arrangement. The first two calls provide
   complete information on the available memory. The information is provided
   in the form of a table, with each page of physical memory space having
   one entry in the table. Due to the large number of pages the table is
   packed down to only 4 bits per page. In each byte of the table the low
   order 4 bits correspond to the page before the high order 4 bits, ie it
   is little-endian. This is the meaning of a nibble in the table:

        bit     meaning
        0-2     type of memory:
                0       not present
                1       DRAM
                2       VRAM
                3       ROM
                4       I/O
                5-7     Undefined
        3       0 - Page available for allocation
                1 - Page not available for allocation

   The page availability is based on whether it is RAM, and whether it has
   already been allocated in such a way that it can't be replaced with a
   different RAM page eg the OS's page tables or screen memory.

   The third call gives a summary of available memory.


     6.4.2.1 Read Physical Memory Arrangement Table Size
     ---------------------------------------------------

     On entry:   r0 = 6 (bits 8-31 clear)

     On exit:    r1 = table size (bytes)
                 r2 = page size (bytes)

     This returns information about the memory arrangement table.


     6.4.2.2 Read Physical Memory Arrangement Table
     -----------------------------------------------

     On entry:   r0 = 7 (bits 8-31 clear)
                 r1 = pointer to table to be filled in

     On exit:    registers preserved

     This returns the physical memory arrangement table in the block of memory
     pointed at by r1. Note the information about page availability may well
     change between this being called before a OS_ChangeDynamicArea and the
     PreGrow routine being called, in particular it may have been necessary
     for OS_ChangeDynamicArea to allocate level 2 page tables for the grown
     area, and these are not available for allocation. Hence, for
     applications which require, say, all pages from physical address 0
     onwards their PreGrow handler must make this call, rather than the
     information being extracted and held before OS_ChangeDynamicArea being
     called.


     6.4.2.3 Read Amounts Of Various Sorts Of Memory
     -----------------------------------------------

     On entry:   r0 = bits   meaning
                      0-7    must be 8 - its the reason code
                      8-11   the type of memory:
                             1 - DRAM
                             2 - VRAM
                             3 - ROM
                             4 - I/O
                      12-31  reserved - set to 0
              
     On exit:    r1 = number of pages of that sort of memory
                 r2 = page size (in bytes)


   6.4.3 I/O Space Information
   ---------------------------

   These give information about the I/O space. Controllers are identified by
   type and sequence number so that a machine could be constructed with,
   say, more than one IDE controller in it.

     6.4.3.1 Read Controller Presence
     --------------------------------

     On entry:   r0 = 9 (bits 8-31 clear)
                 r1 = controller ID
                      bit       meaning
                      0-7       controller sequence number
                      8-31      controller type:
                                0 - EASI card access speed control
                                1 - EASI space
                                2 - VIDC1
                                3 - VIDC20

     On exit:    r1 = controller base address or 0 if not present.

     This returns the location of a controller on the given machine. For
     example the EASI space gives the base address of podule N where N is
     the sequence number given. This reason code is provided for internal
     use only and is documented here for completeness' sake. In particular
     you must use the Podule manager to get at this information and to
     control your podule's EASI space access speed.

 6.5 Old SWI OS_SetMemMapEntries (&53)
 -------------------------------------

 As noted in the RISC OS 3 PRMs -1 should be used to indicate that a page
 should become inaccessible, for future compatibility. In the Medusa kernel
 the future has arrived - only -1 will work!

 6.6 Old SWI OS_ReadDynamicArea (&5C)
 ------------------------------------

 As noted in the RISC OS 3 PRMs if bit 7 of the dynamic area number is set
 then r2 will be returned with the maximum area size. This is being changed
 slightly to be that if the dynamic area number passed in is greater than or
 equal to 128 then r2 will be returned as the dynamic area size. Also, if
 the dynamic area number passed in is between 128 and 255 inclusive then the
 information will be returned for the area whose number is 128 less than the
 passed-in value. The net result is that for old dynamic area numbers (0-5)
 the functionality is unchanged, but the number-space impact of the
 interface is minimised - it was prety horrible to have to force bit 7 of
 all dynamic area numbers to be clear just for this SWI, so we just prohibit
 a small patch of low numbers instead.
 
 6.7 New SWI OS_ClaimProcessorVector
 -----------------------------------


 In
   r0=Vector and flags
         bit     meaning
         0-7     Vector number:
                 0 - 'Branch through 0' vector
                 1 - Undefined instruction
                 2 - SWI
                 3 - Prefetch abort
                 4 - data abort
                 5 - address exception (only on ARM 2 & 3)
                 6 - IRQ
                 7+ - reserved for future use
         8       0=release, 1=claim
         9-31    reserved, must be 0
   r1=replacement value
   r2=value which should currently be on vector (only needed for release)
 Out
   r1=value which has been replaced (only returned on claim)

 This SWI provides a means whereby a module can attach itself to one of the
 processor's vectors. This is a direct attachment - you get no environment
 except what the processor provides. As such, claiming and releasing the
 vectors is somewhat primitive - the claims and releases must occur in the
 right order (the release order being the reverse of claim order).

 On release if the value in r2 doesn't match what is currently on the vector
 then an error will be returned. This ensures correct chaining of claims and
 releases.

 [ Implementation note:
 On break the 1st ROM instruction gets copied to location 0 and branched to
 (MOV pc, #0). This used to be a branch direct (B thing) instruction, but
 will be changed to a branch indirect (LDR pc, [pc, #thing]). This means the
 indirection vector must be filled in with the correct reset address. Hence,
 the reset vector must be a different indirection vector to the 'Branch
 through 0' one.
 ]



 7. External Dependencies
 =========================

The development of the new memory management system relies upon the
availability of ARM600 (or 610) processor boards for A540s.

The Window Manager will need modification to cope with the changed memory
management system. In particular it will need to:
        Cope with the free pool being external to the wimp
        Change how it does TransferBlock operations
        Change how it gets the pages for new tasks


 8. Development Test Strategy
 =============================

PHTester scripts will be writen to exercise the following SWIs:
OS_Memory
 All reasons (0-9)
In range, edge of range, just outside range and wildly out of range values
will be tried. Where buffer contents are returned the buffer will be output.

OS_AbortTrap
Where this implemented then the test strategy would be as follows. Due to the
nature of this SWI unsupported PHTester scripts will not be able to do the
job properly. A piece of support code will be written which can be loaded
into RMA and will monitor calls to the abort trapper. A PHTester script will
be written which will load this trapper, add it, exercise it and monitor the
results. The trapper will then be removed twice to make sure the correct
behaviour results.

OS_ChangeDynamicArea
Again, this is hard to test with straight PHTester scripts. Under normal
circumstance the presence of PHTester running will prohibit dynamic areas
growing, however, this can be got around by growing a dynamic area before
PHTester starts, starting the script then shrink the dynamic area thus
giving the system a free pool (PHTester will refuse to allow the application
space to resize and thus the memory will be pushed into the free pool).
Support code will be writen which will monitor service calls and upcalls and
will exercise the various cases. This act of exercising must be done without
PHTester running.

OS_DynamicArea
Again, support code will be needed for PHTester to be usable. With this
support code PHTester scripts will be writen to add (twice) and remove
(twice) a dynamic area. This area will then be resized testing success and
failure of both grow and shrink, failing because of either not enough memory
or unavilable specific pages being requeested. A straight PHTester script
will be used to exercise enumeration, readinfo and renumber operations.



Testing the Wimp and Switcher

Wimp:

SWI Wimp_SlotSize

The behaviour of this SWI depends on a number of external (To the task and calling parameters) factors:
        - Environment, particularly MemoryLimit and ApplicationSpace
        - Machine state, eg. remaining amount of memory
        - Page size, to compare with ARM 3 systems units of 32K should be used

Shrinking a slot:
        Needs to be tested when MemLimit <> AppSpace, when MemLimit=AppSpace < RealSpace
        where RealSpace is actual memory mapped in- This feature is used extensively by flex.
        When a shrink succeedes, the free pool should grow by the shrinkage and the RMA by a roughly
        proportional ammount (for slot being reduced)

Growing a slot:
        Again Different environments need testing, but also effects near total memory usage:
        Eg. A large increase is requested, but only a smaller amount is available. Also when the 
        area has been grown, there may not be enough RMA to extend the Memory Map slot and so the
        slot shrinks by a page.

In both cases the SWI should return with the environment set to the real size and a message sent
to the switcher.

Application testing.
        As mentioned above, flex makes good use of the features of this SWI. Loading a file into !Draw
or !Paint should make the slot grow by a comparable amount to the file size (taking into account the
internal storage methods). When the document is discarded the slot should reduce to the value it was 
before (unless flex/malloc usage makes this impossible) and total RMA/system memory should be roughly
what it was, though of course for a first document load the application may claim additional memory.
        A small application could be written to do similar things repeatedly and could this give a
measure to memory leaks etc. Medusa is bound to be slower because of smaller page size, more pages (which
need to be scanned when growing a slot) and Log-Phys map (Level 2 table) being in RAM rather than on
chip.

SWI Wimp_TransferBlock

Many possible cases:
        Should always be possible even if no free memory.
        For tasks a,b,c (c is current task)
        a <-> b         a <-> c         c <-> c
                For small and large lengths     (eg. 1K or 8Meg)
                For when c takes up all/most of app space
                For when transfers occur to/from non application space (eg. RMA)
                For non word aligned/ size transfers
                For transfers involving over-the-page memory, eg. 34k-38k (32-36,36-40 pages)
        
Application testing.
        RAM transfer from !Paint to !Draw (this is c->a,small, prob aligned)
        Use of !SqlFiler and !Faults (this c(RMA)->a,small, prob aligned)
        Some combinations can only be tested on real Medusa's with 32Meg memory.

SWI Wimp_ClaimFreeMemory
        Only claimable once at a time, memory should be accessible and remain intact until free'd
        (incidentally can be freed by any task).

System testing
        *copy, *compact ?

Mode changing:

SWI Wimp_SetMode, *wimpmode
        numbers 0-255 as before (testable by script which then checks screen memory usage and VDU
variables) and new style configuration (again script can work out from config the mem usage and VDU
vars). Wimp should shrink screen memory as much as possible and send mode changed message to all tasks

Switcher:
        Dynamic areas used to be scanned (finding addresses for all the system pages) now RDA is used.
Dynamic areas (all, including app-created areas) should update when window is open and a task calls
CDA successfully. Areas which are non-fixed should be draggable, should reflect/update area as seen
by a task. Dragging bars should update memory text as appropriate, on medusa platforms with more than 
4Meg this should be logarithmic for large values. Switcher should behave as before on non medusa platforms.



 9. Organisation
 ================

 The software described herein resides in the RISC OS ROM.

 10. Future Enhancements
 =======================

Some sort of system to request memory to be freed in cases of memory
shortage might be nice.

OS_Heap to be extended to allow allocation of anchored moveable blocks. This
would be used to prevent heap fragmentation.

 10.1 New SWI: OS_AbortTrap (&67)
 --------------------------------

 This has been moved to the future enhancements section as this is not
 required by the project specification, there is insufficient time to do it
 and it can be added later if needed. Also, there are some unresolved issues
 regarding handling aborts of writes to &00-&1f and handling of coprocessor
 data transfer operations.

  10.1.1 Technical background
  ---------------------------

  The extra processor modes in the ARM6 and ARM7 processor cores allow for
  complete recovery from data aborts, even if the abort happens while in
  privileged modes, such as supervisor mode. This was not possible on
  earlier processors, because when the abort was taken, the return address
  (and condition codes) was placed in r14_svc, thereby corrupting it.

  This allows for (amongst other things) complete software emulation of
  hardware devices (apart from devices which cause interrupts, or which are
  very time-critical). In particular, it becomes possible to write a module
  which emulates VIDC1 on systems which are VIDC20 based (provided that the
  address map is set up so that the address where VIDC1 is accessed
  (&03400000) causes a data abort when written to).

  In order to facilitate this kind of activity, RISC OS allows a module to
  provide a trap routine for accesses within specified address ranges. This
  is an additional feature over and above the usual abort handlers which are
  owned by the current application.

  When a data abort happens, the OS works out the range of addresses
  accessed by the instruction.

  It then looks through its MMU page tables, and splits the range into
  sub-ranges which correspond to accesses within one page or section, as
  appropriate.

  For each sub-range, it then checks the access privileges to see if the
  access was valid. If so, it performs the access itself. (For a load, it
  transfers the data into a temporary stack frame from which the register(s)
  will be subsequently loaded. For a store, the stack frame is already set
  up with the register(s) to be stored.)

  If the sub-range corresponds to a page or section which would have caused
  an abort, the sub-range is then checked against its list of abort traps.
  Starting with the lowest address in the sub-range, if the address is
  contained within any of the address ranges specified in the list, then
  the corresponding routine is called. The registers on entry and on exit
  are as follows:-

  On entry:     r0 = flags
                        bits 1,0 = 00 undefined
                                   01 store
                                   10 load
                                   11 SWP

                        bit 2 = 0 => user mode access
                                1 => privileged mode access

                        bits 3..31 undefined

                r1 -> block of registers to be transferred to/from
                r2 = lowest address which faulted in the specifed address range
                r3 = number of transferred bytes which fall within the specified address range
                r4 -> instruction which aborted
                r12 = workspace ptr specified in node
                SVC26 (at the moment - I might change this to SVC32 at some stage)

  On exit:      VC => instruction processed, please complete writeback
                VS => instruction shouldn't be allowed - generate exception
                All registers preserved (apart from PSR)

  If the routine wishes to accept the transfer as valid, it must perform the
  transfer itself by transferring the data (of length r3 bytes) in or out of
  the block pointed to by r1. (In the case of the SWP instruction it must
  transfer data out of, then into the block). It should then exit with V=0.

  The OS will then advance its address pointer by the number of bytes
  processed by this routine, and continue with the next sub-range (if there
  are any more to do).

  If the routine wishes to fault the transfer after all, it should exit with
  V=1. This will cause the OS to call the normal data abort handler. (This
  also happens if an address in a sub-range which faulted does not lie in
  any address range on the list).

  Note: this behaviour currently precludes having two or more abort traps on
  the list which have overlapping address ranges, where each trap actually
  is interested in a subset of accesses within that range. At the moment,
  the OS faults if any trap routine exits VS, whereas it could carry on down
  the list looking for further trap ranges containing the address. But then
  you would have to have some way of returning saying you had done part of
  the transfer.

  In addition to trapping page and section faults, the OS has special code
  to deal with writes to addresses in the range &00 to &1F inclusive, which
  cause aborts on ARM6/7 when the processor is executing in a 26-bit PC mode
  (assuming we are in the 32-bit PC configuration, which we are).

  If the address range for the transfer includes an address in the range
  0-&1F, and the aborting instruction is within the RISC OS "ROM" image,
  then RISC OS executes the transfer itself (in 32-bit PC mode), as ROM code
  is considered kosher. This is mainly to allow FIQ claimants such as ADFS
  floppy drivers or Econet to set up their FIQ code while executing in
  26-bit PC mode. It also allows the FPE to set up the undefined instruction
  vector (although of course the FPE still has to know that it will get
  called in undef_32 mode).

  If the aborting instruction is not in the ROM image, then the usual abort
  list is checked. If however the address is not in the list, or the routine
  exits with V set, then instead of calling the current data abort handler,
  the OS calls its default data abort handler (this was so I could then do a
  *ShowRegs and find out where the program went bang, rather than have the C
  exception handler swallow it up).

  Note that if you set up a node to respond to vector poking, and you want
  to accept the transfer, you'll have to switch to SVC32 to execute it (this
  is why I may change the entry to be called in SVC32.

  10.1.2 New SWI: OS_AbortTrap (&66)
  ----------------------------------

  SWI OS_AbortTrap provides calls to add or remove abort trap routines.

  On entry, r0 provides a reason code which determines which operation is
  performed.

    10.1.2.1 Add abort trap (0)
    ---------------------------

    This reason code adds a trap routine to RISC OS's list.

    On entry:   r0 = 0 (reason code)
                r1 = lowest trapped address
                r2 = highest trapped address +1
                r3 = address of trap routine
                r4 = workspace pointer for trap routine

    On exit:    All registers preserved

    The entry and exit conditions for the trap routine are described in
    section x.y.z.

    10.1.2.2 Remove abort trap (1)
    ------------------------------

    This reason code removes a trap routine from RISC OS's list.

    On entry:   r0 = 1 (reason code)
                r1 = lowest trapped address
                r2 = highest trapped address +1
                r3 = address of trap routine
                r4 = workspace pointer for trap routine

    On exit:    All registers preserved

    Registers r1 to r4 on entry should be identical to those previously
    passed to reason code 0.
