; ; CDDL HEADER START ; ; The contents of this file are subject to the terms of the ; Common Development and Distribution License (the "Licence"). ; You may not use this file except in compliance with the Licence. ; ; You can obtain a copy of the licence at ; cddl/RiscOS/Sources/FileSys/SDFS/SDFS/LICENCE. ; See the Licence for the specific language governing permissions ; and limitations under the Licence. ; ; When distributing Covered Code, include this CDDL HEADER in each ; file and include the Licence file. If applicable, add the ; following below this CDDL HEADER, with the fields enclosed by ; brackets "[]" replaced with your own identifying information: ; Portions Copyright [yyyy] [name of copyright owner] ; ; CDDL HEADER END ; ; Copyright 2012 Ben Avison. All rights reserved. ; Portions Copyright 2012 Jeffrey Lee. ; Use is subject to license terms. ; [ :LNOT::DEF: StoreInHAL GBLL StoreInHAL StoreInHAL SETL {FALSE}; ] GET ListOpts GET Macros GET System GET Proc GET HighFSI GET ModHand GET OsBytes GET FileTypes GET VersionASM AREA |Asm$$Code|, CODE, READONLY, PIC ENTRY DCD 0 ; Start DCD Init - |Asm$$Code| DCD Final - |Asm$$Code| DCD 0; Service call handler DCD Title - |Asm$$Code| DCD Help - |Asm$$Code| DCD 0 ; Keyword table DCD 0 ; SWI chunk DCD 0 ; SWI handler DCD 0 ; SWI table DCD 0 ; SWI decoder DCD 0 ; Messages DCD Flags - |Asm$$Code| Title = Module_ComponentName, 0 Help = Module_ComponentName, 9, 9, Module_HelpVersion, 0 ALIGN Flags & ModuleFlag_32bit [ StoreInHAL NonCanonicalisedPath = "SDFS::0.$.!Boot.Loader.riscos/img", 0 ALIGN CMOSMarker UND #&C305 OSIm = "OSIm" | NonCanonicalisedPath = "SDFS::0.$.CMOS", 0 NonCanonicalisedPath2 = "SDFS::0.$.!Boot.Loader.CMOS", 0 ALIGN SaveCMOS = "SaveCMOS " Len_SaveCMOS * .-SaveCMOS ALIGN ] Init ROUT Entry ; This module is designed to be included in a ROM, in which case we have ; to take account of the fact that SDFS::0 isn't properly initialised ; until the callbacks after ROM init. ADR r0, CallBackFromInit MOV r1, r12 SWI XOS_AddCallBack EXIT CallBackFromInit ROUT Push "lr" ; separate instructions to reduce warnings ADD lr, sp, #4 Push "r0-r6, lr" ; yes, need to stack sp ; We assume that we're entered during or soon after boot. In which case, ; if there is an SD card inserted, and if it contains a file called ; "CMOS" in its root directory of the correct filetype, then we must ; assume that it could have been used to initialise the kernel's CMOS ; RAM cache, and therefore needs updating whenever someone writes CMOS. ADR r1, NonCanonicalisedPath BL TryInit [ :LNOT: StoreInHAL ; Also try !Boot.Loader.CMOS, to allow the special FAT-in-Filecore ; partition formats to be used on machines other than the Raspberry Pi ADRVS r1, NonCanonicalisedPath2 BLVS TryInit ] BVS %FT90 ; All good - get on ByteV MOV r0, #ByteV ADR r1, MyByteV MOV r2, r12 SWI XOS_Claim BVS %F90 Pull "r0-r6, lr" ; separate instructions to reduce warnings Pull "pc" 90 ; Error detected during callback - kill the module and exit ASSERT %F99-%F98 = 8 ADR r0, %F98 LDMIA r0, {r1-r2} Push "r1-r2" MOV r0, #1 MOV r1, sp ADD r2, sp, #%F99-%F98-1 SWI XOS_SynchroniseCodeAreas MOV r0, #ModHandReason_Delete ADR r1, Title ADD r2, sp, #%F99-%F98 ; point r2 at stack frame MOV pc, sp ; This last bit is executed after the module is killed so can't safely ; be executed in place - do it from the stack instead 98 SWI XOS_Module LDMIA r2, {r0-r6, sp, pc} ; atomic update of sp (which makes this code volatile) with pc 99 ; In: r1 = filename ; Out: Regs corrupt ; V set on failure ; No error pointer returned TryInit ROUT Entry ; Find how long the canonicalised name is MOV r0, #FSControl_CanonicalisePath MOV r2, #0 MOV r3, #0 MOV r4, #0 MOV r5, #0 SWI XOS_FSControl BVS %F90 [ StoreInHAL ; Allocate a buffer to hold filename of the ROM image plus terminator RSB r3, r5, #1 | ; Allocate a buffer for the command string - will contain "SaveCMOS " ; plus the canonicalised name of the file, plus a terminator RSB r3, r5, #Len_SaveCMOS + 1 ] MOV r0, #ModHandReason_Claim SWI XOS_Module BVS %F90 STR r2, [r12] ; Get the canonicalised name [ :LNOT: StoreInHAL ADD r2, r2, #Len_SaveCMOS ] MOV r5, r3 MOV r0, #FSControl_CanonicalisePath MOV r3, #0 SWI XOS_FSControl BVS %F90 [ :LNOT: StoreInHAL ; Copy in the "SaveCMOS " part now we have a few more working registers ASSERT Len_SaveCMOS = 9 SUB r2, r2, #Len_SaveCMOS ADR r3, SaveCMOS LDMIA r3!, {r4-r5} LDRB r6, [r3] STMIA r2!, {r4-r5} STRB r6, [r2], #1 ] ; Check it's a file (or image file) MOV r0, #OSFile_ReadWithTypeNoPath MOV r1, r2 SWI XOS_File BVS %F90 TST r0, #object_file BEQ %F90 [ :LNOT: StoreInHAL ; Check it's a sensible filetype LDR r0, =FileType_Configuration TEQ r6, r0 LDRNE r0, =FileType_MSDOS TEQNE r6, r0 BNE %F90 ] ; All good CLRV EXIT 90 ; Something went wrong ; Free our workspace to avoid potential leak if TryInit called multiple times LDR r2, [r12] CMP r2, #0 MOVNE r0, #ModHandReason_Free SWINE XOS_Module MOV r2, #0 STR r2, [r12] SETV EXIT MyByteV ROUT TEQ r0, #OsByte_WriteCMOS MOVNE pc, lr ; only interested in when the CMOS is written ADR r0, %F10 Push "r0, r12" ; set up address for claimant to return to (NB this code is not 26-bit compatible) MOV r0, #OsByte_WriteCMOS MOV pc, lr ; pass on, and... 10 ; ... we end up here after the CMOS has been written Pull "r12" ; get our own r12 back Pull "pc", VS ; if an error, just pass it up to original claim address [ StoreInHAL Push "r0-r7" SUB sp, sp, #4 ; allocate space on stack for buffer MOV r7, r1 MOV r0, #&CF ; open existing file for read/write, error if missing or directory, no path LDR r1, [r12] SWI XOS_Find BVS %F90 MOV r1, r0 ; Search for the CMOS in the ROM on disc - can't be sure it matches the ; running version! LDR r5, CMOSMarker LDR r6, OSIm MOV r0, #4 ; read bytes from current file pointer 20 MOV r2, sp MOV r3, #4 SWI XOS_GBPB BVS %F80 LDR r14, [sp] TEQ r14, r6 BEQ %F80 ; got to the end of the HAL and not found CMOS - give up TEQ r14, r5 BNE %B20 ; Read size of block in HAL MOV r2, sp MOV r3, #4 SWI XOS_GBPB BVS %F80 LDR r6, [sp] MOV r5, r1 ; keep file handle safe ; Copy the CMOS RAM into a block on the stack (should be small enough) ; in physical address order SUB sp, sp, r6 MOV r3, #0 30 MOV r0, #OsByte_ReadCMOS MOV r1, r3 CMP r3, #&10 ADDLO r1, r1, #&40 CMP r3, #&40 ADDLO r1, r1, #&F0 CMP r3, #&100 SUBLO r1, r1, #&40 SWI XOS_Byte MOVVS r2, #0 STRB r2, [sp, r3] ADD r3, r3, #1 CMP r3, r6 BLO %B30 ; Overwrite the HAL with the block from the stack MOV r0, #2 ; write bytes at current file pointer MOV r1, r5 MOV r2, sp MOV r3, r6 SWI XOS_GBPB ADD sp, sp, r6 80 MOV r2, r0 MRS r3, CPSR MOV r0, #0 ; close file SWI XOS_Find MOV r0, r2 MSR CPSR_f, r3 90 ADD sp, sp, #4 ; skip data block STRVS r0, [sp] Pull "r0-r7, pc" ; go to original claim address | Push "r0" LDR r0, [r12] SWI XOS_CLI ; save the CMOS to the file STRVS r0, [sp] Pull "r0, pc" ; go to original claim address ] Final ROUT Entry ; It's good practice to remove our callback here just in case we got ; killed before it was triggered. ADR r0, CallBackFromInit MOV r1, r12 SWI XOS_RemoveCallBack ; Get off ByteV, if we were on it MOV r0, #ByteV ADR r1, MyByteV MOV r2, r12 SWI XOS_Release ; The block pointed at by r12 is freed for us by the kernel if nonzero CLRV EXIT END