From 4a30b6432b9df8120f0240a77829b09fe7f58060 Mon Sep 17 00:00:00 2001 From: Jeffrey Lee <jlee@gitlab.riscosopen.org> Date: Sat, 10 Dec 2011 19:03:49 +0000 Subject: [PATCH] Improve heap manager. Add heap testbed. Add dummy implementation of some OS_ScreenMode reason codes. Detail: s/HeapMan, hdr/KernelWS - Heap manager improvements: - Errors generated by interrupted heap operations that are forced to complete by a OS_Heap call from the background are now cached in kernel workspace until the foreground task is resumed. This prevents them from being potentially overwritten by MessageTrans running out of background error buffers. - Added new OS_Heap reason code, #7 - Get area aligned. This allows areas of memory to be allocated at specific (power-of-2) alignments, and optionally without crossing a given (power-of-2) boundary. Alignment & boundary calculations are performed using logical addresses. - Removed the limitation that all free and allocated blocks must be a multiple of 8 bytes in length. This change was required in order to allow OS_Heap 7 to function correctly. Now the only requirements are that blocks must be multiples of 4 bytes in length, at 4 byte alignment, with a minimum length of 8 bytes. 4 extra padding bytes may still be added to the end of allocations in order to avoid creating 4-byte free blocks. s/HeapMan, TestSrc/HeapTest/Makefile, TestSrc/HeapTest/c/testbed, TestSrc/HeapTest/s/asm - Added heap testbed program. Can either use the OS_Heap SWI or directly include a copy of the Kernel's heap manager sources. s/vdudecl, s/vduswis - Added dummy implementations of OS_ScreenMode 4, 5 and 6. This prevents the Wimp generating lots of "Unknown OS_ScreenMode reason code" errors when redrawing the screen. s/Arthur3, s/Oscli - Moved dotstring closer to where it's used to avoid "ADRL out of range" errors in Tungsten build Admin: Tested in OMAP3 ROM & Tungsten ROM softload. Heap testbed successfully performed over 400 million heap ops, so there shouldn't be any serious bugs in the new code (touch wood) Version 5.35, 4.79.2.128. Tagged as 'Kernel-5_35-4_79_2_128' --- Dev/HeapTest/Makefile | 20 ++ Dev/HeapTest/c/testbed | 500 +++++++++++++++++++++++++++++++++++++++++ Dev/HeapTest/s/asm | 113 ++++++++++ VersionASM | 10 +- VersionNum | 14 +- hdr/KernelWS | 2 + s/Arthur3 | 2 + s/HeapMan | 458 +++++++++++++++++++++++++++++++++---- s/Oscli | 3 +- s/vdu/vdudecl | 5 +- s/vdu/vduswis | 54 ++++- 11 files changed, 1124 insertions(+), 57 deletions(-) create mode 100644 Dev/HeapTest/Makefile create mode 100644 Dev/HeapTest/c/testbed create mode 100644 Dev/HeapTest/s/asm diff --git a/Dev/HeapTest/Makefile b/Dev/HeapTest/Makefile new file mode 100644 index 0000000..0bc4f42 --- /dev/null +++ b/Dev/HeapTest/Makefile @@ -0,0 +1,20 @@ +# Copyright 2011 Castle Technology Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +COMPONENT = HeapTest +OBJS = asm testbed + +include CApp + +# Dynamic dependencies: diff --git a/Dev/HeapTest/c/testbed b/Dev/HeapTest/c/testbed new file mode 100644 index 0000000..420ee13 --- /dev/null +++ b/Dev/HeapTest/c/testbed @@ -0,0 +1,500 @@ +/* Copyright 2011 Castle Technology Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* OS_Heap testbed code. Creates a heap and randomly allocates/deallocates/ + resizes blocks of memory to test for any bugs. Tests can either be performed + using the OS_Heap SWI or by compiling a special version of the heap code + from the kernel source folder (see USE_LOCAL_OSHEAP #define and s.asm) +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <stdbool.h> +#include <time.h> + +#include "kernel.h" +#include "swis.h" + +#include "Global/Heap.h" +#include "Global/NewErrors.h" + +/* Whether to use the XOS_Heap SWI or the local copy of the heap code */ +#define USE_LOCAL_OSHEAP + +/* Maximum number of allocations to make */ +#define MAX_ALLOCS 1024 + +#define VBIT (1<<28) + +#ifdef USE_LOCAL_OSHEAP +extern _kernel_oserror *CallHeap(_kernel_swi_regs *r); +#else +#define CallHeap(R) _kernel_swi(OS_Heap,R,R) +#endif + +/* Workspace */ +static uint32_t *heap=NULL; /* Main heap */ +static uint32_t *backup=NULL; /* Backup copy of heap */ +static uint32_t allocsize=0; /* Heap memory block size */ +static uint32_t *usedspace=NULL; /* Bitmap of used space; 1 bit per word */ +static uint32_t seed=0; /* RNG seed */ +static uint32_t sequence=0; /* Number of ops performed */ +static uint32_t numblocks=0; /* Number of blocks currently allocated */ +static uint32_t blocks[MAX_ALLOCS]; /* Offsets of blocks within heap */ +static uint32_t currentop = 0; /* Current heap operation */ +static uint32_t opsleft = 0; /* Number of ops left */ +static _kernel_swi_regs r; +static _kernel_swi_regs last; + +/* Utility functions */ + +static void init(void) +{ + srand(seed); + printf("Seed %08x alloc size %08x\n",seed,allocsize); + /* Make heap 4K aligned */ + heap = (uint32_t *) (((uint32_t) malloc(allocsize+4096)+4095)&0xfffff000); + /* Same for backup */ + backup = (uint32_t *) (((uint32_t) malloc(allocsize+4096)+4095)&0xfffff000); + /* Used space map */ + usedspace = (uint32_t *) malloc(((allocsize+31*4)>>7)<<2); + memset(usedspace,0,((allocsize+31*4)>>7)<<2); + memset(heap,0,allocsize); + memset(backup,0,allocsize); +} + +static uint32_t getrand(uint32_t max) +{ + uint64_t temp = ((uint64_t) max)*rand(); + return (uint32_t) (temp/RAND_MAX); +} + +static void dumpheap(uint32_t *h) +{ + fprintf(stderr,"heap @ %p:\nmag %x\nfree %x\nbase %x\nend %x\n",h,h[0],h[1],h[2],h[3]); + uint32_t free = h[1]; + uint32_t next = 16; + if(free) + free += 4; + while(free) + { + if(free > next) + { + fprintf(stderr,"allocs between %x and %x:\n",next,free); + do { + fprintf(stderr,"%x: alloc size %x\n",next,h[next>>2]); + if((h[next>>2] > h[2]) || (h[next>>2]+next > h[2]) || (h[next>>2]&3) || !h[next>>2]) + { + fprintf(stderr,"bad block, skipping rest\n"); + break; + } + next += h[next>>2]; + } while(free>next); + if(free!=next) + fprintf(stderr,"alloc mismatch! next=%x\n",next); + } + fprintf(stderr,"%x: free size %x next %x\n",free,h[(free+4)>>2],h[free>>2]); + if(h[(free+4)>>2] == h[free>>2]) + fprintf(stderr,"consecutive free blocks!\n"); + next = free+h[(free+4)>>2]; + if((h[free>>2] & 3) || (h[free>>2] >= h[2]) || (h[free>>2]+free >= h[2])) + { + fprintf(stderr,"bad next ptr\n"); + return; + } + if((h[(free+4)>>2] & 3) || (h[(free+4)>>2] >= h[2]) || (h[(free+4)>>2]+free >= h[2])) + { + fprintf(stderr,"bad size\n"); + return; + } + if(!h[free>>2]) + { + fprintf(stderr,"end of free list\n"); + break; + } + free = free+h[free>>2]; + if(free<next) + { + fprintf(stderr,"next free is inside current?\n"); + return; + } + } + if(free > h[2]) + { + fprintf(stderr,"free list extends beyond heap end\n"); + } + if(next > h[2]) + { + fprintf(stderr,"next ptr beyond heap end\n"); + } + fprintf(stderr,"end allocs:\n"); + while(next < h[2]) + { + fprintf(stderr,"%x: alloc size %x\n",next,h[next>>2]); + if((h[next>>2] > h[2]) || (h[next>>2]+next > h[2]) || (h[next>>2]&3) || !h[next>>2]) + { + fprintf(stderr,"bad block, skipping rest\n"); + return; + } + next += h[next>>2]; + } + fprintf(stderr,"end\n"); +} + +static bool heapvalid(uint32_t *h) +{ + uint32_t free = h[1]; + uint32_t next = 16; + if(free) + free += 4; + while(free) + { + if(free > next) + { + do { + if((h[next>>2] > h[2]) || (h[next>>2]+next > h[2]) || (h[next>>2]&3) || !h[next>>2]) + { + return false; + } + next += h[next>>2]; + } while(free>next); + if(free!=next) + return false; + } + if(h[(free+4)>>2] == h[free>>2]) + return false; + next = free+h[(free+4)>>2]; + if((h[free>>2] & 3) || (h[free>>2] >= h[2]) || (h[free>>2]+free >= h[2])) + { + return false; + } + if((h[(free+4)>>2] & 3) || (h[(free+4)>>2] >= h[2]) || (h[(free+4)>>2]+free >= h[2])) + { + return false; + } + if(!h[free>>2]) + { + break; + } + free = free+h[free>>2]; + if(free<next) + { + return false; + } + } + if(free > h[2]) + { + return false; + } + if(next > h[2]) + { + return false; + } + while(next < h[2]) + { + if((h[next>>2] > h[2]) || (h[next>>2]+next > h[2]) || (h[next>>2]&3) || !h[next>>2]) + { + return false; + } + next += h[next>>2]; + } + return true; +} + +static void fail(void) +{ + fprintf(stderr,"Failed on sequence %d\n",sequence); + fprintf(stderr,"Last op registers:\n"); + for(int i=0;i<5;i++) + fprintf(stderr,"r%d = %08x\n",i,last.r[i]); + fprintf(stderr,"Result registers:\n"); + for(int i=0;i<5;i++) + fprintf(stderr,"r%d = %08x\n",i,r.r[i]); + fprintf(stderr,"Heap before op:\n"); + dumpheap(backup); + fprintf(stderr,"Heap after op:\n"); + dumpheap(heap); + fprintf(stderr,"Allocated blocks:\n"); + for(uint32_t i=0;i<numblocks;i++) + { + fprintf(stderr,"%08x\n",blocks[i]); + } + exit(1); +} + +static uint32_t blocksize(uint32_t offset) +{ + return heap[(offset-4)>>2]; +} + +static void tryuse(uint32_t offset) +{ + uint32_t len = blocksize(offset); + if((len-4 > allocsize-offset) || (len & 3) || (len<4)) + { + fprintf(stderr,"tryuse: Bad block at %08x\n",offset); + fail(); + } + offset >>= 2; + while(len) + { + if(usedspace[offset>>5] & (1<<(offset&31))) + { + fprintf(stderr,"tryuse: Overlapping block at %08x\n",offset<<2); + fail(); + } + usedspace[offset>>5] |= 1<<(offset&31); + offset++; + len -= 4; + } +} + +static void tryfree(uint32_t offset) +{ + uint32_t len = blocksize(offset); + if((len-4 > allocsize-offset) || (len & 3) || (len<4)) + { + fprintf(stderr,"tryfree: Bad block at %08x\n",offset); + fail(); + } + offset >>= 2; + while(len) + { + if(!(usedspace[offset>>5] & (1<<(offset&31)))) + { + fprintf(stderr,"tryfree: Block at %08x already freed\n",offset<<2); + fail(); + } + usedspace[offset>>5] -= 1<<(offset&31); + offset++; + len -= 4; + } +} + +/* Main function */ + +int main(int argc,char **argv) +{ + _kernel_oserror *err; + + /* TODO - Take parameters from command line */ + _swix(OS_ReadMonotonicTime,_OUT(0),&seed) + allocsize = 8*1024; + + init(); + + /* Initialise heap */ + r.r[0] = HeapReason_Init; + r.r[1] = (int) heap; + r.r[3] = allocsize; + err = CallHeap(&r); + if(err) + { + fprintf(stderr,"Heap initialise failed! %s\n",err->errmess); + exit(1); + } + usedspace[0] = 0xf; + + /* Begin tests */ + uint32_t temp,temp2,temp3,temp4; + while(heapvalid(heap)) + { + if(!opsleft) + { + opsleft = getrand(128); + switch(getrand(4)) + { + case 0: + currentop = HeapReason_Get; + break; + case 1: + currentop = HeapReason_Free; + break; + case 2: + currentop = HeapReason_ExtendBlock; + break; + default: + currentop = HeapReason_GetAligned; + break; + } + } + if(!(sequence&0xffff)) + { +// printf("."); + dumpheap(heap); + } + sequence++; + r.r[0] = currentop; + memcpy(backup,heap,allocsize); + switch(currentop) + { + case HeapReason_Get: + if(numblocks == MAX_ALLOCS) + { + opsleft = 0; + break; + } + r.r[3] = temp = getrand(allocsize>>5)+1; + last = r; + err = CallHeap(&r); + if(err) + { + if(err->errnum != ErrorNumber_HeapFail_Alloc) + { + fprintf(stderr,"Failed allocating %08x bytes: %s\n",temp,err->errmess); + fail(); + } + } + else + { + temp2 = blocks[numblocks++] = r.r[2]-((uint32_t)heap); + if(blocksize(temp2) < temp+4) + { + fprintf(stderr,"Failed to allocate requested block size: %08x bytes at %08x\n",temp,temp2); + fail(); + } + tryuse(temp2); + } + break; + case HeapReason_Free: + if(!numblocks) + { + opsleft = 0; + break; + } + temp = getrand(numblocks); + r.r[2] = blocks[temp]+((uint32_t) heap); + tryfree(blocks[temp]); /* Must free beforehand */ + last = r; + err = CallHeap(&r); + if(err) + { + fprintf(stderr,"Failed freeing block at %08x: %s\n",blocks[temp],err->errmess); + fail(); + } + blocks[temp] = blocks[--numblocks]; + break; + case HeapReason_ExtendBlock: + if(!numblocks) + { + opsleft = 0; + break; + } + temp = getrand(numblocks); + r.r[2] = blocks[temp]+((uint32_t) heap); + temp2 = getrand(allocsize>>4)-(allocsize>>5); + r.r[3] = temp2; + temp3 = blocksize(blocks[temp]); + tryfree(blocks[temp]); /* Must free beforehand */ + last = r; + err = CallHeap(&r); + if(err) + { + if(err->errnum != ErrorNumber_HeapFail_Alloc) + { + fprintf(stderr,"Failed resizing block at %08x by %08x bytes: %s\n",blocks[temp],(int) temp2,err->errmess); + fail(); + } + if(blocksize(blocks[temp]) != temp3) + { + fprintf(stderr,"Resize failed but block size changed\n"); + fail(); + } + tryuse(blocks[temp]); + } + else + { + if(r.r[2] && (r.r[2] != 0xffffffff)) + { + if((int) (temp3+temp2) <= 4) + { + fprintf(stderr,"Resized block was kept when it should have been freed: block %08x by %08x\n",blocks[temp],(int) temp2); + fail(); + } + blocks[temp] = r.r[2]-((uint32_t)heap); + tryuse(blocks[temp]); + if((blocksize(blocks[temp])-(temp3+temp2)) > 7) + { + fprintf(stderr,"Failed to resize block by required amount: block %08x by %08x\n",blocks[temp],(int) temp2); + fail(); + } + } + else + { + if((int) (temp3+temp2) > 4) + { + fprintf(stderr,"Resized block was freed when it should have remained: block %08x by %08x\n",blocks[temp],(int) temp2); + fail(); + } + blocks[temp] = blocks[--numblocks]; + } + } + break; + case HeapReason_GetAligned: + if(numblocks == MAX_ALLOCS) + { + opsleft = 0; + break; + } + r.r[3] = temp = getrand(allocsize>>4)+1; + temp2 = 4<<getrand(9); /* Max 2K alignment (heap 4K aligned) */ + temp3 = temp2*(1<<getrand(5)); + if(temp3 > 4096) /* Max 2K boundary (heap 4K aligned) */ + temp3 = 2048; + if(temp3 < temp) + temp3 = 0; + r.r[2] = temp2; + r.r[4] = temp3; + last = r; + err = CallHeap(&r); + if(err) + { + if(err->errnum != ErrorNumber_HeapFail_Alloc) + { + fprintf(stderr,"Failed allocating %08x bytes at alignment %08x boundary %08x: %s\n",temp,temp2,temp3,err->errmess); + fail(); + } + } + else + { + temp4 = blocks[numblocks++] = r.r[2]-((uint32_t) heap); + if(blocksize(temp4) < temp+4) + { + fprintf(stderr,"Failed to allocate requested block size: %08x bytes at alignment %08x boundary %08x at %08x\n",temp,temp2,temp3,temp4); + fail(); + } + if(temp4 & (temp2-1)) + { + fprintf(stderr,"Block allocated at wrong alignment: %08x bytes at alignment %08x boundary %08x at %08x\n",temp,temp2,temp3,temp4); + fail(); + } + if(temp3 && ((temp4 & ~(temp3-1)) != ((temp4+temp-1) & ~(temp3-1)))) + { + fprintf(stderr,"Block crosses boundary: %08x bytes at alignment %08x boundary %08x at %08x\n",temp,temp2,temp3,temp4); + fail(); + } + tryuse(temp4); + } + break; + } + if(opsleft) + opsleft--; + } + fprintf(stderr,"Heap corruption detected!\n"); + fail(); + return 0; +} diff --git a/Dev/HeapTest/s/asm b/Dev/HeapTest/s/asm new file mode 100644 index 0000000..f136f9e --- /dev/null +++ b/Dev/HeapTest/s/asm @@ -0,0 +1,113 @@ +; Copyright 2011 Castle Technology Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + +; Assembler gubbins to allow a local copy of the heap manager to be used by +; the testbed application + + + GET Hdr:ListOpts + GET Hdr:Macros + GET Hdr:System + GET Hdr:CPU.Arch + GET Hdr:Machine.<Machine> + GET Hdr:Heap + GET Hdr:Proc + GET Hdr:FSNumbers + GET Hdr:HighFSI + GET Hdr:NewErrors + +; Disable internationalisation + GBLL International +International SETL {FALSE} + +; Indicate we're compiling the testbed + GBLL HeapTestbed +HeapTestbed SETL {TRUE} + +; Heap debugging disabled for now + GBLL DebugHeaps +DebugHeaps SETL {FALSE} + +; Fake zero page workspace + + ^ 0 +IRQsema # 4 +HeapSavedReg_R0 # 4 +HeapSavedReg_R1 # 4 +HeapSavedReg_R2 # 4 +HeapSavedReg_R3 # 4 +HeapSavedReg_R4 # 4 +HeapSavedReg_R13 # 4 +HeapReturnedReg_R0 # 4 +HeapReturnedReg_R1 # 4 +HeapReturnedReg_R2 # 4 +HeapReturnedReg_R3 # 4 +HeapReturnedReg_R4 # 4 +HeapReturnedReg_R13 # 4 +HeapReturnedReg_PSR # 4 +ZeroPageSize * @ + +; Macros and other bits + + MACRO + assert $condition + [ :LNOT: ($condition) + ! 1,"Assert failed: $condition" + ] + MEND + +SVC2632 * SVC32_mode + + + AREA testbeddata, DATA + +ZeroPage % ZeroPageSize + +HeapBackgroundError % 256 + + AREA testbedcode, CODE + +; C interface + + EXPORT CallHeap +CallHeap ROUT + ; r0 = _kernel_swi_regs ptr for input/output + ; Returns error ptr in r0 + Push "r0,r4-r11,lr" + LDMIA r0,{r0-r9} + SWI OS_EnterOS ; Call in SVC mode? + BL DoCallXOSHeap + MOVVS r10,r0 + MOVVC r10,#0 + SWI OS_LeaveOS + Pull "r11" + STMIA r11,{r0-r9} + MOV r0,r10 + Pull "r4-r11,pc" + +; Assembler bits for use by heap code + +DoCallXOSHeap + ; Fake an XOS_Heap SWI + ; Preserve r10-r12 and enter with PSR in lr + Push "r10-r12,lr" + MRS lr,CPSR + B HeapEntry + +; Main heap manager code + + GET ^.^.s.HeapMan + + END diff --git a/VersionASM b/VersionASM index 8c4cd11..5648e2f 100644 --- a/VersionASM +++ b/VersionASM @@ -13,11 +13,11 @@ GBLS Module_ComponentPath Module_MajorVersion SETS "5.35" Module_Version SETA 535 -Module_MinorVersion SETS "4.79.2.127" -Module_Date SETS "27 Nov 2011" -Module_ApplicationDate SETS "27-Nov-11" +Module_MinorVersion SETS "4.79.2.128" +Module_Date SETS "10 Dec 2011" +Module_ApplicationDate SETS "10-Dec-11" Module_ComponentName SETS "Kernel" Module_ComponentPath SETS "castle/RiscOS/Sources/Kernel" -Module_FullVersion SETS "5.35 (4.79.2.127)" -Module_HelpVersion SETS "5.35 (27 Nov 2011) 4.79.2.127" +Module_FullVersion SETS "5.35 (4.79.2.128)" +Module_HelpVersion SETS "5.35 (10 Dec 2011) 4.79.2.128" END diff --git a/VersionNum b/VersionNum index 01410f1..bb184ae 100644 --- a/VersionNum +++ b/VersionNum @@ -5,19 +5,19 @@ * */ #define Module_MajorVersion_CMHG 5.35 -#define Module_MinorVersion_CMHG 4.79.2.127 -#define Module_Date_CMHG 27 Nov 2011 +#define Module_MinorVersion_CMHG 4.79.2.128 +#define Module_Date_CMHG 10 Dec 2011 #define Module_MajorVersion "5.35" #define Module_Version 535 -#define Module_MinorVersion "4.79.2.127" -#define Module_Date "27 Nov 2011" +#define Module_MinorVersion "4.79.2.128" +#define Module_Date "10 Dec 2011" -#define Module_ApplicationDate "27-Nov-11" +#define Module_ApplicationDate "10-Dec-11" #define Module_ComponentName "Kernel" #define Module_ComponentPath "castle/RiscOS/Sources/Kernel" -#define Module_FullVersion "5.35 (4.79.2.127)" -#define Module_HelpVersion "5.35 (27 Nov 2011) 4.79.2.127" +#define Module_FullVersion "5.35 (4.79.2.128)" +#define Module_HelpVersion "5.35 (10 Dec 2011) 4.79.2.128" #define Module_LibraryVersionInfo "5:35" diff --git a/hdr/KernelWS b/hdr/KernelWS index f32be4f..5e413f9 100644 --- a/hdr/KernelWS +++ b/hdr/KernelWS @@ -1980,6 +1980,8 @@ ROMBuildDate # 128 NewFX0Error # 64 ] +HeapBackgroundError # 256 ; For storing errors generated in the background by the forced completion of a foreground heap op + KbuffsEnd # 0 KbuffsSize * KbuffsEnd - KbuffsBaseAddress ;size of Kernel buffers area diff --git a/s/Arthur3 b/s/Arthur3 index 76644e9..12bef03 100644 --- a/s/Arthur3 +++ b/s/Arthur3 @@ -1545,6 +1545,8 @@ ReadNumAuto Entry "r1,r3,r4" AutoString = "Auto", 0 +dotstring + = ".", 0 ALIGN ReadSizeParm ROUT diff --git a/s/HeapMan b/s/HeapMan index 839f49e..794e7a4 100644 --- a/s/HeapMan +++ b/s/HeapMan @@ -33,6 +33,11 @@ TubeInfo SETL {FALSE} GBLL debheap debheap SETL 1=0 + [ :LNOT: :DEF: HeapTestbed + GBLL HeapTestbed +HeapTestbed SETL {FALSE} + ] + [ DebugHeaps FreeSpaceDebugMask * &04000000 UsedSpaceDebugMask * &08000000 @@ -43,11 +48,11 @@ Nil * 0 hpd RN r1 ; The punter sees these addr RN r2 size RN r3 +work RN r4 HpTemp RN r10 ; But not these tp RN r11 bp RN r12 -work RN r4 ; This is the only one we have to save. ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; + H E A P O R G A N I S A T I O N + @@ -103,7 +108,7 @@ freblksize # 0 ; The link field is Nil (0) for the last block in the list -; Block sizes must be forced to a multiple of 8 bytes for subsequent link and +; Block sizes must be forced to a minimum of 8 bytes for subsequent link and ; size information to be stored in them if they are disposed of by the user. ; They must also be capable of storing a 4 byte size field while allocated. @@ -124,6 +129,17 @@ $label BL ValidateHpdSubr MEND +; Call XOS_Heap SWI + + MACRO + CallXOSHeap + [ HeapTestbed + BL DoCallXOSHeap + | + SWI XOS_Heap + ] + MEND + ;**************************************************************************** ; These bits of ExtendBlock are outside the IRQ HeapOp range because they @@ -157,7 +173,7 @@ ReallocateInSafeZone Push addr ; save for later freeing MOV R0, #HeapReason_Get - SWI XOS_Heap + CallXOSHeap Pull addr, VS BVS SafeNaffExtension @@ -192,11 +208,11 @@ CopyForExtension MOV R0, #HeapReason_Free Pull addr ; heap block addr - SWI XOS_Heap + CallXOSHeap - MOV R0, #HeapReason_ExtendBlock + MOVVC R0, #HeapReason_ExtendBlock WritePSRc SVC_mode + I_bit,work ; disable IRQs before we venture back - B GoodExtension ; into danger zone + BVC GoodExtension ; into danger zone SafeNaffExtension WritePSRc SVC_mode + I_bit,work ; disable IRQs before we venture back @@ -236,6 +252,14 @@ heapopdoneinbackground ROUT ; clear the interlock TST R11, #V_bit ; look at returned error BEQ GoodHeapExit + ; Recover the error from our buffer + LDR R0,=HeapBackgroundError + LDR R10,[R0] + SWI XMessageTrans_CopyError + ; Check that it worked - MessageTrans may be dead + LDR R11,[R0] + TEQ R10,R11 + LDRNE R0,=HeapBackgroundError ; Just return our internal buffer if MessageTrans couldn't provide one B NaffHeapExit ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -247,8 +271,9 @@ heapopdoneinbackground ROUT ; In r0 = heap action requested ; r1(hpd) -> heap block -; r2(addr) -> start of block +; r2(addr) -> start of block, or required alignment ; r3(size) = size of block +; r4(work) = boundary limitation ; Out VClear -> Action performed ; VSet -> Something terrible has happened, error set @@ -282,7 +307,7 @@ inspect_IRQ_stack ORR R10, R10, #I32_bit:OR:SVC2632 STR R10, [R11, #4*6] ; return into SVC26/32 mode with IRQs disabled - Push "R0-R3, lr" + Push "R0-R4, lr" LDR R10, =ZeroPage+HeapSavedReg_R0 @@ -292,15 +317,30 @@ inspect_IRQ_stack ; CMP R12, #0 ; BNE HeapInUse - LDMIA R10, {R0-R3, R10, R11} + LDMIA R10, {R0-R4, R11} SWI XOS_Heap ; with interrupts off! LDR R12, =ZeroPage+HeapReturnedReg_R0 ; Could we poke these into the IRQ stack too...? ; would allow interruptible IRQ processes to do heap ops!!! MRS lr, CPSR - STMIA R12, {R0-R3, R10, R11, lr} - Pull "R0-R3, lr" + STMIA R12, {R0-R4, R11, lr} +; Any errors that were generated by the foreground operation may have ended up +; using one of MessageTrans' IRQ buffers. Trouble is, any number of IRQ errors +; could occur between now and when the foreground task gets the error. Avoid +; the error getting clobbered by copying it into a special kernel buffer, and +; then copy it back to a MessageTrans buffer once we're back in the foreground. + BVC noheapbackgrounderror + LDR R1,=HeapBackgroundError + MOV LR,#256 +heapbackgrounderrorloop + LDMIA R0!,{R2-R4,R12} + SUBS LR,LR,#16 + STMIA R1!,{R2-R4,R12} + BNE heapbackgrounderrorloop + +noheapbackgrounderror + Pull "R0-R4, lr" iis_end ; store the registers in the info block LDR R12, =ZeroPage+HeapSavedReg_R0 @@ -334,6 +374,8 @@ HeapJumpTable ; Check reason codes against Hdr:Heap defs B ExtendHeap assert ((.-HeapJumpTable) :SHR: 2) = HeapReason_ReadBlockSize B ReadBlockSize + assert ((.-HeapJumpTable) :SHR: 2) = HeapReason_GetAligned + B GetAreaAligned [ debheap B ShowHeap ] @@ -352,7 +394,12 @@ GoodHeapExit ; V cleared on entry to SWI dispatch Pull lr ORRVS lr, lr, #V_bit ; VSet Exit + [ HeapTestbed + MSR CPSR_cxsf, lr ; Fake exit for testbed + Pull "r10-r12,pc" + | ExitSWIHandler ; Like all good SWI handlers + ] ;HeapInUse ; $HeapBadAsModuleBRA @@ -592,8 +639,8 @@ GetArea ROUT BLE garfailed_zero ; And -ve is invalid as well! ; note sizes of many megabytes thrown out by looking. - ADD size, size, #(freblksize-1)+4 ; Make block size granular - BIC size, size, #(freblksize-1) ; with size field added + ADD size, size, #3+4 ; Make block size multiple of 4 + BIC size, size, #3 ; including header ADR addr, hpdfree-frelink ; addr:= @(hpd!free)-frelink @@ -610,7 +657,11 @@ garloop ; If we have an exact fit (or as close as the granularity of the free list will ; allow), unlink this block and return it - BNE SplitFreeBlock + CMP HpTemp, #freblksize + BGE SplitFreeBlock + +; Increase allocation size if there wasn't enough space to split the free block + ADD size, size, HpTemp [ debheap LDR HpTemp, hpddebug @@ -660,6 +711,7 @@ ResultIsAddrPlus4 STR size, [addr], #4 ; Store block size and increment addr Pull "size" ; Return original value to the punter ; Note : real size got would be an option! + CLRV B GoodHeapExit ; RESULTIS addr @@ -689,7 +741,7 @@ garmore ] garfailed - ADR R0, ErrorBlock_HeapFail_Alloc + ADRL R0, ErrorBlock_HeapFail_Alloc [ International BL TranslateError ] @@ -705,7 +757,7 @@ garfailed_badhpd [ debheap STRIM "Invalid heap descriptor" ] - ADR R0, ErrorBlock_HeapFail_BadDesc + ADRL R0, ErrorBlock_HeapFail_BadDesc [ International BL TranslateError ] @@ -719,6 +771,298 @@ garfailed_zero garfailed_zero * garfailed ] +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; GetAreaAligned. Top level HeapEntry +; ============== +; +; Allocate an aligned block of memory from the heap + +; This is the same as GetArea, except it will only allocate areas with the given +; (power-of-two) alignment. +; Fails if requesting size = 0 + +; In : hpd -> heap pointer +; size = size of block required +; addr = alignment (power of 2) +; work = boundary (power of 2, 0 for none) + +; Out : VClear : addr -> got a block +; VSet : addr = 0, couldn't get block +; Rest of universe ok + +GetAreaAligned ROUT + Push "size,work" + ValidateHpd garafailed + + [ debheap +; HpTemp not critical + LDR HpTemp, hpddebug + CMP HpTemp, #0 + BEQ %FT00 + Push "r0, link" + MOV r0, size + DREG r0, "GetAreaAligned " + MOV r0, addr + DREG r0, "alignment " + MOV r0, work + DREG r0, "boundary " + BL iShowHeap + Pull "r0, link" +00 + ] + + CMP size, #0 ; Can't deallocate 0, so there! + BLE garafailed_zero ; And -ve is invalid as well! + ; note sizes of many megabytes thrown out by looking. + + ADD size, size, #3 ; Make block size multiple of 4 + BIC size, size, #3 ; excluding header + + SUB bp, addr, #1 ; Store alignment-1 in bp + TST bp, addr + BNE garafailed_align ; Must be power of 2! + CMP bp, #3 + MOVLT bp, #3 ; Minimum alignment is 4 + + SUB r0, work, #1 ; Store boundary-1 in r0 + TST r0, work + BNE garafailed_boundary ; Must be power of 2! + + ADR addr, hpdfree-frelink ; addr:= @(hpd!free)-frelink + + ; If we have a boundary, it must be >= alignment, and >= size + CMP r0, #-1 + BEQ garaloop + CMP r0, bp + CMPHS work, size + BLO garafailed_boundary2 + +garaloop + LDR tp, [addr, #frelink] ; tp := addr!fre.link + CMP tp, #Nil ; Is this the end of the chain ? + BEQ garamore ; - so try main blk + ADD addr, addr, tp ; convert offset + LDR HpTemp, [addr, #fresize] + +; Calculate start and end addresses as if we were to allocate from this block + ADD work,addr,#4 ; 4 bytes for storing block size + ADD HpTemp,HpTemp,addr ; End of free block + ADD work,work,bp +garaloop2 + BIC work,work,bp ; work = start of user block + SUB lr,work,addr + CMP lr,#4 + BEQ garastartok ; Start alignment is exact + CMP lr,#freblksize+4 + BGE garastartok ; Enough space to fit a free block at the start + +; We need a free block, but there isn't enough space for it. +; Shift 'work' up by one unit of alignment and try again. + + ADD work,work,bp,LSL #1 + B garaloop2 + +garastartok +; Calculate block end address + ADD lr,work,size ; End of user block + SUBS lr,HpTemp,lr ; Gap after user block + BLO garaloop ; Not big enough + +; Check boundary requirement + CMP r0,#-1 + BEQ garaboundaryok + AND lr,work,r0 ; Start offset within boundary + ADD lr,lr,size + SUB lr,lr,#1 ; Last byte of allocation + CMP lr,r0 + BLS garaboundaryok + +; This allocation crosses a boundary. Shift 'work' up to be boundary aligned. + ADD work,work,r0 + BIC work,work,r0 + B garaloop2 ; Loop back round to recheck everything (with small boundary sizes, we may have created a situation where we can't fit an initial free block) + +garaboundaryok + +; We have a suitable space to allocate from. + ADD size,size,#4 ; Correct size to store + SUB work,work,#4 ; Correct block start + + [ debheap + LDR lr, hpddebug + CMP lr, #0 + BEQ %FT60 + WRLN "Using existing free block" +60 + ] + +; Note: bp now being used as scratch + + ADD bp,work,size ; End of user block + SUB bp,HpTemp,bp ; Gap after user block + + WritePSRc SVC_mode+I_bit, lr + +; Work out if we need a new free block afterwards + CMP bp, #freblksize + ADDLT size, size, bp ; Not enough space, so enlarge allocated block + BLT %FT10 + +; Create a new free block that will lie after our allocated block + SUB HpTemp, HpTemp, bp + STR bp, [HpTemp, #fresize] ; Write size + LDR bp, [addr, #frelink] + CMP bp, #Nil + ADDNE bp, bp, addr + SUBNE bp, bp, HpTemp + STR bp, [HpTemp, #frelink] ; Write next ptr + SUB HpTemp, HpTemp, addr + STR HpTemp, [addr, #frelink] ; Fix up link from previous block +10 + +; Shrink this free block to take up the space preceeding the allocated block. + SUBS bp,work,addr + STRNE bp, [addr, #fresize] + BNE ResultIsWorkPlus4 + +; No space for an initial free block. Get rid of it. + ASSERT frelink=0 ; otherwise LDR bp,[addr,#frelink]! + LDR bp, [addr] + CMP bp, #0 + ADDNE bp, bp, tp + STR bp, [addr, -tp] + B ResultIsWorkPlus4 + +; Got no more free blocks of length >= size, so try to allocate more heap space +; out of the block described by hpd + +garamore + [ debheap + LDR work, hpddebug + CMP work, #0 + BEQ %FT80 + WRLN "Trying to get more from main block" +80 + ] + LDR work, hpdbase + ADD work, work, hpd + ADD tp, work, #4 + ADD tp, tp, bp +garamoreloop + BIC tp, tp, bp ; tp = pointer to return to user + +; Make sure there's enough space for a free block if necessary + SUB HpTemp, tp, work ; HpTemp = tp-(hpd+hpdbase) + CMP HpTemp, #4 + BEQ garamoreok + CMP HpTemp, #freblksize+4 + ADDLT tp, tp, bp, LSL #1 ; Not enough space for free block + BLT garamoreloop + +garamoreok +; Boundary check + CMP r0, #-1 + BEQ garamoreboundaryok + AND HpTemp, tp, r0 + ADD HpTemp, HpTemp, size + SUB HpTemp, HpTemp, #1 + CMP HpTemp, r0 + BLS garamoreboundaryok + +; Shift 'tp' up to be boundary aligned + ADD tp, tp, r0 + BIC tp, tp, r0 + B garamoreloop + +garamoreboundaryok + ADD HpTemp, tp, size ; New heap end + SUB HpTemp, HpTemp, hpd ; New heap size + LDR lr, hpdend + CMP HpTemp, lr + BGT garafailed + + WritePSRc SVC_mode+I_bit, lr + +; Set up the block to return to the user + ADD size, size, #4 + STR size, [tp, #-4]! + +; Grow the heap + STR HpTemp, hpdbase + +; Create preceeding free block if necessary + SUBS HpTemp, tp, work + BEQ ResultIsTpPlus4 + +; Write the free block + STR HpTemp, [work, #fresize] + MOV HpTemp, #Nil + STR HpTemp, [work, #frelink] + +; Patch up the preceeding block + SUB HpTemp, work, addr + STR HpTemp, [addr, #frelink] + +ResultIsTpPlus4 +; Block size is already stored + ADD addr, tp, #4 + Pull "size,work" + MOV r0,#HeapReason_GetAligned + CLRV + B GoodHeapExit + +ResultIsWorkPlus4 + STR size, [work] ; Store block size + ADD addr, work, #4 ; Move to correct return reg & add offset + Pull "size,work" + MOV r0,#HeapReason_GetAligned + CLRV + B GoodHeapExit + +garafailed + ADRL R0, ErrorBlock_HeapFail_Alloc + [ International + BL TranslateError + ] + [ debheap + WRLN " : GetAreaAligned failed" + ] +garafail_common + MOV addr, #0 ; addr := 0 if we couldn't allocate + Pull "size,work" ; RESULTIS 0 + B NaffHeapExit ; VSet Exit + +garafailed_badhpd + [ debheap + STRIM "Invalid heap descriptor" + ] + ADRL R0, ErrorBlock_HeapFail_BadDesc + [ International + BL TranslateError + ] + B garafail_common + + [ debheap +garafailed_zero + STRIM "Can't allocate 0 or less bytes" + B garafailed +garafailed_align + STRIM "Alignment not power of 2" + B garafailed +garafailed_boundary + STRIM "Boundary not power of 2" + B garafailed +garafailed_boundary2 + STRIM "Boundary too small" + B garafailed + | +garafailed_zero * garafailed +garafailed_align * garafailed +garafailed_boundary * garafailed +garafailed_boundary2 * garafailed + ] + ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; FreeArea. Top level HeapEntry @@ -787,7 +1131,7 @@ ExtendBlock CMP HpTemp, #0 BEQ %FT00 Push "r0, link" - DREG size, "ExtendBlock by ",concat + DREG size, "ExtendBlock by ",cc STRIM " block at " SUB r0, addr, hpd SUB r0, r0, #4 @@ -799,8 +1143,8 @@ ExtendBlock BL FindHeapBlock BVS NaffExtension - ADD size, size, #freblksize-1 ; round size as appropriate : - BICS size, size, #freblksize-1 ; round up to nearest 8 + ADD size, size, #3 ; round size as appropriate : + BICS size, size, #3 ; round up to nearest 4 BEQ GoodExtension ; get the easy case done. BPL MakeBlockBigger @@ -808,7 +1152,8 @@ ExtendBlock RSB size, size, #0 LDR bp, [addr, hpd] ; get block size WritePSRc SVC_mode+I_bit, R14 - SUBS bp, bp, size ; size of block left + SUB bp, bp, size ; size of block left + CMP bp, #4 [ debheap ; HpTemp not critical, GE/LT critical @@ -818,22 +1163,40 @@ ExtendBlock BEQ %FT01 WRLN "Freeing part of block" 01 - CMP bp, #0 ; restore GE/Lt + CMP bp, #4 ; restore GE/Lt ] MOVLE HpTemp, #-1 ; if discarding block, then STRLE HpTemp, [stack] ; make pointer really naff. + BLE GoodShrink - STRGT bp, [addr, hpd] ; update size of block left - ADDGT addr, addr, bp ; offset of block to free - STRGT size, [addr, hpd] ; construct block for freeing - + ; If we're only shrinking 4 bytes, only allow the shrink to go ahead + ; if there's a free block (or hpdbase) after us + CMP size, #4 + BGT DoShrink + LDR HpTemp, [hpd, tp] + CMP HpTemp, #Nil + ADDNE HpTemp, HpTemp, tp + LDREQ HpTemp, hpdbase + ADD HpTemp, HpTemp, hpd ; Next free block ptr + SUB HpTemp, HpTemp, addr ; Offset from start of this block + SUB HpTemp, HpTemp, size ; Apply shrink amount to match bp + CMP HpTemp, bp + MOVGT size, #0 ; Used block after us. Deny shrink. + BGT GoodExtension + BLT CorruptExtension ; Heap corrupt! + ; Else there's a free block (or hpdbase) directly after us +DoShrink + STR bp, [addr, hpd] ; update size of block left + ADD addr, addr, bp ; offset of block to free + STR size, [addr, hpd] ; construct block for freeing + +GoodShrink BL FreeChunkWithConcatenation ; work still set from block lookup GoodExtension Pull "addr, size, work" [ DebugHeaps - ADD lr, size, #freblksize-1 ; work out how much we actually extended by - BICS lr, lr, #freblksize-1 + MOVS lr, size ; work out how much we actually extended by BEQ %FT99 ; if zero or negative BMI %FT99 ; then nothing to do LDR HpTemp, [addr, #-4] ; get new block size @@ -847,6 +1210,7 @@ GoodExtension BNE %BT98 99 ] + CLRV B GoodHeapExit MakeBlockBigger @@ -871,7 +1235,7 @@ MakeBlockBigger LDRNE HpTemp, [HpTemp, #fresize] LDREQ HpTemp, hpdend SUBEQ HpTemp, HpTemp, bp - BICEQ HpTemp, HpTemp, #(freblksize-1) + BICEQ HpTemp, HpTemp, #3 ; force it to a sensible blocksize MRS lr, CPSR ; save EQ/NE state @@ -890,7 +1254,7 @@ MakeBlockBigger STRIM "Extending block into " 02 Pull "HpTemp,lr" - msr ,CPSR_f, lr + msr CPSR_f, lr ] LDR work, [addr, hpd] ; get size back @@ -925,8 +1289,13 @@ IntoFreeEntry Pull HpTemp ] - CMP HpTemp, size - BNE SplitFreeBlockForExtend + SUB HpTemp, HpTemp, size ; new freblk size + CMP HpTemp, #4 + BGT SplitFreeBlockForExtend + +; Not enough space for a free block. Increase the grow amount a bit. + ADDEQ work, work, #4 + STREQ work, [addr, hpd] ; free entry just right size : remove from free list LDR HpTemp, [bp, hpd] ; free link @@ -942,7 +1311,6 @@ SplitFreeBlockForExtend STR work, [tp, hpd] ; prevnode points at right place ADD work, work, tp ; offset of new free entry ADD work, work, hpd - SUB HpTemp, HpTemp, size ; new freblk size STR HpTemp, [work, #fresize] LDR HpTemp, [bp, hpd] CMP HpTemp, #Nil @@ -992,13 +1360,15 @@ hack_preceder ; work is prevprevfree offset ; size is amount block grows by ; addr is block offset - CMP bp, #0 - ADDNE HpTemp, tp, hpd - STRNE bp, [HpTemp, #fresize] ; prevblock shrunk - BNE copy_backwards + CMP bp, #freblksize + ADDGE HpTemp, tp, hpd + STRGE bp, [HpTemp, #fresize] ; prevblock shrunk + BGE copy_backwards ; free freblk: work is still prevprevblk pointer LDR HpTemp, [tp, hpd] + ADDNE size, size, bp ; Increase grow amount by any remainder + MOVNE bp, #0 ; And make sure the block does die CMP HpTemp, #Nil ADDNE HpTemp, HpTemp, tp ; offset from heap start SUBNE HpTemp, HpTemp, work @@ -1015,7 +1385,7 @@ copy_backwards LDR r0, hpddebug CMP r0, #0 BEQ %FT06 - DREG HpTemp, "copying -4+",concat + DREG HpTemp, "copying -4+",cc STRIM " from " SUB R0, addr, hpd BL PrintOffset @@ -1074,7 +1444,7 @@ try_add_preceding_block BNE ext_delink LDR work, hpdend SUB work, work, bp ; get back real size - BIC work, work, #(freblksize-1) + BIC work, work, #3 ADD work, work, bp STR work, hpdbase ; all free allocated B ext_hack @@ -1111,9 +1481,15 @@ got_to_reallocate B ReallocateInSafeZone +CorruptExtension + ADRL R0,ErrorBlock_HeapFail_BadLink + [ International + BL TranslateError + ] + NaffExtension Pull "addr, size, work" - B NaffHeapExit + B NaffHeapExit ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -1522,7 +1898,7 @@ iShowHeap ROUT ; Internal entry point for debugging heap BL PrintOffsetLine SUB r0, work, bp ; hpdend-hpdbase - DREG r0,"Bytes free: ",concat, Word + DREG r0,"Bytes free: ",cc, Word SUB r0, bp, addr ; hpdbase-hpdsize DREG r0,", bytes used: ",, Word SWI XOS_NewLine @@ -1605,7 +1981,7 @@ PrintOffset DREG r0 CMP R0, #0 ADDNE R0, R0, hpd - DREG r0," (",concat + DREG r0," (",cc STRIM ")" GRAB "R0, PC" diff --git a/s/Oscli b/s/Oscli index e12ed74..2f6473c 100644 --- a/s/Oscli +++ b/s/Oscli @@ -547,8 +547,7 @@ AliasOscliTooLong AliasStr_QA = "ALIAS$", 0 ] AliasStr = "Alias$*", 0 -AliasDot = "Alias$" -dotstring = ".", 0 +AliasDot = "Alias$.", 0 ALIGN [ Oscli_QuickAliases diff --git a/s/vdu/vdudecl b/s/vdu/vdudecl index c760714..9a77f9a 100644 --- a/s/vdu/vdudecl +++ b/s/vdu/vdudecl @@ -68,7 +68,10 @@ ScreenModeReason_SelectMode * 0 ScreenModeReason_ReturnMode * 1 ScreenModeReason_EnumerateModes * 2 ScreenModeReason_SelectMonitorType * 3 -ScreenModeReason_Limit * 4 +ScreenModeReason_ConfigureAcceleration * 4 +ScreenModeReason_CleanCache * 5 +ScreenModeReason_ForceCleanCache * 6 +ScreenModeReason_Limit * 7 ; Mode selector format diff --git a/s/vdu/vduswis b/s/vdu/vduswis index 37575ad..ce7493d 100644 --- a/s/vdu/vduswis +++ b/s/vdu/vduswis @@ -1933,7 +1933,10 @@ ScreenModeSWI Entry ASSERT ScreenModeReason_ReturnMode = 1 ASSERT ScreenModeReason_EnumerateModes = 2 ASSERT ScreenModeReason_SelectMonitorType = 3 - ASSERT ScreenModeReason_Limit = 4 + ASSERT ScreenModeReason_ConfigureAcceleration = 4 + ASSERT ScreenModeReason_CleanCache = 5 + ASSERT ScreenModeReason_ForceCleanCache = 6 + ASSERT ScreenModeReason_Limit = 7 ScreenModeSub CMP r0, #ScreenModeReason_Limit @@ -1943,6 +1946,9 @@ ScreenModeSub B ScreenMode_ReturnMode B ScreenMode_EnumerateModes B ScreenMode_SelectMonitorType + B ScreenMode_ConfigureAcceleration + B ScreenMode_CleanCache + B ScreenMode_ForceCleanCache ; unknown OS_ScreenMode reason code @@ -2063,6 +2069,52 @@ ScreenMode_SelectMonitorType Entry "r0" STR r1, [WsPtr, #CurrentMonitorType] ; update current value EXIT +;************************************************************************** +; +; ScreenMode_ConfigureAcceleration - Configure screen memory cacheability +; +; Internal routine called by ScreenModeSWI +; +; in: r0 = reason code (4) +; r1 = flags: +; bit 0 : set to suspend cached screen until mode change +; bit 1 : set to suspend screen cleaning +; bit 2 : set to disable hardware acceleration +; other : reserved, must be 0 +; or -1 to read current value +; r2 = number of VSyncs between automatic screen cleaning (1-3), or -1 +; to read current value +; +; out: r1 = new flag state +; r2 = new number of VSyncs between automatic screen cleaning +; r10-r12 may be corrupted +; All other registers preserved +; + +ScreenMode_ConfigureAcceleration + ; Screen caching isn't supported yet. Just return dummy values. + MOV r1,#1 + MOV r2,#1 + MOV pc,lr + +;************************************************************************** +; +; ScreenMode_CleanCache - Clean screen memory from cache, if cache enabled +; ScreenMode_ForceCleanCache - Force clean of screen memory from cache +; +; Internal routine called by ScreenModeSWI +; +; in: r0 = reason code (5 or 6) +; +; out: r10-r12 may be corrupted +; All other registers preserved +; + +ScreenMode_CleanCache +ScreenMode_ForceCleanCache + ; Screen caching isn't supported yet. Just do nothing. + MOV pc,lr + ;;;mjsHAL - VIDCDividerSWI is horrible VIDC specific API, compiled out ;;; ; Should not cause any problems on any machine. STB flag just to be safe though. -- GitLab