www.riscos.com Technical Support: |
|
This chapter describes changes in memory management made in RISC OS 3.5. These changes have been caused by the changes in the underlying hardware used in the new architecture.
Memory management now incorporates the following:
The new generation of ARM chips used provide 26 bit processor modes (which are backwards compatible with the ARM2 and ARM3), and 32 bit processor modes. With one exception, RISC OS 3.5 only supports 26 bit processor modes. You must not execute code in 32 bit processor modes. If you try to do so, you may get unpredictable crashes, especially if you try to run the code in address space over 64M.
The exception mentioned above is if you are writing handlers that claim a hardware vector. For details, see the chapter entitled Hardware vectors.
In RISC OS 2 and 3 memory management was divided between the kernel and the Wimp.
RISC OS 3.5 supports amounts of memory so large that the free pool may now be too large to map into application space.
When you grow or shrink dynamic areas other than the free pool, the free pool is used as follows:
If 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.
The Wimp grows or shrinks tasks by shrinking or growing (respectively) the free pool itself:
The tasks themselves must still change their memory allocation using current RISC OS interfaces (as before), rather than changing the size of the free pool.
In RISC OS 2 and 3 the main kernel interface for memory management was OS_ChangeDynamicArea, with which you could resize the predefined dynamic areas. This SWI then called other modules, depending on which dynamic area was being resized. This left no flexibility, and in particular, there were no facilities for creating other dynamic areas. This meant the existing areas were often used illicitly by applications which - once they quit - would leave the area badly fragmented.
Other memory related services were not available. For example it was not possible to find out what memory was available on the system without knowing a great deal about the platform.
From RISC OS 3.5 onwards the new SWI OS_DynamicArea is provided for you to create dynamic areas, get information on them, and delete them. This allows you to claim and release your own area of memory that is managed by hardware (and so does not suffer from garbage), and is persistent. This is far preferable to illicitly using (say) a part of the RMA or sprite area, as has been common practice.
You should still use OS_ChangeDynamicArea just as before to alter the size of dynamic areas.
As all operations on dynamic areas work in physical page numbers you cannot map anything other than RAM pages (DRAM and VRAM) into a dynamic area. In particular you cannot map in the extension to the existing expansion card bus space, known as the EASI space.
Base | Description | Size |
---|---|---|
2.5G | More dynamic areas | 1.5G Public5 |
2G | Copy of physical space | 512M Private |
64M | Dynamic areas | 2G-64M Public5 |
56M | ROM | 8M Private |
55M | Reserved for 2nd processor control registers | 1M Private |
54M | Reserved for future expansion | 1M Private |
53M | VIDC20 | 1M Private |
52M | Reserved for VIDC1 emulation | 1M Private |
48M | I/O space | 4M Private4 |
44M | Reserved for system use | 4M Private |
33M | RMA | 11M Public3 |
31M+64K | Reserved for fake screen (480K) | 2M-64K Private |
31M+32K | "Nowhere" | 32K Private |
31M | Cursor / system space / sound DMA | 32K Private |
30M+8K | Soft CAM map | 1M-8K Private |
30M | Undefined stack | 8K Public2 |
28M+8K | System heap | 2M-8K Private |
28M | SVC stack | 8K Public2 |
32K | Application space | 28M-32K Public |
16K | Scratch space | 16K Public1 |
0 | System workspace | 16K |
Notes about the logical memory map:
An example client would be FileCore using the scratch space to hold structures while working out how to allocate some free space. Another example would be the Filer using the scratch space to hold structures for OS_HeapSort.
There are three ways of referring to memory:
This refers to the address of the memory in the physical address space, as presented by the ARM chip to IOMD.
This refers to the logical address space that the ARM processor core presents to the ARM chip memory management unit. This is controlled by the operating system.
This is an arbitrary number assigned to each page of RAM physically present in the computer.
Several interfaces use page blocks to pass round lists of addresses and/or pages. These are tables of 12-byte records (so a page block is 12n bytes long, where n is the number of records). Each record has the following format:
Offset | Meaning |
---|---|
0 | Physical page number |
4 | Logical address |
8 | Physical address |
The following new SWIs have been created. They are defined in full at the end of this chapter.
You can now alter the space allocation of the free pool (see Free memory pool) by setting R0 to 6 on entry.
With the new architecture you must use -1 to indicate that a page should become inaccessible.
In RISC OS 3, if bit 7 of the dynamic area number is set then R2 will be returned with the maximum area size.
This has changed slightly from RISC OS 3.5 onwards.
If the dynamic area number passed in is greater than or equal to 128 then R2 is returned as the maximum size of the dynamic area. Also, if the dynamic area number passed in is between 128 and 255 inclusive then the information is 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.
Also, if R0 is -1 on entry, it returns the following information on application space:
R0 = base address (&8000)
R1 = current size (ie for current task)
R2 = maximum size ( 28MB-32kB in current implementation)
RISC OS 2 and 3 place strong restrictions on the heap: the base of the heap as specified in R1 must be word-aligned and less than 32Mbytes, and the size of the heap must be a multiple of 4 and less than 16Mbytes.
From RISC OS 3.5 onwards the only restrictions are that the base of the heap must be word-aligned, and the size must be a multiple of 4 bytes.
In earlier operating systems Wimp_TransferBlock put all used task memory into the application space, and then copied the relevant parts over. It cannot do this any more, as the total used task memory may not fit into application space.
The algorithm used by this call has accordingly been changed, and the opportunity taken to improve its performance. The call still has the same entry and exit conditions.
Because the Wimp no longer maintains control of the free pool, the call Wimp_ClaimFreeMemory has had to be modified; it simulates its previous behaviour as well as possible. In general, applications written for older versions of RISC OS will work unmodified; but you should be aware that the call may now return addresses that use more than 26 bits. This will be a problem if your old applications use any of the top 6 bits for their own purposes.
Using this call in new applications is deprecated. You should instead use OS_DynamicArea to create your own dynamic area.
These ARM3-specific SWIs are not implemented from RISC OS 3.5 onwards.
When you create a dynamic area with the new SWI OS_DynamicArea 0 you can also specify the address of a dynamic area handler routine, which is called when the size of the area is being changed. The routine is called in SVC mode; the reason for calling it is given in a reason code held in R0. The section below gives the entry and exit conditions of the routine for each valid reason code.
When called, OS_ChangeDynamicArea is working. It rejects requests to resize dynamic areas. You should not use SWIs which resize dynamic areas, for example using OS_Module to claim some workspace. File operations should be normally avoided, although I/O on an existing file is usually safe.
Issued just before pages are moved to grow an area
R0 = 0 (reason code)
R1 = pointer to a page block, the physical page numbers of which are set to -1; or undefined if bit 8 of the areas flags was clear on creation (see OS_DynamicArea 0)
R2 = number of entries in page block (i.e. number of pages area is growing by)
R3 = amount area is growing by, in bytes (i.e. R2 × R5)
R4 = current size of area, in bytes
R5 = page size, in bytes
R12 = pointer to workspace
All registers preserved
This reason code is issued when a call to OS_ChangeDynamicArea results in an area growing, before any pages are actually moved.
You can request that specific pages be used for growing the area by filling in their page numbers in the page block. If you do so, you must specify all the pages. 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.
You can prevent the area changing size by returning an error. R0 should point to a standard RISC OS error block, or be set to zero for a generic error message to be used. You should then return with the V flag set.
Issued just after pages are moved to grow an area
R0 = 1 (reason code)
R1 = pointer to a page block, only the physical page numbers of which are defined; or undefined if bit 8 of the areas flags was clear on creation (see OS_DynamicArea 0)
R2 = number of entries in page block (i.e. number of pages area grew by)
R3 = amount area grew by, in bytes (i.e. R2 × R5)
R4 = new size of area, in bytes
R5 = page size, in bytes
R12 = pointer to workspace
All registers preserved
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.
Issued just before pages are moved to shrink an area
R0 = 2 (reason code)
R3 = amount area is shrinking by, in bytes
R4 = current size of area, in bytes
R5 = page size, in bytes
R12 = pointer to workspace
R3 = amount area can shrink by, in bytes (must be R3 on entry)
All other registers preserved
This reason code is issued when a call to OS_ChangeDynamicArea results in an area shrinking, before any pages are moved. You can limit the amount of memory moved out of the area. If the permitted shrinkage you return is a non-page multiple, it will be rounded down to a page multiple.
You can prevent the area changing size by returning an error. R0 should point to a null terminated error message, or be set to zero for a generic error message to be used. R3 should be zero, to show that no shrinkage is possible. You should then return with the V flag set.
Issued just after pages are moved to shrink an area
R0 = 3 (reason code)
R3 = amount area shrunk by
R4 = new size of area, in bytes
R5 = page size, in bytes
R12 = pointer to workspace
All registers preserved
This reason code is issued when a call to OS_ChangeDynamicArea results in an area shrinking. It is called after the PreShrink reason code has been issued successfully even if the memory pages cannot be moved.
The system stack is used for the page block passed to the PreGrow routine, where required. 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.
Two new service calls are used; Service_PagesUnsafe and Service_PagesSafe. These are issued around page swapping to inform any DMA subsystems (eg IOMD DMA or second processor) that some pages are being swapped around.
R1 = &8E (reason code)
R2 = page block filled in by the PreGrow routine, with the two address fields also filled in
R3 = number of pages in page block
All registers preserved
This service call informs recipients that the pages specified are about to be swapped for different pages. Direct memory access activities involving the specified pages should be suspended until Service_PagesSafe has been received indicating the pages are safe.
You must not claim this service call.
This service call is only issued from RISC OS 3.5 onwards.
R1 = &8F (reason code)
R2 = number of entries in each page block
R3 = pointer to page block before move
R4 = pointer to page block after move
All registers preserved
This service call informs recipients that the pages specified have been swapped for different pages and what those different pages are.
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 swapped, and the 'after' block the page numbers and physical addresses of the different pages which replaced them.
You must not claim this service call.
This service call is only issued from RISC OS 3.5 onwards.
R1 = &90 (reason code)
R2 = area number of dynamic area just created
All registers preserved
This service call is issued just after the successful creation of a dynamic area.
This service call keeps the rest of the system informed about changes to the dynamic areas. It is used by the Task Manager, although other modules could make use of it.
You must not claim this service call.
This service call is only issued from RISC OS 3.5 onwards.
R1 = &91 (reason code)
R2 = area number of dynamic area about to be removed
All registers preserved
This service call is issued just before the removal of a dynamic area, after the area has been successfully reduced to zero size, but before it has been removed completely.
This service call keeps the rest of the system informed about changes to the dynamic areas. It is used by the Task Manager, although other modules could make use of it.
You must not claim this service call.
This service call is only issued from RISC OS 3.5 onwards.
R1 = &92 (reason code)
R2 = old area number
R3 = new area number
All registers preserved
This service call is issued when a dynamic area is being renumbered.
This service call keeps the rest of the system informed about changes to the dynamic areas. It is used by the Task Manager, although other modules could make use of it.
You must not claim this service call.
This service call is only issued from RISC OS 3.5 onwards.
R0 = reason code
Other registers depend upon the reason code
R0 preserved
Other registers depend upon the reason code
Interrupt status is undefined
Fast interrupts are enabled
Processor is in SVC mode
Not defined
This SWI provides a number of calls to perform operations on dynamic areas.
The particular action of OS_DynamicArea is given by the reason code in R0 as follows:
R0 | Action | Page |
---|---|---|
0 | Creates a new dynamic area | OS_DynamicArea 0 |
1 | Removes a previously created dynamic area | OS_DynamicArea 1 |
2 | Returns information on a dynamic area | OS_DynamicArea 2 |
3 | Enumerates dynamic areas | OS_DynamicArea 3 |
4 | Renumbers dynamic areas | OS_DynamicArea 4 |
This call is only available from RISC OS 3.5 onwards.
None
R0 = 0 (reason code)
R1 = -1 (or new area number not in range 128 - 255; this is reserved for Acorn use)
R2 = initial size of area, in bytes
R3 = -1 (or base logical address of area; this is reserved for Acorn use)
R4 = area flags (see below)
R5 = maximum size of area, in bytes (-1 total RAM size of the machine)
R6 =pointer to dynamic area handler routine, or 0 if no routine
R7 = pointer to workspace, passed in R12 on entry to dynamic area handler routine; or -1 for RISC OS to instead pass base address of area; or 0 if R6 = 0
R8 = pointer to null terminated string describing dynamic area (e.g. 'Font cache')
R0 preserved
R1 = allocated area number
R2 preserved
R3 = specified or allocated base address of area
R4 preserved
R5 = specified or allocated maximum size of area
R6 - R8 preserved
This call creates a new dynamic area.
The area is created initially with size zero (no pages assigned to it), and is then grown to the size specified in R2, which involves calling the area handler (if any) pointed to by R6. The area's maximum size is set to the lesser of the amount given in R5 on entry and the total RAM size of the machine; or to the total RAM size if R5 was -1 on entry.
RISC OS allocates a free area of logical address space which is big enough for the dynamic area's maximum size. The base logical address is the lowest logical address used by that area. The area grows by adding pages at the high address end.
RISC OS allocates an area number itself, which is greater than or equal to 256. This means that a call to OS_ReadDynamicArea will always return the maximum area size in R2 for these areas.
The area flags passed in R4 are as follows:
Bit(s) | Meaning |
---|---|
0 - 3 | access privileges to be given to each page in the area (same format as for OS_Read/SetMemMapEntries) |
4 | 0 area is bufferable |
1 area is not bufferable | |
5 | 0 area is cacheable |
1 area is not cacheable | |
6 | 0 area is singly mapped |
1 area is doubly mapped (reserved for Acorn use) | |
7 | 0 area size may be dragged by the user in Task Manager window (has red bar) |
1 area size may not be dragged by the user in Task Manager window (has green bar) | |
8 | 0 area does not require specific physical pages (ie R1 is undefined on entry to the PreGrow and PostGrow handlers) |
1 area may require specific physical pages (ie R1 points at a page block on entry to the PreGrow and PostGrow handlers) | |
9 - 31 | reserved (must be zero) |
The description string passed in R8 is used by the TaskManager in its display.
Once the area has been created, Service_DynamicAreaCreate is issued to inform the rest of the system about this change.
If the create dynamic area call returns an error for any reason, it may be assumed that the new area has not been created.
Applications should 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. For details of other usage, which has been provided largely for internal backwards compatibility, see the section entitled System use below.
On entry, R6 points to the area handler routine which gets called with various reason codes when an area is grown or shrunk, and R7 specifies the workspace pointer that is passed to it in R12. If zero is passed in R6, then no routine will be called, and any shrink or grow will be allowed.
Details of the entry and exit conditions for this routine are given in the Dynamic area handler routinessection.
An error will be returned if:
The following facilities are intended for internal system use only:
The ability to create areas at specific logical addresses.
On entry, R3 holds the base address of the area, which must be aligned on a memory page boundary (to read the page size use OS_ReadMemMapInfo). With this usage, RISC OS does not allocate and area of logical address spage for the dynamic area.
The ability to create doubly-mapped areas.
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 one copy move down to accomodate the new pages at the end, and the second copy simply grows at the end.
R0 = 1 (reason code)
R1 = area number
All registers preserved
This call removes a previously created dynamic area.
Before the area is removed, RISC OS attempts to shrink it to zero size. This is done using OS_ChangeDynamicArea. If OS_ChangeDynamicArea returns an error, then the area will be grown back to its original size using OS_ChangeDynamicArea, and this call will return with an error. If OS_ChangeDynamicArea successfully reduced the area to zero size, then it will be removed.
Once the area has been removed Service_DynamicAreaRemove is issued to inform the rest of the system about this change.
An error is returned if the area was not removed for any reason.
R0 = 2 (reason code)
R1 = area number
R0, R1 preserved
R2 = current size of area, in bytes
R3 = base logical address of area
R4 = area flags
R5 = maximum size of area, in bytes
R6 = pointer to dynamic area handler routines, or 0 if no routine
R7 = pointer to workspace, passed in R12 on entry to dynamic area handler routine
R8 = pointer to null terminated string describing dynamic area (e.g. 'Font cache')
This call returns information on a dynamic area.
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).
R0 = 3 (reason code)
R1 = -1 to start enumeration, or area number
R1 = next area number, or -1 if no further areas
This call enumerates dynamic areas.
This allows an application to find out what dynamic areas are defined. -1 is passed on entry to start the enumeration; the call is then repeated until -1 is returned on exit, which indicates that the enumeration has finished.
R0 = 4 (reason code)
R1 = old area number
R2 = new area number
R0 - R2 preserved
This call renumbers dynamic areas, and is intended for system use only.
Once the area has been renumbered Service_DynamicAreaRenumber is issued to inform the rest of the system about this change.
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.
R0 = reason code (bits 0 - 7) and flags (bits 8 - 31, reason code specific)
Other registers depend upon the reason code
R0 preserved
Other registers depend upon the reason code
Interrupt status is undefined
Fast interrupts are enabled
Processor is in SVC mode
Not defined
This SWI performs miscellaneous operations for memory management.
The particular action of OS_Memory is given by the reason code in bits 0 - 7 of R0 as follows:
R0 | Action | page |
---|---|---|
0 | General page block operations | OS_Memory 0 |
1 - 5 | Reserved for system use | OS_Memory 1 - 5 |
6 | Reads the size of the physical memory arrangement table | OS_Memory 6 |
7 | Reads the physical memory arrangement table | OS_Memory 7 |
8 | Reads the amount of a specified sort of memory available in the computer | OS_Memory 8 |
9 | Reads controller presence and base address | OS_Memory 9 |
This call is only available from RISC OS 3.5 onwards.
None
None
R0 = reason code and flags:
Bits | Meaning |
---|---|
0 - 7 | 0 (reason code) |
8 | physical page number provided when set |
9 | logical address provided when set |
10 | physical address provided when set |
11 | physical page number will be filled in when set (if bit 8 also clear) |
12 | logical address will be filled in when set (if bit 9 also clear) |
13 | physical address will be filled in when set (if bit 10 also clear) |
14 - 15 | cacheability control: |
0 no change | |
1 no change | |
2 disable cacheing on all specified pages | |
3 enable cacheing on all specified pages | |
16 - 31 | reserved (must be clear) |
R0 - R2 preserved
This call converts between the different memory spaces used to specify addresses in a page block: i.e. logical address, physical address, and physical page number. It can also alter the cacheability of pages. The addresses must be in RAM, but need not be page-aligned. You can do address conversions and control the cacheability on a per-page basis. You need not do any conversion when changing cacheability (i.e. bits 11 - 13 may be clear).
The page block is scanned and the specified operations applied to it. If any page is made physically uncacheable, then the cache will be flushed before the SWI exits. If any page cannot be converted or is non-existent then an error will be returned and the cacheability unaffected.
Cacheability is accumulated for each page. For example, if there are five clients which need cacheing turned off on a page, then each of them must turn cacheing 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.
These reason codes are for system use only; you must not use them in your own code.
R0 = 6 (reason code); all flags are reserved, so bits 8 - 31 must be clear
R0 preserved
R1 = table size (in bytes)
R2 = page size (in bytes)
This call reads the size of the physical memory arrangement table, as returned by OS_Memory 7.
R0 = 7 (reason code); all flags are reserved, so bits 8 - 31 must be clear
R1 = pointer to table to be filled in
R0, R1 preserved
This call reads the physical memory arrangement table into the block of memory pointed to by R1. (You can find the required size of the block by calling OS_Memory 6.)
Each page of physical memory space has 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, i.e. the table 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.
If an area has particular requirements on the physical addresses used by it (eg if it needs contiguous physical memory for its area) we recommend that you issue this call inside the area's PreGrow handler, and then choose which pages to ask for on the basis of this information. This is preferable to issuing the call before you create the area, because the page availability may change during the process of creating the area.
Reads the amount of a specified sort of memory available in the computer
R0 = reason code and flags:
Bits | Meaning |
---|---|
0 - 7 | 8 (reason code) |
8 - 11 | type of memory: |
1 DRAM | |
2 VRAM | |
3 ROM | |
4 I/O | |
12 - 31 | reserved (must be clear) |
R0 preserved
R1 = number of pages of specified sort of memory
R2 = page size (in bytes)
This call reads the amount of a specified sort of memory available in the computer. For I/O memory, all I/O memory is included: ie I/O space, VIDC space, and EASI space.
R0 = 9 (reason code); all flags are reserved, so bits 8 - 31 must be clear
R1 = controller ID:
Bit | Meaning |
---|---|
0 - 7 | controller sequence number |
8 - 31 | controller type: |
0 EASI card access speed control (for internal use only) | |
1 EASI space (for internal use only) | |
2 VIDC1 | |
3 VIDC20 |
R0 preserved
R1 = controller base address, or 0 if not present.
This call checks for the presence of a given controller, and returns its base address if it is fitted. Controllers are identified by type and sequence number so that a machine could be constructed with, say, more than one IDE controller in it.
For EASI space this call gives the base address of expansion card 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 Expansion Card Manager to read this information and to control your expansion card's EASI space access speed.
R0 = reason code and flags (must be zero)
R1 = XOR mask
R2 = AND mask
R1 = old value of control register
R2 = new value of control register
Interrupt status is undefined
Fast interrupts are enabled
Processor is in SVC mode
Not defined
This call modifies the ARM MMU control register. The new value of the register is:
((old value AND R2) XOR R1)
The old value of the register is returned in R1, and the new value in R2. If the call results in the C (Cache enable) bit being changed, the cache is flushed.
This call is intended for internal system use only. Users wishing to enable or disable the cache should use the *Cache command instead.
This call is only available from RISC OS 3.5 onwards.
None