Home | History | Annotate | Line # | Download | only in fuc
      1 /*
      2  *  fuc microcode for g98 sec engine
      3  *  Copyright (C) 2010  Marcin Kocielnicki
      4  *
      5  *  This program is free software; you can redistribute it and/or modify
      6  *  it under the terms of the GNU General Public License as published by
      7  *  the Free Software Foundation; either version 2 of the License, or
      8  *  (at your option) any later version.
      9  *
     10  *  This program is distributed in the hope that it will be useful,
     11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  *  GNU General Public License for more details.
     14  *
     15  *  You should have received a copy of the GNU General Public License
     16  *  along with this program; if not, write to the Free Software
     17  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     18  */
     19 
     20 .section #g98_sec_data
     21 
     22 ctx_dma:
     23 ctx_dma_query:		.b32 0
     24 ctx_dma_src:		.b32 0
     25 ctx_dma_dst:		.b32 0
     26 .equ #dma_count 3
     27 ctx_query_address_high:	.b32 0
     28 ctx_query_address_low:	.b32 0
     29 ctx_query_counter:	.b32 0
     30 ctx_cond_address_high:	.b32 0
     31 ctx_cond_address_low:	.b32 0
     32 ctx_cond_off:		.b32 0
     33 ctx_src_address_high:	.b32 0
     34 ctx_src_address_low:	.b32 0
     35 ctx_dst_address_high:	.b32 0
     36 ctx_dst_address_low:	.b32 0
     37 ctx_mode:		.b32 0
     38 .align 16
     39 ctx_key:		.skip 16
     40 ctx_iv:			.skip 16
     41 
     42 .align 0x80
     43 swap:
     44 .skip 32
     45 
     46 .align 8
     47 common_cmd_dtable:
     48 .b32 #ctx_query_address_high + 0x20000 ~0xff
     49 .b32 #ctx_query_address_low + 0x20000 ~0xfffffff0
     50 .b32 #ctx_query_counter + 0x20000 ~0xffffffff
     51 .b32 #cmd_query_get + 0x00000 ~1
     52 .b32 #ctx_cond_address_high + 0x20000 ~0xff
     53 .b32 #ctx_cond_address_low + 0x20000 ~0xfffffff0
     54 .b32 #cmd_cond_mode + 0x00000 ~7
     55 .b32 #cmd_wrcache_flush + 0x00000 ~0
     56 .equ #common_cmd_max 0x88
     57 
     58 
     59 .align 8
     60 engine_cmd_dtable:
     61 .b32 #ctx_key + 0x0 + 0x20000 ~0xffffffff
     62 .b32 #ctx_key + 0x4 + 0x20000 ~0xffffffff
     63 .b32 #ctx_key + 0x8 + 0x20000 ~0xffffffff
     64 .b32 #ctx_key + 0xc + 0x20000 ~0xffffffff
     65 .b32 #ctx_iv + 0x0 + 0x20000 ~0xffffffff
     66 .b32 #ctx_iv + 0x4 + 0x20000 ~0xffffffff
     67 .b32 #ctx_iv + 0x8 + 0x20000 ~0xffffffff
     68 .b32 #ctx_iv + 0xc + 0x20000 ~0xffffffff
     69 .b32 #ctx_src_address_high + 0x20000 ~0xff
     70 .b32 #ctx_src_address_low + 0x20000 ~0xfffffff0
     71 .b32 #ctx_dst_address_high + 0x20000 ~0xff
     72 .b32 #ctx_dst_address_low + 0x20000 ~0xfffffff0
     73 .b32 #sec_cmd_mode + 0x00000 ~0xf
     74 .b32 #sec_cmd_length + 0x10000 ~0x0ffffff0
     75 .equ #engine_cmd_max 0xce
     76 
     77 .align 4
     78 sec_dtable:
     79 .b16 #sec_copy_prep #sec_do_inout
     80 .b16 #sec_store_prep #sec_do_out
     81 .b16 #sec_ecb_e_prep #sec_do_inout
     82 .b16 #sec_ecb_d_prep #sec_do_inout
     83 .b16 #sec_cbc_e_prep #sec_do_inout
     84 .b16 #sec_cbc_d_prep #sec_do_inout
     85 .b16 #sec_pcbc_e_prep #sec_do_inout
     86 .b16 #sec_pcbc_d_prep #sec_do_inout
     87 .b16 #sec_cfb_e_prep #sec_do_inout
     88 .b16 #sec_cfb_d_prep #sec_do_inout
     89 .b16 #sec_ofb_prep #sec_do_inout
     90 .b16 #sec_ctr_prep #sec_do_inout
     91 .b16 #sec_cbc_mac_prep #sec_do_in
     92 .b16 #sec_cmac_finish_complete_prep #sec_do_in
     93 .b16 #sec_cmac_finish_partial_prep #sec_do_in
     94 
     95 .align 0x100
     96 
     97 .section #g98_sec_code
     98 
     99 	// $r0 is always set to 0 in our code - this allows some space savings.
    100 	clear b32 $r0
    101 
    102 	// set up the interrupt handler
    103 	mov $r1 #ih
    104 	mov $iv0 $r1
    105 
    106 	// init stack pointer
    107 	mov $sp $r0
    108 
    109 	// set interrupt dispatch - route timer, fifo, ctxswitch to i0, others to host
    110 	movw $r1 0xfff0
    111 	sethi $r1 0
    112 	mov $r2 0x400
    113 	iowr I[$r2 + 0x300] $r1
    114 
    115 	// enable the interrupts
    116 	or $r1 0xc
    117 	iowr I[$r2] $r1
    118 
    119 	// enable fifo access and context switching
    120 	mov $r1 3
    121 	mov $r2 0x1200
    122 	iowr I[$r2] $r1
    123 
    124 	// enable i0 delivery
    125 	bset $flags ie0
    126 
    127 	// sleep forver, waking only for interrupts.
    128 	bset $flags $p0
    129 	spin:
    130 	sleep $p0
    131 	bra #spin
    132 
    133 // i0 handler
    134 ih:
    135 	// see which interrupts we got
    136 	iord $r1 I[$r0 + 0x200]
    137 
    138 	and $r2 $r1 0x8
    139 	cmpu b32 $r2 0
    140 	bra e #noctx
    141 
    142 		// context switch... prepare the regs for xfer
    143 		mov $r2 0x7700
    144 		mov $xtargets $r2
    145 		mov $xdbase $r0
    146 		// 128-byte context.
    147 		mov $r2 0
    148 		sethi $r2 0x50000
    149 
    150 		// read current channel
    151 		mov $r3 0x1400
    152 		iord $r4 I[$r3]
    153 		// if bit 30 set, it's active, so we have to unload it first.
    154 		shl b32 $r5 $r4 1
    155 		cmps b32 $r5 0
    156 		bra nc #ctxload
    157 
    158 			// unload the current channel - save the context
    159 			xdst $r0 $r2
    160 			xdwait
    161 			// and clear bit 30, then write back
    162 			bclr $r4 0x1e
    163 			iowr I[$r3] $r4
    164 			// tell PFIFO we unloaded
    165 			mov $r4 1
    166 			iowr I[$r3 + 0x200] $r4
    167 
    168 		bra #noctx
    169 
    170 		ctxload:
    171 			// no channel loaded - perhaps we're requested to load one
    172 			iord $r4 I[$r3 + 0x100]
    173 			shl b32 $r15 $r4 1
    174 			cmps b32 $r15 0
    175 			// if bit 30 of next channel not set, probably PFIFO is just
    176 			// killing a context. do a faux load, without the active bit.
    177 			bra nc #dummyload
    178 
    179 				// ok, do a real context load.
    180 				xdld $r0 $r2
    181 				xdwait
    182 				mov $r5 #ctx_dma
    183 				mov $r6 #dma_count - 1
    184 				ctxload_dma_loop:
    185 					ld b32 $r7 D[$r5 + $r6 * 4]
    186 					add b32 $r8 $r6 0x180
    187 					shl b32 $r8 8
    188 					iowr I[$r8] $r7
    189 					sub b32 $r6 1
    190 				bra nc #ctxload_dma_loop
    191 
    192 			dummyload:
    193 			// tell PFIFO we're done
    194 			mov $r5 2
    195 			iowr I[$r3 + 0x200] $r5
    196 
    197 	noctx:
    198 	and $r2 $r1 0x4
    199 	cmpu b32 $r2 0
    200 	bra e #nocmd
    201 
    202 		// incoming fifo command.
    203 		mov $r3 0x1900
    204 		iord $r2 I[$r3 + 0x100]
    205 		iord $r3 I[$r3]
    206 		// extract the method
    207 		and $r4 $r2 0x7ff
    208 		// shift the addr to proper position if we need to interrupt later
    209 		shl b32 $r2 0x10
    210 
    211 		// mthd 0 and 0x100 [NAME, NOP]: ignore
    212 		and $r5 $r4 0x7bf
    213 		cmpu b32 $r5 0
    214 		bra e #cmddone
    215 
    216 		mov $r5 #engine_cmd_dtable - 0xc0 * 8
    217 		mov $r6 #engine_cmd_max
    218 		cmpu b32 $r4 0xc0
    219 		bra nc #dtable_cmd
    220 		mov $r5 #common_cmd_dtable - 0x80 * 8
    221 		mov $r6 #common_cmd_max
    222 		cmpu b32 $r4 0x80
    223 		bra nc #dtable_cmd
    224 		cmpu b32 $r4 0x60
    225 		bra nc #dma_cmd
    226 		cmpu b32 $r4 0x50
    227 		bra ne #illegal_mthd
    228 
    229 			// mthd 0x140: PM_TRIGGER
    230 			mov $r2 0x2200
    231 			clear b32 $r3
    232 			sethi $r3 0x20000
    233 			iowr I[$r2] $r3
    234 			bra #cmddone
    235 
    236 		dma_cmd:
    237 			// mthd 0x180...: DMA_*
    238 			cmpu b32 $r4 0x60+#dma_count
    239 			bra nc #illegal_mthd
    240 			shl b32 $r5 $r4 2
    241 			add b32 $r5 ((#ctx_dma - 0x60 * 4) & 0xffff)
    242 			bset $r3 0x1e
    243 			st b32 D[$r5] $r3
    244 			add b32 $r4 0x180 - 0x60
    245 			shl b32 $r4 8
    246 			iowr I[$r4] $r3
    247 			bra #cmddone
    248 
    249 		dtable_cmd:
    250 			cmpu b32 $r4 $r6
    251 			bra nc #illegal_mthd
    252 			shl b32 $r4 3
    253 			add b32 $r4 $r5
    254 			ld b32 $r5 D[$r4 + 4]
    255 			and $r5 $r3
    256 			cmpu b32 $r5 0
    257 			bra ne #invalid_bitfield
    258 			ld b16 $r5 D[$r4]
    259 			ld b16 $r6 D[$r4 + 2]
    260 			cmpu b32 $r6 2
    261 			bra e #cmd_setctx
    262 			ld b32 $r7 D[$r0 + #ctx_cond_off]
    263 			and $r6 $r7
    264 			cmpu b32 $r6 1
    265 			bra e #cmddone
    266 			call $r5
    267 			bra $p1 #dispatch_error
    268 			bra #cmddone
    269 
    270 		cmd_setctx:
    271 			st b32 D[$r5] $r3
    272 			bra #cmddone
    273 
    274 
    275 		invalid_bitfield:
    276 			or $r2 1
    277 		dispatch_error:
    278 		illegal_mthd:
    279 			mov $r4 0x1000
    280 			iowr I[$r4] $r2
    281 			iowr I[$r4 + 0x100] $r3
    282 			mov $r4 0x40
    283 			iowr I[$r0] $r4
    284 
    285 			im_loop:
    286 				iord $r4 I[$r0 + 0x200]
    287 				and $r4 0x40
    288 				cmpu b32 $r4 0
    289 			bra ne #im_loop
    290 
    291 		cmddone:
    292 		// remove the command from FIFO
    293 		mov $r3 0x1d00
    294 		mov $r4 1
    295 		iowr I[$r3] $r4
    296 
    297 	nocmd:
    298 	// ack the processed interrupts
    299 	and $r1 $r1 0xc
    300 	iowr I[$r0 + 0x100] $r1
    301 iret
    302 
    303 cmd_query_get:
    304 	// if bit 0 of param set, trigger interrupt afterwards.
    305 	setp $p1 $r3
    306 	or $r2 3
    307 
    308 	// read PTIMER, beware of races...
    309 	mov $r4 0xb00
    310 	ptimer_retry:
    311 		iord $r6 I[$r4 + 0x100]
    312 		iord $r5 I[$r4]
    313 		iord $r7 I[$r4 + 0x100]
    314 		cmpu b32 $r6 $r7
    315 	bra ne #ptimer_retry
    316 
    317 	// prepare the query structure
    318 	ld b32 $r4 D[$r0 + #ctx_query_counter]
    319 	st b32 D[$r0 + #swap + 0x0] $r4
    320 	st b32 D[$r0 + #swap + 0x4] $r0
    321 	st b32 D[$r0 + #swap + 0x8] $r5
    322 	st b32 D[$r0 + #swap + 0xc] $r6
    323 
    324 	// will use target 0, DMA_QUERY.
    325 	mov $xtargets $r0
    326 
    327 	ld b32 $r4 D[$r0 + #ctx_query_address_high]
    328 	shl b32 $r4 0x18
    329 	mov $xdbase $r4
    330 
    331 	ld b32 $r4 D[$r0 + #ctx_query_address_low]
    332 	mov $r5 #swap
    333 	sethi $r5 0x20000
    334 	xdst $r4 $r5
    335 	xdwait
    336 
    337 	ret
    338 
    339 cmd_cond_mode:
    340 	// if >= 5, INVALID_ENUM
    341 	bset $flags $p1
    342 	or $r2 2
    343 	cmpu b32 $r3 5
    344 	bra nc #return
    345 
    346 	// otherwise, no error.
    347 	bclr $flags $p1
    348 
    349 	// if < 2, no QUERY object is involved
    350 	cmpu b32 $r3 2
    351 	bra nc #cmd_cond_mode_queryful
    352 
    353 		xor $r3 1
    354 		st b32 D[$r0 + #ctx_cond_off] $r3
    355 	return:
    356 		ret
    357 
    358 	cmd_cond_mode_queryful:
    359 	// ok, will need to pull a QUERY object, prepare offsets
    360 	ld b32 $r4 D[$r0 + #ctx_cond_address_high]
    361 	ld b32 $r5 D[$r0 + #ctx_cond_address_low]
    362 	and $r6 $r5 0xff
    363 	shr b32 $r5 8
    364 	shl b32 $r4 0x18
    365 	or $r4 $r5
    366 	mov $xdbase $r4
    367 	mov $xtargets $r0
    368 
    369 	// pull the first one
    370 	mov $r5 #swap
    371 	sethi $r5 0x20000
    372 	xdld $r6 $r5
    373 
    374 	// if == 2, only a single QUERY is involved...
    375 	cmpu b32 $r3 2
    376 	bra ne #cmd_cond_mode_double
    377 
    378 		xdwait
    379 		ld b32 $r4 D[$r0 + #swap + 4]
    380 		cmpu b32 $r4 0
    381 		xbit $r4 $flags z
    382 		st b32 D[$r0 + #ctx_cond_off] $r4
    383 		ret
    384 
    385 	// ok, we'll need to pull second one too
    386 	cmd_cond_mode_double:
    387 	add b32 $r6 0x10
    388 	add b32 $r5 0x10
    389 	xdld $r6 $r5
    390 	xdwait
    391 
    392 	// compare COUNTERs
    393 	ld b32 $r5 D[$r0 + #swap + 0x00]
    394 	ld b32 $r6 D[$r0 + #swap + 0x10]
    395 	cmpu b32 $r5 $r6
    396 	xbit $r4 $flags z
    397 
    398 	// compare RESen
    399 	ld b32 $r5 D[$r0 + #swap + 0x04]
    400 	ld b32 $r6 D[$r0 + #swap + 0x14]
    401 	cmpu b32 $r5 $r6
    402 	xbit $r5 $flags z
    403 	and $r4 $r5
    404 
    405 	// and negate or not, depending on mode
    406 	cmpu b32 $r3 3
    407 	xbit $r5 $flags z
    408 	xor $r4 $r5
    409 	st b32 D[$r0 + #ctx_cond_off] $r4
    410 	ret
    411 
    412 cmd_wrcache_flush:
    413 	bclr $flags $p1
    414 	mov $r2 0x2200
    415 	clear b32 $r3
    416 	sethi $r3 0x10000
    417 	iowr I[$r2] $r3
    418 	ret
    419 
    420 sec_cmd_mode:
    421 	// if >= 0xf, INVALID_ENUM
    422 	bset $flags $p1
    423 	or $r2 2
    424 	cmpu b32 $r3 0xf
    425 	bra nc #sec_cmd_mode_return
    426 
    427 		bclr $flags $p1
    428 		st b32 D[$r0 + #ctx_mode] $r3
    429 
    430 	sec_cmd_mode_return:
    431 	ret
    432 
    433 sec_cmd_length:
    434 	// nop if length == 0
    435 	cmpu b32 $r3 0
    436 	bra e #sec_cmd_mode_return
    437 
    438 	// init key, IV
    439 	cxset 3
    440 	mov $r4 #ctx_key
    441 	sethi $r4 0x70000
    442 	xdst $r0 $r4
    443 	mov $r4 #ctx_iv
    444 	sethi $r4 0x60000
    445 	xdst $r0 $r4
    446 	xdwait
    447 	ckeyreg $c7
    448 
    449 	// prepare the targets
    450 	mov $r4 0x2100
    451 	mov $xtargets $r4
    452 
    453 	// prepare src address
    454 	ld b32 $r4 D[$r0 + #ctx_src_address_high]
    455 	ld b32 $r5 D[$r0 + #ctx_src_address_low]
    456 	shr b32 $r8 $r5 8
    457 	shl b32 $r4 0x18
    458 	or $r4 $r8
    459 	and $r5 $r5 0xff
    460 
    461 	// prepare dst address
    462 	ld b32 $r6 D[$r0 + #ctx_dst_address_high]
    463 	ld b32 $r7 D[$r0 + #ctx_dst_address_low]
    464 	shr b32 $r8 $r7 8
    465 	shl b32 $r6 0x18
    466 	or $r6 $r8
    467 	and $r7 $r7 0xff
    468 
    469 	// find the proper prep & do functions
    470 	ld b32 $r8 D[$r0 + #ctx_mode]
    471 	shl b32 $r8 2
    472 
    473 	// run prep
    474 	ld b16 $r9 D[$r8 + #sec_dtable]
    475 	call $r9
    476 
    477 	// do it
    478 	ld b16 $r9 D[$r8 + #sec_dtable + 2]
    479 	call $r9
    480 	cxset 1
    481 	xdwait
    482 	cxset 0x61
    483 	xdwait
    484 	xdwait
    485 
    486 	// update src address
    487 	shr b32 $r8 $r4 0x18
    488 	shl b32 $r9 $r4 8
    489 	add b32 $r9 $r5
    490 	adc b32 $r8 0
    491 	st b32 D[$r0 + #ctx_src_address_high] $r8
    492 	st b32 D[$r0 + #ctx_src_address_low] $r9
    493 
    494 	// update dst address
    495 	shr b32 $r8 $r6 0x18
    496 	shl b32 $r9 $r6 8
    497 	add b32 $r9 $r7
    498 	adc b32 $r8 0
    499 	st b32 D[$r0 + #ctx_dst_address_high] $r8
    500 	st b32 D[$r0 + #ctx_dst_address_low] $r9
    501 
    502 	// pull updated IV
    503 	cxset 2
    504 	mov $r4 #ctx_iv
    505 	sethi $r4 0x60000
    506 	xdld $r0 $r4
    507 	xdwait
    508 
    509 	ret
    510 
    511 
    512 sec_copy_prep:
    513 	cs0begin 2
    514 		cxsin $c0
    515 		cxsout $c0
    516 	ret
    517 
    518 sec_store_prep:
    519 	cs0begin 1
    520 		cxsout $c6
    521 	ret
    522 
    523 sec_ecb_e_prep:
    524 	cs0begin 3
    525 		cxsin $c0
    526 		cenc $c0 $c0
    527 		cxsout $c0
    528 	ret
    529 
    530 sec_ecb_d_prep:
    531 	ckexp $c7 $c7
    532 	cs0begin 3
    533 		cxsin $c0
    534 		cdec $c0 $c0
    535 		cxsout $c0
    536 	ret
    537 
    538 sec_cbc_e_prep:
    539 	cs0begin 4
    540 		cxsin $c0
    541 		cxor $c6 $c0
    542 		cenc $c6 $c6
    543 		cxsout $c6
    544 	ret
    545 
    546 sec_cbc_d_prep:
    547 	ckexp $c7 $c7
    548 	cs0begin 5
    549 		cmov $c2 $c6
    550 		cxsin $c6
    551 		cdec $c0 $c6
    552 		cxor $c0 $c2
    553 		cxsout $c0
    554 	ret
    555 
    556 sec_pcbc_e_prep:
    557 	cs0begin 5
    558 		cxsin $c0
    559 		cxor $c6 $c0
    560 		cenc $c6 $c6
    561 		cxsout $c6
    562 		cxor $c6 $c0
    563 	ret
    564 
    565 sec_pcbc_d_prep:
    566 	ckexp $c7 $c7
    567 	cs0begin 5
    568 		cxsin $c0
    569 		cdec $c1 $c0
    570 		cxor $c6 $c1
    571 		cxsout $c6
    572 		cxor $c6 $c0
    573 	ret
    574 
    575 sec_cfb_e_prep:
    576 	cs0begin 4
    577 		cenc $c6 $c6
    578 		cxsin $c0
    579 		cxor $c6 $c0
    580 		cxsout $c6
    581 	ret
    582 
    583 sec_cfb_d_prep:
    584 	cs0begin 4
    585 		cenc $c0 $c6
    586 		cxsin $c6
    587 		cxor $c0 $c6
    588 		cxsout $c0
    589 	ret
    590 
    591 sec_ofb_prep:
    592 	cs0begin 4
    593 		cenc $c6 $c6
    594 		cxsin $c0
    595 		cxor $c0 $c6
    596 		cxsout $c0
    597 	ret
    598 
    599 sec_ctr_prep:
    600 	cs0begin 5
    601 		cenc $c1 $c6
    602 		cadd $c6 1
    603 		cxsin $c0
    604 		cxor $c0 $c1
    605 		cxsout $c0
    606 	ret
    607 
    608 sec_cbc_mac_prep:
    609 	cs0begin 3
    610 		cxsin $c0
    611 		cxor $c6 $c0
    612 		cenc $c6 $c6
    613 	ret
    614 
    615 sec_cmac_finish_complete_prep:
    616 	cs0begin 7
    617 		cxsin $c0
    618 		cxor $c6 $c0
    619 		cxor $c0 $c0
    620 		cenc $c0 $c0
    621 		cprecmac $c0 $c0
    622 		cxor $c6 $c0
    623 		cenc $c6 $c6
    624 	ret
    625 
    626 sec_cmac_finish_partial_prep:
    627 	cs0begin 8
    628 		cxsin $c0
    629 		cxor $c6 $c0
    630 		cxor $c0 $c0
    631 		cenc $c0 $c0
    632 		cprecmac $c0 $c0
    633 		cprecmac $c0 $c0
    634 		cxor $c6 $c0
    635 		cenc $c6 $c6
    636 	ret
    637 
    638 // TODO
    639 sec_do_in:
    640 	add b32 $r3 $r5
    641 	mov $xdbase $r4
    642 	mov $r9 #swap
    643 	sethi $r9 0x20000
    644 	sec_do_in_loop:
    645 		xdld $r5 $r9
    646 		xdwait
    647 		cxset 0x22
    648 		xdst $r0 $r9
    649 		cs0exec 1
    650 		xdwait
    651 		add b32 $r5 0x10
    652 		cmpu b32 $r5 $r3
    653 	bra ne #sec_do_in_loop
    654 	cxset 1
    655 	xdwait
    656 	ret
    657 
    658 sec_do_out:
    659 	add b32 $r3 $r7
    660 	mov $xdbase $r6
    661 	mov $r9 #swap
    662 	sethi $r9 0x20000
    663 	sec_do_out_loop:
    664 		cs0exec 1
    665 		cxset 0x61
    666 		xdld $r7 $r9
    667 		xdst $r7 $r9
    668 		cxset 1
    669 		xdwait
    670 		add b32 $r7 0x10
    671 		cmpu b32 $r7 $r3
    672 	bra ne #sec_do_out_loop
    673 	ret
    674 
    675 sec_do_inout:
    676 	add b32 $r3 $r5
    677 	mov $r9 #swap
    678 	sethi $r9 0x20000
    679 	sec_do_inout_loop:
    680 		mov $xdbase $r4
    681 		xdld $r5 $r9
    682 		xdwait
    683 		cxset 0x21
    684 		xdst $r0 $r9
    685 		cs0exec 1
    686 		cxset 0x61
    687 		mov $xdbase $r6
    688 		xdld $r7 $r9
    689 		xdst $r7 $r9
    690 		cxset 1
    691 		xdwait
    692 		add b32 $r5 0x10
    693 		add b32 $r7 0x10
    694 		cmpu b32 $r5 $r3
    695 	bra ne #sec_do_inout_loop
    696 	ret
    697 
    698 .align 0x100
    699