Date : Fri, 20 Oct 2006 23:51:13 +0100 (BST) From : Greg Cook Subject: Re: Bugs in OS 1.20 (long) On Sat, 14 Oct 2006 16:47:12 +0200, John Kortink wrote: > Two major bugs I've just found in BBC OS 1.20 may be worthy > of attention if you use the ROM filing system, directly or > indirectly (e.g. if you produce ROMs containing ROM filing > system data). > > Acorn must have fixed these silently in later OS versions > (at least in the Master they seem to be). > > The culprit is a piece of routine at F232 which, after a > file load (tape/rom FS) intends to return the file size > in the OSFILE parameter block. It assumes the file size > is (&CC) (i.e. ?&CC+256*?&CD) and that the parameter block > address is (&C8) (i.e. ?&C8+256*?&C9). > > Bug #1 : &CC/CD are not updated UNLESS the file has loaded > under *OPT 1 2 (i.e. verbosely). > > Bug #2 : a *RUN does not do an OSFILE, but jumps straight > into the 'file load' routine without setting up a parameter > block, nor, therefore, its address in (&C8) ! > > Result 1 : OSFILE returns an incorrect file size (whatever > was in &CC/CD /before/ the file loaded) if not done under > *OPT 1 2. > > Result 2 : *RUNning a file randomly corrupts four contiguous > bytes in memory, in that the file size (correct or not) is > written to a non-existing parameter block, (&C8)+10 onwards, > i.e. where &C8/C9 are unset, as /before/ the file loaded. > > &C8/C9 will be 'wrong' easily, e.g. they may have been used > by previous filing systems (as selected before *ROM). > > Conclusion : > > a) Never use the file size returned from an OSFILE file load > unless you're certain *OPT 1 2 has been issued. > > b) NEVER *RUN a file. > > I'm not 100% sure that these apply to the tape filing system > as well, but they probably do, and they certainly apply to > the ROM filing system. > > Especially the *RUN problem is a /huge/ bug if you ask me. > Beware ! > > > John Kortink > > -- > > Email : kortink@... > Homepage : http://www.inter.nl.net/users/J.Kortink > > GoMMC, the ultimate BBC B/B+/Master storage system : > http://web.inter.nl.net/users/J.Kortink/home/hardware/gommc As John notes on the GoMMC mailing list, 'Result 2' (data corruption) can be avoided by entering *LOAD followed by CALL
. I put *TAPE in between, just to make sure. I expect these bugs do appear in CFS, it's just that the default option is to show the file information, so 'Result 1' disappears. The *RUN bug is not well known because typically when files are *RUN from tape (mostly games) the pointer has been left at a 'harmless' value (&FFFF from powerup, or the MOS's OSFILE block at &02EE.) If you are assembling a ROM image containing files that will be *RUN, the simplest fix is to set the pointer at &C8,&C9 to the value &00C2, whenever the data pointer at &F6,&F7 is initialised. This protects user memory but returns *nothing* to an OSFILE block. [[Not possible on non-OS 1.20 as other machine return full control block, including block+14, so &D0-&D3 would be overwritten]] (Aside: I've often rued the fact that Acorn couldn't leave space for patches, such as to return the load/execution address; perhaps they removed that capability to make room for something else, yet they placed a high priority on the unrolled CLS loop. Maybe there'd be room if the assembler used zero-page instructions wherever possible...) Where the above fix is unacceptable the ROM service code can peek at the 6502 stack to see if the *RUN code is loading the file, and if so initialise the OSFILE pointer. (This will be non-robust with 2^-16 probability of failure if the user makes service call &D directly.) The file length can be computed during service call &E; if there is no token to mark when to recalculate the length then it is more efficient to do it on every call. Below is the basic RFS service code from the AUG with a paged ROM header plus two inserts to work around the bugs John mentions. The resulting code is 51 bytes larger than the plain service code. Since the routine at &EE18 may be called from &F351 or &F790, the *RUN return address may appear at one of two depths in the stack. Finally, there's a third bug I've noticed in RFS and CFS; on opening an empty file with OPENIN, EOF# will correctly return nonzero, but BGET# will succeed once, returning &FE. Therefore the idiom REPEAT:...BGET#fh%...:UNTIL EOF#fh% will malfunction on empty files. Greg Cook debounce@... http://homepages.tesco.net/~rainstorm/ 8000 OPT pass% 8000 \ Based on basic server code 8000 \ from the Advanced User Guide, pp 330, 331 8000 .lang 8000 4C 7C 80 JMP exit 8003 .svc 8003 4C 38 80 JMP serve 8006 .type 8006 82 EQUB &82 8007 .cpptr 8007 28 EQUB copyr-lang 8008 .bnver 8008 00 EQUB &00 8009 .title 8009 42 75 67 66 69 78 20 52 4F 4D 46 53 EQUS "Bugfix ROMFS" 8015 .ver 8015 00 EQUB &00 8016 30 2E 30 31 20 28 32 30 20 4F 63 74 20 32 30 30 36 29 EQUS "0.01 (20 Oct 2006)" 8028 .copyr 8028 00 EQUB &00 8029 28 43 29 32 30 30 36 20 47 2E 43 6F 6F 6B EQUS "(C)2006 G.Cook" 8037 00 EQUB &00 8038 .serve 8038 C9 0D CMP #&0D \ Is it a ROM initialising call? 803A D0 41 BNE ninit \ No - branch 803C 48 PHA \ Save the service call type 803D 98 TYA \ Get logical ROM number 803E 49 0F EOR #&0F \ Adjust it (do 15-x) 8040 C5 F4 CMP &F4 \ Compare with this ROM's number 8042 90 37 BCC notus \ Number less, this ROM already been done 8044 A9 A7 LDA #data MOD 256 \ Low byte of data address 8046 85 F6 STA &F6 \ Location &F6 and &F7 reserved for this 8048 A9 80 LDA #data DIV 256 \ High byte of data address 804A 85 F7 STA &F7 \ Save high byte 804C A5 F4 LDA &F4 \ this ROM's number 804E 49 0F EOR #&0F \ Adjust it back (15-x) 8050 85 F5 STA &F5 \ pass over any higher non-filing system ROMs 8052 \ #################### INSERT 1 8052 8A TXA \ transfer X to A 8053 48 PHA \ save it 8054 BA TSX \ transfer 6502 stack pointer to X 8055 B8 CLV 8056 50 07 BVC test \ jump into test 8058 .next 8058 70 1B BVS init2 \ tested two addrs? if so restore AX and exit 805A E8 INX \ else increment copy of stack pointer 805B E8 INX \ to point to second address 805C 18 CLC \ clear carry flag 805D 69 80 ADC #&80 \ set overflow flag 805F .test 805F BD 16 01 LDA &0116,X \ peek high byte of a return address in stack 8062 C9 F3 CMP #&F3 \ does it match address of *RUN? 8064 D0 F2 BNE next \ if not try next address 8066 BD 15 01 LDA &0115,X \ else peek low byte 8069 C9 0F CMP #&0F \ is it the return address into *RUN? 806B D0 EB BNE next \ if not try next address 806D .fix 806D A9 C2 LDA #&C2 \ else initialise OSFILE pointer 806F 85 C8 STA &C8 \ to copy file length variable in zero page 8071 A9 00 LDA #&00 \ onto itself. &CE and &CF (unused by MOS) 8073 85 C9 STA &C9 \ will be cleared when loading is finished. 8075 .init2 8075 68 PLA \ get old value of X 8076 AA TAX \ return it to X 8077 \ #################### END INSERT 1 8077 68 PLA \ Discard service type 8078 A9 00 LDA #0 \ Set service type to no-operation 807A 60 RTS \ Exit 807B .notus 807B 68 PLA \ Restore service type 807C .exit 807C 60 RTS \ Exit 807D .ninit 807D C9 0E CMP #&0E \ Is it a byte request call? 807F D0 FB BNE exit \ No - exit 8081 48 PHA \ Save service type 8082 A5 F5 LDA &F5 \ Find the current ROM number 8084 49 0F EOR #&0F \ Adjust it 8086 C5 F4 CMP &F4 \ compare it with this ROM 8088 D0 F1 BNE notus \ Not the same, must be for another ROM 808A A0 00 LDY #0 \ Prepare to get the data 808C B1 F6 LDA (&F6),Y \ Get the data 808E A8 TAY \ In the Y register ready for exit 808F \ #################### INSERT 2 808F AD C6 03 LDA &03C6 \ get low byte of block number 8092 18 CLC \ add high byte of block length 8093 6D C9 03 ADC &03C9 8096 85 CD STA &CD \ store as high byte of length 8098 AD C8 03 LDA &03C8 \ get low byte of block length 809B 85 CC STA &CC \ store as low byte of length 809D \ #################### END INSERT 2 809D E6 F6 INC &F6 \ Increment the address for next time 809F D0 02 BNE ninc7 \ No need to increment &F7 80A1 E6 F7 INC &F7 80A3 .ninc7 80A3 68 PLA \ Discard service type 80A4 A9 00 LDA #0 \ Set service type to no-operation 80A6 60 RTS \ Exit 80A7 .data \ Data onward from here Send instant messages to your online friends http://uk.messenger.yahoo.com << Previous Message Main Index Next Message >> << Previous Message in Thread This Month Next Message in Thread >>