| 1 | REM |
| 2 | REM tearSupt.bs |
| 3 | REM |
| 4 | REM TearoffSupport code (encrypted) |
| 5 | REM |
| 6 | REM © 1994-1998 Straylight |
| 7 | REM |
| 8 | |
| 9 | REM ----- Licensing note ---------------------------------------------------- |
| 10 | REM |
| 11 | REM This file is part of Straylight's Tearoff Menu System (TMS), but it's |
| 12 | REM distributed with Straylight's core libraries (corelib). |
| 13 | REM |
| 14 | REM TMS is free software; you can redistribute it and/or modify |
| 15 | REM it under the terms of the GNU General Public License as published by |
| 16 | REM the Free Software Foundation; either version 2, or (at your option) |
| 17 | REM any later version |
| 18 | REM |
| 19 | REM TMS is distributed in the hope that it will be useful, |
| 20 | REM but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 21 | REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 22 | REM GNU General Public License for more details. |
| 23 | REM |
| 24 | REM You should have received a copy of the GNU General Public License |
| 25 | REM along with Corelib. If not, write to the Free Software Foundation, |
| 26 | REM 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| 27 | |
| 28 | LIBRARY "libs:BAS" |
| 29 | |
| 30 | ON ERROR ERROR 0,REPORT$+" ["+STR$(ERL)+"]" |
| 31 | PROCbas_init |
| 32 | PROCbas_aofInit(&4000) |
| 33 | |
| 34 | XOS_ClaimProcessorVector=&20069 |
| 35 | XOS_SynchroniseCodeAreas=&2006E |
| 36 | |
| 37 | PRINT "Assembling..."; |
| 38 | |
| 39 | ts_version=110 |
| 40 | |
| 41 | FOR o=4 TO 6 STEP 2 |
| 42 | [ opt o |
| 43 | FNpass |
| 44 | |
| 45 | ;----- TearoffSupport interface code ---------------------------------------- |
| 46 | |
| 47 | FNarea("Asm$$Code","CODE,READONLY") |
| 48 | |
| 49 | ; --- tearSupport_init --- |
| 50 | ; |
| 51 | ; On entry; -- |
| 52 | ; |
| 53 | ; On exit; -- |
| 54 | ; |
| 55 | ; Use; Initialises tearSupport |
| 56 | |
| 57 | FNexport("tearSupport_init") |
| 58 | .tearSupport_init |
| 59 | |
| 60 | stmfd r13!,{r0-r4,r12,r14} ;Save some registers |
| 61 | mvn r0,#0 ;Find address of TearSupport |
| 62 | swi "XOS_ChangeEnvironment" ;Find the address then |
| 63 | bvc tSupt_init10 ;If resident, skip install |
| 64 | |
| 65 | ; --- We need to set up the RMA block --- |
| 66 | |
| 67 | .tSupt_init00 ldr r3,ts__image ;Load RMA block size wanted |
| 68 | mov r0,#6 ;Allocate RMA space |
| 69 | swi "OS_Module" ;Try to allocate anyway |
| 70 | mov r1,r2 ;Keep pointer to RMA block |
| 71 | |
| 72 | ; --- Copy the program across and decrypt it --- |
| 73 | |
| 74 | adr r0,ts__image+4 ;Point to encrypted image |
| 75 | ldr r3,FNlitw(ts__imageEnd-ts__image-4) |
| 76 | ldr r12,FNlitw(&1b9a7f83) ;IV for decryption process |
| 77 | |
| 78 | .tSupt_init05 ldr r4,[r0],#4 ;Get a word from the image |
| 79 | eor r14,r12,r4,ror #24 ;Decrypt the word |
| 80 | str r14,[r2],#4 ;Store the word in the block |
| 81 | mov r12,r4 ;Update IV from ciphertext |
| 82 | subs r3,r3,#4 ;Decrement the size counter |
| 83 | bgt tSupt_init05 ;More to do -- loop |
| 84 | |
| 85 | ; --- Be friendly to StrongARM --- |
| 86 | ; |
| 87 | ; By spooky coincidence, these registers are set up already. |
| 88 | |
| 89 | mov r0,#1 ;Synchronise address range |
| 90 | sub r2,r2,#4 ;Because Acorn are weird... |
| 91 | swi XOS_SynchroniseCodeAreas ;Go and do that, please |
| 92 | |
| 93 | ; --- Initialise the image --- |
| 94 | |
| 95 | mov r14,pc ;Get return address |
| 96 | add pc,r1,#0 ;Call the initialise routine |
| 97 | str r1,ts__image ;Store base address away |
| 98 | ldmfd r13!,{r0-r4,r12,pc}^ ;Return to caller |
| 99 | |
| 100 | ; --- It's already resident --- |
| 101 | |
| 102 | .tSupt_init10 cmp r2,#ts_version ;Which version is in there? |
| 103 | strcs r1,ts__image ;New enough -- store base |
| 104 | ldmcsfd r13!,{r0-r4,r12,pc}^ ;And return to caller |
| 105 | |
| 106 | adr r0,ts__tooOld ;Point to error message |
| 107 | swi "OS_GenerateError" ;And raise merry hell |
| 108 | ldmfd r13!,{r0-r4,r12,pc}^ ;Return to caller |
| 109 | |
| 110 | .ts__tooOld dcd 1 |
| 111 | dcb "Tearoff support code is too old" |
| 112 | dcb 0 |
| 113 | |
| 114 | FNltorg |
| 115 | |
| 116 | ; --- tearSupport_opened --- |
| 117 | ; |
| 118 | ; On entry; R0 == task handle of task which opened tearoff menu |
| 119 | ; |
| 120 | ; On exit; -- |
| 121 | ; |
| 122 | ; Use; Informs TearSupport that a transient tearoff menu has been |
| 123 | ; opened, and which task owns the menu. |
| 124 | |
| 125 | FNexport("tearSupport_opened") |
| 126 | .tearSupport_opened |
| 127 | |
| 128 | stmfd r13!,{r12,r14} |
| 129 | ldr r12,ts__image |
| 130 | mov r14,pc |
| 131 | add pc,r12,#4 |
| 132 | ldmfd r13!,{r12,pc}^ |
| 133 | |
| 134 | ; --- tearSupport_closed --- |
| 135 | ; |
| 136 | ; On entry; -- |
| 137 | ; |
| 138 | ; On exit; -- |
| 139 | ; |
| 140 | ; Use; Informs TearSupport that a transient tearoff menu has been |
| 141 | ; closed, and that support is no longer required for it. |
| 142 | |
| 143 | FNexport("tearSupport_closed") |
| 144 | .tearSupport_closed |
| 145 | |
| 146 | stmfd r13!,{r12,r14} |
| 147 | ldr r12,ts__image |
| 148 | mov r14,pc |
| 149 | add pc,r12,#8 |
| 150 | ldmfd r13!,{r12,pc}^ |
| 151 | |
| 152 | ; --- tearSupport_switch --- |
| 153 | ; |
| 154 | ; On entry; R0 == 1 to disable, 0 to enable trapping |
| 155 | ; |
| 156 | ; On exit; -- |
| 157 | ; |
| 158 | ; Use; Enables or disables trapping of Wimp_CreateMenu while a |
| 159 | ; transient tearoff menu is open. This is intended to allow |
| 160 | ; use of Wimp_CreateMenu by the transient tearoff owner while |
| 161 | ; a transient tearoff is open (e.g. to close Wimp menus). |
| 162 | |
| 163 | FNexport("tearSupport_switch") |
| 164 | .tearSupport_switch |
| 165 | |
| 166 | stmfd r13!,{r12,r14} |
| 167 | ldr r12,ts__image |
| 168 | mov r14,pc |
| 169 | add pc,r12,#12 |
| 170 | ldmfd r13!,{r12,pc}^ |
| 171 | |
| 172 | ;----- The actual TearoffSupport code --------------------------------------- |
| 173 | |
| 174 | ; --- Structure of the code --- |
| 175 | ; |
| 176 | ; Since this chunk is going to be copied into the RMA, we need to be able to |
| 177 | ; interface with it. We stick a branch table on the beginning and encrypt |
| 178 | ; everything else. |
| 179 | |
| 180 | FNnoReloc |
| 181 | |
| 182 | .ts__image dcd ts__wSize+ts__wSpace-ts__image-4 |
| 183 | b ts_init |
| 184 | b ts_opened |
| 185 | b ts_closed |
| 186 | b ts_switch |
| 187 | b ts_unload |
| 188 | |
| 189 | ;----- Initialisation ------------------------------------------------------- |
| 190 | |
| 191 | ; --- ts_init --- |
| 192 | ; |
| 193 | ; On entry; -- |
| 194 | ; |
| 195 | ; On exit; -- |
| 196 | ; |
| 197 | ; Use; Initialises the TearSupport system. |
| 198 | |
| 199 | .ts_init stmfd r13!,{r0-r2,r14} ;Stack link register nicely |
| 200 | FNadrl (r12,ts__wSpace) ;Find workspace address |
| 201 | mov r0,#0 ;A nice 0 value |
| 202 | str r0,[r12,#ts_useCount] ;Stuff it in the usage count |
| 203 | str r0,[r12,#ts_owner] ;No task using me yet |
| 204 | strb r0,[r12,#ts_swiCaught] ;Remember we're not on SWIV |
| 205 | |
| 206 | mov r0,#ChangeEnvV ;Trap OS_ChangeEnvironment |
| 207 | adr r1,ts_changeEnv ;Point to my handler |
| 208 | mov r2,r12 ;Pass my workspace pointer |
| 209 | swi "XOS_Claim" ;Claim the vector nicely |
| 210 | |
| 211 | ; --- Read the OS version --- |
| 212 | |
| 213 | mov r0,#129 ;Load the OS version number |
| 214 | mov r1,#0 ;Set up OS_Byte arguments |
| 215 | mov r2,#255 ;For most obscure OS call |
| 216 | swi "OS_Byte" ;Read the version number |
| 217 | strb r1,[r12,#ts_osVersion] ;Save this away for later |
| 218 | |
| 219 | ; --- I think that's it --- |
| 220 | |
| 221 | ldmfd r13!,{r0-r2,pc}^ ;Return to caller happy |
| 222 | |
| 223 | FNltorg |
| 224 | |
| 225 | ; --- ts_unload --- |
| 226 | ; |
| 227 | ; On entry; -- |
| 228 | ; |
| 229 | ; On exit; V clear if unloaded OK, otherwise V set |
| 230 | ; |
| 231 | ; Use; Attempts to remove TearSupt from memory, to replace it with |
| 232 | ; a later version. If we can't close down, because we're in |
| 233 | ; use, we return an error. |
| 234 | |
| 235 | .ts_unload bic r14,r14,#&10000000 ;Clear the V flag |
| 236 | stmfd r13!,{r0-r2,r14} ;Save some registers |
| 237 | FNadrl (r12,ts__wSpace) ;Find the workspace address |
| 238 | |
| 239 | ; --- Free all the vectors --- |
| 240 | |
| 241 | mov r0,#ChangeEnvV ;Trap OS_ChangeEnvironment |
| 242 | adr r1,ts_changeEnv ;Point to my handler |
| 243 | mov r2,r12 ;Pass my workspace pointer |
| 244 | swi "XOS_Release" ;Let go of that |
| 245 | |
| 246 | bl ts_closed ;Pretend the transient closed |
| 247 | |
| 248 | ; --- Deallocate my memory --- |
| 249 | ; |
| 250 | ; This is a bit tricky, because I'm in it. I have to |
| 251 | ; copy a bit of myself onto the stack, and call that. Yuk. |
| 252 | |
| 253 | adr r14,ts__return ;Point to return code |
| 254 | ldmia r14,{r0-r2} ;Load the code out |
| 255 | stmfd r13!,{r0-r2} ;Save it onto the stack |
| 256 | |
| 257 | adr r2,ts__image+4 ;Point to the block base |
| 258 | mov r0,#7 ;Deallocate an RMA block |
| 259 | mov pc,r13 ;Call return code |
| 260 | |
| 261 | .ts__return swi "OS_Module" ;Deallocate the memory |
| 262 | add r13,r13,#12 ;Point to stack frame |
| 263 | ldmfd r13!,{r0-r2,pc}^ ;Return without mishap |
| 264 | |
| 265 | FNltorg |
| 266 | |
| 267 | ; --- Vector numbers --- |
| 268 | ] |
| 269 | MouseV = &1A |
| 270 | InsV = &14 |
| 271 | ChangeEnvV = &1E |
| 272 | [ opt o |
| 273 | |
| 274 | ; --- ts_opened --- |
| 275 | ; |
| 276 | ; On entry; R0 == task handle attempting to open tearoff transient |
| 277 | ; |
| 278 | ; On exit; -- |
| 279 | ; |
| 280 | ; Use; Informs the TearSupt system that a task is opening a |
| 281 | ; transient tearoff menu. |
| 282 | |
| 283 | |
| 284 | .ts_opened stmfd r13!,{r0-r2,r11,r12,r14} |
| 285 | mov r11,r0 ;Look after the task handle |
| 286 | FNadrl (r12,ts__wSpace) ;Find my workspace address |
| 287 | |
| 288 | ; --- Make sure we need to do this --- |
| 289 | |
| 290 | ldr r0,[r12,#ts_useCount] ;Get the counter |
| 291 | cmp r0,#0 ;Am I currently running? |
| 292 | bne ts_opened00 ;Yes -- skip this little bit |
| 293 | |
| 294 | ; --- Claim event vector --- |
| 295 | |
| 296 | swi "XOS_Mouse" ;Get the current mouse pos |
| 297 | str r2,[r12,#ts_mouseState] ;Store it in workspace |
| 298 | |
| 299 | mov r0,#MouseV ;Vector number |
| 300 | adr r1,ts_mouse ;Point to event handler |
| 301 | mov r2,r12 ;Point to workspace |
| 302 | swi "XOS_Claim" ;Try it and see |
| 303 | |
| 304 | mov r0,#InsV ;Vector number |
| 305 | adr r1,ts_insert ;Point to event handler |
| 306 | mov r2,r12 ;Point to workspace |
| 307 | swi "XOS_Claim" ;Try it and see |
| 308 | |
| 309 | addvs r13,r13,#4 |
| 310 | ldmvsfd r13!,{r1,r2,r11,r12,pc} ;Can't see this failing, but |
| 311 | |
| 312 | bl ts_swiClaim |
| 313 | |
| 314 | ; --- Update my tables and leave --- |
| 315 | |
| 316 | .ts_opened00 ldr r0,[r12,#ts_owner] ;Who's using me at the mo? |
| 317 | cmp r0,r11 ;Is it someone else? |
| 318 | cmpne r0,#0 ;Make sure s'not a ghost |
| 319 | blne ts_escape_cb ;Tell the appl to close |
| 320 | str r11,[r12,#ts_owner] ;Store the new handle |
| 321 | |
| 322 | ldr r0,[r12,#ts_useCount] ;Find my usage counter |
| 323 | add r0,r0,#1 ;Bump it |
| 324 | str r0,[r12,#ts_useCount] ;And store it back for later |
| 325 | |
| 326 | ldmfd r13!,{r0-r2,r11,r12,pc}^ |
| 327 | |
| 328 | FNltorg |
| 329 | |
| 330 | ; --- ts_closed --- |
| 331 | ; |
| 332 | ; On entry; -- |
| 333 | ; |
| 334 | ; On exit; -- |
| 335 | ; |
| 336 | ; Use; Informs TearSupt that the transient tearoff has been closed. |
| 337 | ; If no transient is open, no action is performed. |
| 338 | |
| 339 | .ts_closed stmfd r13!,{r12,r14} ;Save some registers |
| 340 | adr r12,ts__wSpace ;Find my workspace address |
| 341 | ldr r14,[r12,#ts_useCount] ;Find out my counter thing |
| 342 | cmp r14,#0 ;Is it zero? |
| 343 | ldmeqfd r13!,{r12,pc}^ ;Someone's being silly |
| 344 | subs r14,r14,#1 ;Decrement the counter |
| 345 | str r14,[r12,#ts_useCount] ;Store for later |
| 346 | ldmnefd r13!,{r12,pc}^ ;Return if still nonzero |
| 347 | |
| 348 | ; --- Remove handlers and things --- |
| 349 | |
| 350 | stmfd r13!,{r0-r2} ;Save some more registers |
| 351 | bl ts_swiRelease ;Release SWI vector patch |
| 352 | |
| 353 | mov r0,#InsV ;Vector number |
| 354 | adr r1,ts_insert ;Point to handler code |
| 355 | mov r2,r12 ;Point to workspace |
| 356 | swi "XOS_Release" ;Let go of the vector |
| 357 | |
| 358 | mov r0,#MouseV ;Vector number |
| 359 | adr r1,ts_mouse ;Point to handler code |
| 360 | mov r2,r12 ;Point to workspace |
| 361 | swi "XOS_Release" ;Let go of the vector |
| 362 | |
| 363 | ldmfd r13!,{r0-r2,r12,pc}^ ;Return to caller |
| 364 | |
| 365 | FNltorg |
| 366 | |
| 367 | ; --- ts_switch --- |
| 368 | ; |
| 369 | ; On entry; R0 == 1 to suspend trapping, 0 to unsuspend |
| 370 | ; |
| 371 | ; On exit; -- |
| 372 | ; |
| 373 | ; Use; Enables or disables trapping of Wimp_CreateMenu, to enable |
| 374 | ; TMS implementations to close Wimp menus where necessary. |
| 375 | |
| 376 | .ts_switch stmfd r13!,{r12,r14} ;Save some registers |
| 377 | adr r12,ts__wSpace ;Find my workspace |
| 378 | strb r0,[r12,#ts_swiThreaded] ;Disable the SWI patch |
| 379 | ldmfd r13!,{r12,pc}^ ;And return to caller |
| 380 | |
| 381 | FNltorg |
| 382 | |
| 383 | ;----- The handlers and callbacks ------------------------------------------- |
| 384 | |
| 385 | ; --- ts_changeEnv --- |
| 386 | ; |
| 387 | ; On entry; As for OS_ChangeEnvironment |
| 388 | ; |
| 389 | ; On exit; R0 == address of TearSupt, if R0 == -1 on entry |
| 390 | ; |
| 391 | ; Use; Traps odd calls to OS_ChangeEnvironment to allow TearSupt |
| 392 | ; to be located. |
| 393 | |
| 394 | .ts_changeEnv cmn r0,#1 ;Is it our special env code? |
| 395 | adreq r1,ts__image+4 ;Yes -- return ptr to base |
| 396 | moveq r2,#ts_version ;And get the version number |
| 397 | ldmeqfd r13!,{pc}^ ;And claim the vector |
| 398 | movs pc,r14 ;Otherwise pass on vector |
| 399 | |
| 400 | ; --- ts_insert --- |
| 401 | ; |
| 402 | ; On entry; R0 == byte inserted into buffer |
| 403 | ; R1 == buffer number |
| 404 | ; |
| 405 | ; On exit; -- |
| 406 | ; |
| 407 | ; Use; Inspects all insertions into buffers, and traps attempts |
| 408 | ; to insert escape keypresses, converting these to requests |
| 409 | ; to close the current transient tearoff. |
| 410 | |
| 411 | .ts_insert cmp r0,#27 ;Make sure it's an escape |
| 412 | cmpeq r1,#0 ;And it's from the keyboard |
| 413 | movnes pc,r14 ;If not, give up and leave |
| 414 | stmfd r13!,{r14} ;Save a register |
| 415 | ldr r14,[r12,#ts_owner] ;Get my owner's ID |
| 416 | cmn r14,#1 ;Is it valid? |
| 417 | ldmeqfd r13!,{pc}^ ;No -- then return to caller |
| 418 | |
| 419 | ; --- Mess about with the processor status --- |
| 420 | |
| 421 | stmfd r13!,{r0,r1,r8} ;Store registers away |
| 422 | mov r8,pc ;Get PC with PSR |
| 423 | teqp pc,#3 ;Enter SVC mode |
| 424 | mov r0,r0 ;Avoid contention of R13/R14 |
| 425 | stmfd r13!,{r14} ;Stack return address |
| 426 | adr r0,ts_escape_cb ;Point to callback routine |
| 427 | mov r1,r12 ;Point to workspace |
| 428 | swi "XOS_AddCallBack" ;Add the callback routine |
| 429 | ldmfd r13!,{r14} ;Restore R14_svc |
| 430 | teqp r8,#0 ;Restore old PSR values |
| 431 | mov r0,r0 ;No-op to keep ARM happy |
| 432 | ldmfd r13!,{r0,r1,r8,pc}^ ;Return to caller |
| 433 | |
| 434 | FNltorg |
| 435 | |
| 436 | ; --- ts_mouse --- |
| 437 | ; |
| 438 | ; On entry; -- |
| 439 | ; |
| 440 | ; On exit; -- |
| 441 | ; |
| 442 | ; Use; Inspects all mouse positions returned by OS_Mouse, and sends |
| 443 | ; them to the current transient owner. |
| 444 | |
| 445 | .ts_mouse stmfd r13!,{r10-r12,r14} ;Stack some registers |
| 446 | |
| 447 | ; --- Pass on the vector, leaving ourself on the stack --- |
| 448 | ; |
| 449 | ; Modified from Acorn's code to avoid dependency on |
| 450 | ; possibly non-compatible PC+12 behaviour. |
| 451 | |
| 452 | mov r14,pc ;Get current program counter |
| 453 | add r14,r14,#12 ;Point at our processing code |
| 454 | stmfd r13!,{r14} ;Make us get called back |
| 455 | add r12,r13,#4 ;Point to saved R10 on stack |
| 456 | ldmia r12,{r10-r12,pc} ;Call next routine on vector |
| 457 | |
| 458 | ; --- The vector has now completed nicely --- |
| 459 | |
| 460 | ldr r12,[r13,#8] ;Get my stacked r12 |
| 461 | |
| 462 | stmfd r13!,{r0-r3} ;Stack some registers for me |
| 463 | ldr r0,[r12,#ts_mouseState] ;Get old mouse state |
| 464 | str r2,[r12,#ts_mouseState] ;Store as the old state |
| 465 | bics r2,r2,r0 ;Find out what changed |
| 466 | ldmeqfd r13!,{r0-r3,r10-r12,r14,pc} ;If nothing then return |
| 467 | |
| 468 | ; --- A button was clicked -- tell our client --- |
| 469 | |
| 470 | add r1,r12,#ts_message+20 ;Point to message buffer |
| 471 | swi "XWimp_GetPointerInfo" ;Get pointer info |
| 472 | sub r1,r1,#20 ;Point to base of message |
| 473 | mov r0,#40 ;Length of message |
| 474 | str r0,[r1,#0] ;Store in message block |
| 475 | mov r0,#0 ;This isn't a reply |
| 476 | str r0,[r1,#12] ;So zero the your_ref |
| 477 | ldr r0,FNlitw(&4A340) ;The magic message number |
| 478 | str r0,[r1,#16] ;Fill it in |
| 479 | mov r0,#17 ;Don't want it bouncing |
| 480 | ldr r2,[r12,#ts_owner] ;Find my owner application |
| 481 | swi "XWimp_SendMessage" ;Send it the message |
| 482 | |
| 483 | ldmfd r13!,{r0-r3,r10-r12,r14,pc} ;We're a happy bunny |
| 484 | |
| 485 | FNltorg |
| 486 | |
| 487 | ; --- ts_escape_cb --- |
| 488 | ; |
| 489 | ; On entry; -- |
| 490 | ; |
| 491 | ; On exit; -- |
| 492 | ; |
| 493 | ; Use; Sends a message to the transient tearoff owner, to tell |
| 494 | ; it to close the transient. This is usually as a result of |
| 495 | ; the user pressing escape or another task calling |
| 496 | ; Wimp_CreateMenu. |
| 497 | |
| 498 | .ts_escape_cb stmfd r13!,{r0-r3,r14} ;Save some registers |
| 499 | add r1,r12,#ts_message ;Point to message buffer |
| 500 | mov r0,#20 ;Length of message |
| 501 | str r0,[r1,#0] ;Store in message block |
| 502 | mov r0,#0 ;This isn't a reply |
| 503 | str r0,[r1,#12] ;So zero the your_ref |
| 504 | ldr r0,FNlitw(&4A341) ;The magic message number |
| 505 | str r0,[r1,#16] ;Fill it in |
| 506 | mov r0,#17 ;Don't want it bouncing |
| 507 | ldr r2,[r12,#ts_owner] ;Find my owner application |
| 508 | swi "XWimp_SendMessage" ;Send it the message |
| 509 | mvn r0,#0 ;Stop it happening again |
| 510 | str r0,[r12,#ts_owner] ;Won't happen now! |
| 511 | ldmfd r13!,{r0-r3,pc}^ ;Don't worry. Be happy. |
| 512 | |
| 513 | FNltorg |
| 514 | |
| 515 | ;----- SWI vector handling -------------------------------------------------- |
| 516 | ; |
| 517 | ; Warning; this section contains some really heavy stuff. If you're nervous, |
| 518 | ; you may wish to seek medical advice before looking at this code. We can't |
| 519 | ; accept any responsibility for any loss or disability incurred as a result |
| 520 | ; of reading this source. |
| 521 | |
| 522 | ; --- ts_swiClaim --- |
| 523 | ; |
| 524 | ; On entry; -- |
| 525 | ; |
| 526 | ; On exit; -- |
| 527 | ; |
| 528 | ; Use; Sets up the SWI vector patch. |
| 529 | |
| 530 | .ts_swiClaim stmfd r13!,{r0-r3,r14} ;Stack some registers |
| 531 | ldrb r0,[r12,#ts_swiCaught] ;Have we done it already? |
| 532 | cmp r0,#0 ;Just check |
| 533 | ldmnefd r13!,{r0-r3,pc}^ ;If so, just carry on |
| 534 | |
| 535 | ldrb r14,[r12,#ts_osVersion] ;Get the OS version |
| 536 | cmp r14,#&a5 ;Is this a RISC PC? |
| 537 | bcs ts_swiClaim50 ;Yes -- do special things |
| 538 | |
| 539 | mov r0,#0 ;Point to hardware vectors |
| 540 | ldr r1,[r0,#&08] ;Get the SWIV instruction |
| 541 | str r1,[r12,#ts_oldSWIinstr] ;Remember this instruction |
| 542 | and r2,r1,#&0F000000 ;Get the basic instruction |
| 543 | cmp r2,#&0A000000 ;Is it a branch? |
| 544 | beq ts_swiClaim00 ;Yes -- handle that |
| 545 | |
| 546 | ; --- Mangle an LDR PC,[PC,#...] --- |
| 547 | |
| 548 | ldr r2,FNlitw(&FFF) ;Mask off LDR bits |
| 549 | and r2,r1,r2 ;Get the offset of LDR |
| 550 | tst r1,#1<<23 ;Check the sign bit |
| 551 | addne r3,r2,#&10 ;If additive, then add offset |
| 552 | rsbeq r3,r2,#&10 ;If subtractive, subtract ;-) |
| 553 | str r3,[r12,#ts_oldSWIaddr] ;Store this address away |
| 554 | b ts_swiClaim01 ;Now insert our branch code |
| 555 | |
| 556 | ; --- Mangle a B ... --- |
| 557 | |
| 558 | .ts_swiClaim00 bic r2,r1,#&FF000000 ;Clear instruction bits |
| 559 | add r2,r2,#4 ;Take pipeline into account |
| 560 | mov r2,r2,lsl #2 ;Word align the result |
| 561 | bic r2,r2,#&FC000003 ;Turn it into a real address |
| 562 | str r2,[r12,#ts_dummySWIptr] ;Store this in our pointer |
| 563 | add r3,r12,#ts_dummySWIptr ;Point to this pointer |
| 564 | str r3,[r12,#ts_oldSWIaddr] ;Store *this* address away |
| 565 | |
| 566 | ; --- Now insert our own instruction --- |
| 567 | |
| 568 | .ts_swiClaim01 adr r1,ts_swiClaimer ;Point to the routine |
| 569 | mov r1,r1,lsr #2 ;Shift off bottom zero bits |
| 570 | sub r1,r1,#4 ;Adjust the address of branch |
| 571 | orr r1,r1,#&EA000000 ;Make it a branch instr |
| 572 | str r1,[r12,#ts_newSWIinstr] ;Store this new instruction |
| 573 | swi "OS_EnterOS" ;We're messing with SWI vect |
| 574 | str r1,[r0,#8] ;This is now the SWI vector |
| 575 | teqp pc,#0 ;Back to user mode |
| 576 | mov r0,r0 ;No-op for strange reasons |
| 577 | mov r0,#1 ;We've now patched SWIV |
| 578 | strb r0,[r12,#ts_swiCaught] ;So remember this |
| 579 | mov r0,#0 ;Not yet threaded, though |
| 580 | strb r0,[r12,#ts_swiThreaded] |
| 581 | ldmfd r13!,{r0-r3,pc}^ ;Return to caller |
| 582 | |
| 583 | ; --- We have an OS call to do this --- |
| 584 | |
| 585 | .ts_swiClaim50 mov r0,#2 ;Claim SWI vector |
| 586 | orr r0,r0,#256 ;Set the `claim' flag |
| 587 | adr r1,ts_swi610 ;Point to handler routine |
| 588 | swi "XOS_IntOff" ;Stop all SWIs for a bit |
| 589 | swi XOS_ClaimProcessorVector |
| 590 | str r1,[r12,#ts_dummySWIptr] ;Save old handler address |
| 591 | add r3,r12,#ts_dummySWIptr ;Point to this pointer |
| 592 | str r3,[r12,#ts_oldSWIaddr] ;And store *this* address |
| 593 | swi "XOS_IntOn" ;We can handle SWIs again now |
| 594 | |
| 595 | mov r0,#1 ;We've now patched SWIV |
| 596 | strb r0,[r12,#ts_swiCaught] ;So remember this |
| 597 | mov r0,#0 ;Not yet threaded, though |
| 598 | strb r0,[r12,#ts_swiThreaded] |
| 599 | |
| 600 | ldmfd r13!,{r0-r3,pc}^ ;Return to caller |
| 601 | |
| 602 | FNltorg |
| 603 | |
| 604 | ; --- ts_swiRelease --- |
| 605 | ; |
| 606 | ; On entry; -- |
| 607 | ; |
| 608 | ; On exit; CS if patch removed OK, else CC |
| 609 | ; |
| 610 | ; Use; Attempts to remove the SWI vector patch. If this can't be |
| 611 | ; done, then the patch is left in. |
| 612 | |
| 613 | .ts_swiRelease stmfd r13!,{r0-r2,r14} ;Stack registers |
| 614 | ldrb r0,[r12,#ts_swiCaught] ;Is the vector trapped? |
| 615 | cmp r0,#0 ;Quick check... |
| 616 | ldmeqfd r13!,{r0-r2,pc}^ ;No -- return then |
| 617 | |
| 618 | ; --- Check if this is a RISC PC --- |
| 619 | |
| 620 | ldrb r0,[r12,#ts_osVersion] ;Load the OS version |
| 621 | cmp r0,#&a5 ;Is this a RISC PC |
| 622 | bcs ts_swiRel50 ;Yes -- do different things |
| 623 | |
| 624 | mov r0,#0 ;Point to hardware vectors |
| 625 | ldr r1,[r0,#8] ;Get SWI vector instruction |
| 626 | ldr r2,[r12,#ts_newSWIinstr] ;Get our one |
| 627 | cmp r1,r2 ;Are they the same? |
| 628 | bne ts_swiRel90 ;No -- couldn't reset it |
| 629 | |
| 630 | ldr r1,[r12,#ts_oldSWIinstr] ;Get the old version then |
| 631 | swi "OS_EnterOS" ;We're messing with SWI vect |
| 632 | str r1,[r0,#8] ;Reinstate the old vector |
| 633 | teqp pc,#0 ;Back to user mode |
| 634 | mov r0,r0 ;Wait for things to settle |
| 635 | strb r0,[r12,#ts_swiCaught] ;SWIV no longer patched |
| 636 | ldmfd r13!,{r0-r2,r14} ;Return to caller |
| 637 | orrs pc,r14,#1<<29 ;Setting C to say *YES* |
| 638 | |
| 639 | ; --- Release SWI vector using OS call --- |
| 640 | |
| 641 | .ts_swiRel50 mov r0,#2 ;Releasing the SWI vector |
| 642 | ldr r1,[r12,#ts_dummySWIptr] ;Load address of old claimer |
| 643 | adr r2,ts_swi610 ;Point to expected handler |
| 644 | swi XOS_ClaimProcessorVector |
| 645 | bvs ts_swiRel90 ;Error -- couldn't do it |
| 646 | |
| 647 | mov r14,#0 ;Clear claimed flag |
| 648 | strb r14,[r12,#ts_swiCaught] ;SWIV no longer patched |
| 649 | ldmfd r13!,{r0-r2,r14} ;Return to caller |
| 650 | orrs pc,r14,#1<<29 ;Setting C to say *YES* |
| 651 | |
| 652 | ; --- Couldn't do it --- |
| 653 | |
| 654 | .ts_swiRel90 ldmfd r13!,{r0-r2,r14} ;Restore registers |
| 655 | bics pc,r14,#1<<29 ;But clear C on exit |
| 656 | |
| 657 | FNltorg |
| 658 | |
| 659 | ; --- ts_swi610 --- |
| 660 | ; |
| 661 | ; On entry; R0-R8 == arguments to SWI |
| 662 | ; R9-R12 == random values from the OS |
| 663 | ; R13 == supervisor stack pointer |
| 664 | ; R14 == return address from client |
| 665 | ; |
| 666 | ; On exit; R0-R8 == returned from SWI |
| 667 | ; R9-R13 *AND SPSR_svc* preserved |
| 668 | ; |
| 669 | ; Use; Intercepts all SWI calls in the system, catching |
| 670 | ; Wimp_CreateMenus and informing the transient owner of them. |
| 671 | |
| 672 | .ts_swi610 stmfd r13!,{r10-r12,r14,pc} ;Stack some registers |
| 673 | |
| 674 | ; --- Move into 26 bit mode --- |
| 675 | |
| 676 | dcd &e14fb000 ;mrs r11,spsr_all |
| 677 | stmfd r13!,{r11} ;Save this on the stack |
| 678 | and r12,r11,#&f0000003 ;Get the processor status |
| 679 | orr r14,r14,r12 ;Add it to the R14 value |
| 680 | and r12,r11,#&c0 ;Get the interrupt flags |
| 681 | orr r14,r14,r12,lsl #20 ;Put them into R14 too |
| 682 | dcd &e10fb000 ;mrs r11,cpsr_all |
| 683 | bic r11,r11,#&1f ;Clear all the mode bits |
| 684 | orr r11,r11,#&03 ;Set SVC_26 |
| 685 | dcd &e129f00b ;msr cpsr_all,r11 |
| 686 | |
| 687 | ; --- Now find out about the SWI --- |
| 688 | |
| 689 | adr r12,ts__wSpace ;Point to workspace pointer |
| 690 | ldrb r10,[r12,#ts_swiThreaded] ;Is this routine threaded? |
| 691 | cmp r10,#0 ;Check now, or forever... |
| 692 | bne ts_swi610_00 ;If so, skip onwards |
| 693 | bic r10,r14,#&FC000003 ;Mask off saved PSR bits |
| 694 | ldr r11,[r10,#-4] ;Get SWI instruction |
| 695 | ldr r10,FNlitw(&FFF20000) ;Mask off silly SWI bits |
| 696 | bic r11,r11,r10 ;Get the pure SWI number |
| 697 | ldr r10,FNlitw(FNswiNum("Wimp_CreateMenu")) |
| 698 | cmp r10,r11 ;See if it's interesting |
| 699 | beq ts_swi610_10 ;Yes -- process it nicely |
| 700 | |
| 701 | .ts_swi610_00 ldmfd r13!,{r14} ;Load the saved SPSR |
| 702 | dcd &e169f00e ;msr spsr_all,r14 |
| 703 | |
| 704 | ldr r14,[r12,#ts_oldSWIaddr] ;Point to old pointer |
| 705 | ldr r14,[r14,#0] ;Dereference the pointer |
| 706 | str r14,[r13,#16] ;Overwrite PC on the stack |
| 707 | ldmfd r13!,{r10-r12,r14,pc} ;Pass on to real SWI routine |
| 708 | |
| 709 | ; --- Wimp_CreateMenu handling --- |
| 710 | |
| 711 | .ts_swi610_10 mov r10,#1 ;Set the threaded flag |
| 712 | strb r10,[r12,#ts_swiThreaded] ;Remember we're in here |
| 713 | |
| 714 | bl ts_escape_cb ;Send out the close message |
| 715 | |
| 716 | .ts_swi610_01 mov r10,#0 ;Not threaded any more |
| 717 | strb r10,[r12,#ts_swiThreaded] ;Store this for others |
| 718 | b ts_swi610_00 ;And continue main thread |
| 719 | |
| 720 | FNltorg |
| 721 | |
| 722 | ; --- ts_swiClaimer --- |
| 723 | ; |
| 724 | ; On entry; R0-R8 == arguments to SWI |
| 725 | ; R9-R12 == random values from the OS |
| 726 | ; R13 == supervisor stack pointer |
| 727 | ; R14 == return address from client |
| 728 | ; |
| 729 | ; On exit; R0-R8 == returned from SWI |
| 730 | ; R9-R13 preserved |
| 731 | ; |
| 732 | ; Use; Intercepts all SWI calls in the system, catching |
| 733 | ; Wimp_CreateMenus and informing the transient owner of them. |
| 734 | |
| 735 | .ts_swiClaimer stmfd r13!,{r10-r12,r14,pc} ;Stack some registers |
| 736 | adr r12,ts__wSpace ;Point to workspace pointer |
| 737 | ldrb r10,[r12,#ts_swiThreaded] ;Is this routine threaded? |
| 738 | cmp r10,#0 ;Check now, or forever... |
| 739 | bne ts_swiClaimer00 ;If so, skip onwards |
| 740 | bic r10,r14,#&FC000003 ;Mask off saved PSR bits |
| 741 | ldr r11,[r10,#-4] ;Get SWI instruction |
| 742 | ldr r10,FNlitw(&FFF20000) ;Mask off silly SWI bits |
| 743 | bic r11,r11,r10 ;Get the pure SWI number |
| 744 | ldr r10,FNlitw(FNswiNum("Wimp_CreateMenu")) |
| 745 | cmp r10,r11 ;See if it's interesting |
| 746 | beq ts_swiClaimer10 ;Yes -- process it nicely |
| 747 | |
| 748 | .ts_swiClaimer00 |
| 749 | ldr r14,[r12,#ts_oldSWIaddr] ;Point to old pointer |
| 750 | ldr r14,[r14,#0] ;Dereference the pointer |
| 751 | str r14,[r13,#16] ;Overwrite PC on the stack |
| 752 | ldmfd r13!,{r10-r12,r14,pc} ;Pass on to real SWI routine |
| 753 | |
| 754 | ; --- Wimp_CreateMenu handling --- |
| 755 | |
| 756 | .ts_swiClaimer10 |
| 757 | mov r10,#1 ;Set the threaded flag |
| 758 | strb r10,[r12,#ts_swiThreaded] ;Remember we're in here |
| 759 | |
| 760 | bl ts_escape_cb ;Send out the close message |
| 761 | |
| 762 | .ts_swiClaimer01 |
| 763 | mov r10,#0 ;Not threaded any more |
| 764 | strb r10,[r12,#ts_swiThreaded] ;Store this for others |
| 765 | b ts_swiClaimer00 ;And continue main thread |
| 766 | |
| 767 | FNltorg |
| 768 | |
| 769 | .ts__wSpace |
| 770 | .ts__imageEnd |
| 771 | ] |
| 772 | |
| 773 | PROCws_start |
| 774 | ts_useCount =FNws_word |
| 775 | ts_owner =FNws_word |
| 776 | ts_mouseState =FNws_word |
| 777 | ts_newMouse =FNws_word |
| 778 | ts_oldSWIaddr =FNws_word |
| 779 | ts_dummySWIptr =FNws_word |
| 780 | ts_oldSWIinstr =FNws_word |
| 781 | ts_newSWIinstr =FNws_word |
| 782 | ts_swiCaught =FNws_byte |
| 783 | ts_swiThreaded =FNws_byte |
| 784 | ts_osVersion =FNws_byte |
| 785 | PROCws_align |
| 786 | ts_message =FNws (40) |
| 787 | ts__wSize =FNws (0) |
| 788 | |
| 789 | NEXT |
| 790 | |
| 791 | PRINT '"Encrypting..."; |
| 792 | |
| 793 | REM --- Encrypt the RMA resident section --- |
| 794 | |
| 795 | iv%=&1b9a7f83 |
| 796 | FOR i%=ts__image+4 TO ts__imageEnd STEP 4 |
| 797 | x%=i%!(O%-P%) EOR iv% |
| 798 | x%=(x%>>>8) OR (x%<<24) |
| 799 | i%!(O%-P%)=x% |
| 800 | iv%=x% |
| 801 | NEXT |
| 802 | |
| 803 | PRINT '"Saving..."; |
| 804 | PROCbas_aofSave |
| 805 | PRINT '"Done" |
| 806 | END |
| 807 | |
| 808 | DEF FNswiNum(swi$) |
| 809 | LOCAL swin% |
| 810 | SYS "OS_SWINumberFromString",,swi$ TO swin% |
| 811 | =swin% |
| 812 | |