cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

bugfix.S (14062B)


      1|
      2|	bugfix.sa 3.2 1/31/91
      3|
      4|
      5|	This file contains workarounds for bugs in the 040
      6|	relating to the Floating-Point Software Package (FPSP)
      7|
      8|	Fixes for bugs: 1238
      9|
     10|	Bug: 1238
     11|
     12|
     13|    /* The following dirty_bit clear should be left in
     14|     * the handler permanently to improve throughput.
     15|     * The dirty_bits are located at bits [23:16] in
     16|     * longword $08 in the busy frame $4x60.  Bit 16
     17|     * corresponds to FP0, bit 17 corresponds to FP1,
     18|     * and so on.
     19|     */
     20|    if  (E3_exception_just_serviced)   {
     21|         dirty_bit[cmdreg3b[9:7]] = 0;
     22|         }
     23|
     24|    if  (fsave_format_version != $40)  {goto NOFIX}
     25|
     26|    if !(E3_exception_just_serviced)   {goto NOFIX}
     27|    if  (cupc == 0000000)              {goto NOFIX}
     28|    if  ((cmdreg1b[15:13] != 000) &&
     29|         (cmdreg1b[15:10] != 010001))  {goto NOFIX}
     30|    if (((cmdreg1b[15:13] != 000) || ((cmdreg1b[12:10] != cmdreg2b[9:7]) &&
     31|				      (cmdreg1b[12:10] != cmdreg3b[9:7]))  ) &&
     32|	 ((cmdreg1b[ 9: 7] != cmdreg2b[9:7]) &&
     33|	  (cmdreg1b[ 9: 7] != cmdreg3b[9:7])) )  {goto NOFIX}
     34|
     35|    /* Note: for 6d43b or 8d43b, you may want to add the following code
     36|     * to get better coverage.  (If you do not insert this code, the part
     37|     * won't lock up; it will simply get the wrong answer.)
     38|     * Do NOT insert this code for 10d43b or later parts.
     39|     *
     40|     *  if (fpiarcu == integer stack return address) {
     41|     *       cupc = 0000000;
     42|     *       goto NOFIX;
     43|     *       }
     44|     */
     45|
     46|    if (cmdreg1b[15:13] != 000)   {goto FIX_OPCLASS2}
     47|    FIX_OPCLASS0:
     48|    if (((cmdreg1b[12:10] == cmdreg2b[9:7]) ||
     49|	 (cmdreg1b[ 9: 7] == cmdreg2b[9:7])) &&
     50|	(cmdreg1b[12:10] != cmdreg3b[9:7]) &&
     51|	(cmdreg1b[ 9: 7] != cmdreg3b[9:7]))  {  /* xu conflict only */
     52|	/* We execute the following code if there is an
     53|	   xu conflict and NOT an nu conflict */
     54|
     55|	/* first save some values on the fsave frame */
     56|	stag_temp     = STAG[fsave_frame];
     57|	cmdreg1b_temp = CMDREG1B[fsave_frame];
     58|	dtag_temp     = DTAG[fsave_frame];
     59|	ete15_temp    = ETE15[fsave_frame];
     60|
     61|	CUPC[fsave_frame] = 0000000;
     62|	FRESTORE
     63|	FSAVE
     64|
     65|	/* If the xu instruction is exceptional, we punt.
     66|	 * Otherwise, we would have to include OVFL/UNFL handler
     67|	 * code here to get the correct answer.
     68|	 */
     69|	if (fsave_frame_format == $4060) {goto KILL_PROCESS}
     70|
     71|	fsave_frame = /* build a long frame of all zeros */
     72|	fsave_frame_format = $4060;  /* label it as long frame */
     73|
     74|	/* load it with the temps we saved */
     75|	STAG[fsave_frame]     =  stag_temp;
     76|	CMDREG1B[fsave_frame] =  cmdreg1b_temp;
     77|	DTAG[fsave_frame]     =  dtag_temp;
     78|	ETE15[fsave_frame]    =  ete15_temp;
     79|
     80|	/* Make sure that the cmdreg3b dest reg is not going to
     81|	 * be destroyed by a FMOVEM at the end of all this code.
     82|	 * If it is, you should move the current value of the reg
     83|	 * onto the stack so that the reg will loaded with that value.
     84|	 */
     85|
     86|	/* All done.  Proceed with the code below */
     87|    }
     88|
     89|    etemp  = FP_reg_[cmdreg1b[12:10]];
     90|    ete15  = ~ete14;
     91|    cmdreg1b[15:10] = 010010;
     92|    clear(bug_flag_procIDxxxx);
     93|    FRESTORE and return;
     94|
     95|
     96|    FIX_OPCLASS2:
     97|    if ((cmdreg1b[9:7] == cmdreg2b[9:7]) &&
     98|	(cmdreg1b[9:7] != cmdreg3b[9:7]))  {  /* xu conflict only */
     99|	/* We execute the following code if there is an
    100|	   xu conflict and NOT an nu conflict */
    101|
    102|	/* first save some values on the fsave frame */
    103|	stag_temp     = STAG[fsave_frame];
    104|	cmdreg1b_temp = CMDREG1B[fsave_frame];
    105|	dtag_temp     = DTAG[fsave_frame];
    106|	ete15_temp    = ETE15[fsave_frame];
    107|	etemp_temp    = ETEMP[fsave_frame];
    108|
    109|	CUPC[fsave_frame] = 0000000;
    110|	FRESTORE
    111|	FSAVE
    112|
    113|
    114|	/* If the xu instruction is exceptional, we punt.
    115|	 * Otherwise, we would have to include OVFL/UNFL handler
    116|	 * code here to get the correct answer.
    117|	 */
    118|	if (fsave_frame_format == $4060) {goto KILL_PROCESS}
    119|
    120|	fsave_frame = /* build a long frame of all zeros */
    121|	fsave_frame_format = $4060;  /* label it as long frame */
    122|
    123|	/* load it with the temps we saved */
    124|	STAG[fsave_frame]     =  stag_temp;
    125|	CMDREG1B[fsave_frame] =  cmdreg1b_temp;
    126|	DTAG[fsave_frame]     =  dtag_temp;
    127|	ETE15[fsave_frame]    =  ete15_temp;
    128|	ETEMP[fsave_frame]    =  etemp_temp;
    129|
    130|	/* Make sure that the cmdreg3b dest reg is not going to
    131|	 * be destroyed by a FMOVEM at the end of all this code.
    132|	 * If it is, you should move the current value of the reg
    133|	 * onto the stack so that the reg will loaded with that value.
    134|	 */
    135|
    136|	/* All done.  Proceed with the code below */
    137|    }
    138|
    139|    if (etemp_exponent == min_sgl)   etemp_exponent = min_dbl;
    140|    if (etemp_exponent == max_sgl)   etemp_exponent = max_dbl;
    141|    cmdreg1b[15:10] = 010101;
    142|    clear(bug_flag_procIDxxxx);
    143|    FRESTORE and return;
    144|
    145|
    146|    NOFIX:
    147|    clear(bug_flag_procIDxxxx);
    148|    FRESTORE and return;
    149|
    150
    151
    152|		Copyright (C) Motorola, Inc. 1990
    153|			All Rights Reserved
    154|
    155|       For details on the license for this file, please see the
    156|       file, README, in this same directory.
    157
    158|BUGFIX    idnt    2,1 | Motorola 040 Floating Point Software Package
    159
    160	|section	8
    161
    162#include "fpsp.h"
    163
    164	|xref	fpsp_fmt_error
    165
    166	.global	b1238_fix
    167b1238_fix:
    168|
    169| This code is entered only on completion of the handling of an
    170| nu-generated ovfl, unfl, or inex exception.  If the version
    171| number of the fsave is not $40, this handler is not necessary.
    172| Simply branch to fix_done and exit normally.
    173|
    174	cmpib	#VER_40,4(%a7)
    175	bne	fix_done
    176|
    177| Test for cu_savepc equal to zero.  If not, this is not a bug
    178| #1238 case.
    179|
    180	moveb	CU_SAVEPC(%a6),%d0
    181	andib	#0xFE,%d0
    182	beq	fix_done	|if zero, this is not bug #1238
    183
    184|
    185| Test the register conflict aspect.  If opclass0, check for
    186| cu src equal to xu dest or equal to nu dest.  If so, go to
    187| op0.  Else, or if opclass2, check for cu dest equal to
    188| xu dest or equal to nu dest.  If so, go to tst_opcl.  Else,
    189| exit, it is not the bug case.
    190|
    191| Check for opclass 0.  If not, go and check for opclass 2 and sgl.
    192|
    193	movew	CMDREG1B(%a6),%d0
    194	andiw	#0xE000,%d0		|strip all but opclass
    195	bne	op2sgl			|not opclass 0, check op2
    196|
    197| Check for cu and nu register conflict.  If one exists, this takes
    198| priority over a cu and xu conflict.
    199|
    200	bfextu	CMDREG1B(%a6){#3:#3},%d0	|get 1st src
    201	bfextu	CMDREG3B(%a6){#6:#3},%d1	|get 3rd dest
    202	cmpb	%d0,%d1
    203	beqs	op0			|if equal, continue bugfix
    204|
    205| Check for cu dest equal to nu dest.  If so, go and fix the
    206| bug condition.  Otherwise, exit.
    207|
    208	bfextu	CMDREG1B(%a6){#6:#3},%d0	|get 1st dest
    209	cmpb	%d0,%d1			|cmp 1st dest with 3rd dest
    210	beqs	op0			|if equal, continue bugfix
    211|
    212| Check for cu and xu register conflict.
    213|
    214	bfextu	CMDREG2B(%a6){#6:#3},%d1	|get 2nd dest
    215	cmpb	%d0,%d1			|cmp 1st dest with 2nd dest
    216	beqs	op0_xu			|if equal, continue bugfix
    217	bfextu	CMDREG1B(%a6){#3:#3},%d0	|get 1st src
    218	cmpb	%d0,%d1			|cmp 1st src with 2nd dest
    219	beq	op0_xu
    220	bne	fix_done		|if the reg checks fail, exit
    221|
    222| We have the opclass 0 situation.
    223|
    224op0:
    225	bfextu	CMDREG1B(%a6){#3:#3},%d0	|get source register no
    226	movel	#7,%d1
    227	subl	%d0,%d1
    228	clrl	%d0
    229	bsetl	%d1,%d0
    230	fmovemx %d0,ETEMP(%a6)		|load source to ETEMP
    231
    232	moveb	#0x12,%d0
    233	bfins	%d0,CMDREG1B(%a6){#0:#6}	|opclass 2, extended
    234|
    235|	Set ETEMP exponent bit 15 as the opposite of ete14
    236|
    237	btst	#6,ETEMP_EX(%a6)		|check etemp exponent bit 14
    238	beq	setete15
    239	bclr	#etemp15_bit,STAG(%a6)
    240	bra	finish
    241setete15:
    242	bset	#etemp15_bit,STAG(%a6)
    243	bra	finish
    244
    245|
    246| We have the case in which a conflict exists between the cu src or
    247| dest and the dest of the xu.  We must clear the instruction in
    248| the cu and restore the state, allowing the instruction in the
    249| xu to complete.  Remember, the instruction in the nu
    250| was exceptional, and was completed by the appropriate handler.
    251| If the result of the xu instruction is not exceptional, we can
    252| restore the instruction from the cu to the frame and continue
    253| processing the original exception.  If the result is also
    254| exceptional, we choose to kill the process.
    255|
    256|	Items saved from the stack:
    257|
    258|		$3c stag     - L_SCR1
    259|		$40 cmdreg1b - L_SCR2
    260|		$44 dtag     - L_SCR3
    261|
    262| The cu savepc is set to zero, and the frame is restored to the
    263| fpu.
    264|
    265op0_xu:
    266	movel	STAG(%a6),L_SCR1(%a6)
    267	movel	CMDREG1B(%a6),L_SCR2(%a6)
    268	movel	DTAG(%a6),L_SCR3(%a6)
    269	andil	#0xe0000000,L_SCR3(%a6)
    270	moveb	#0,CU_SAVEPC(%a6)
    271	movel	(%a7)+,%d1		|save return address from bsr
    272	frestore (%a7)+
    273	fsave	-(%a7)
    274|
    275| Check if the instruction which just completed was exceptional.
    276|
    277	cmpw	#0x4060,(%a7)
    278	beq	op0_xb
    279|
    280| It is necessary to isolate the result of the instruction in the
    281| xu if it is to fp0 - fp3 and write that value to the USER_FPn
    282| locations on the stack.  The correct destination register is in
    283| cmdreg2b.
    284|
    285	bfextu	CMDREG2B(%a6){#6:#3},%d0	|get dest register no
    286	cmpil	#3,%d0
    287	bgts	op0_xi
    288	beqs	op0_fp3
    289	cmpil	#1,%d0
    290	blts	op0_fp0
    291	beqs	op0_fp1
    292op0_fp2:
    293	fmovemx %fp2-%fp2,USER_FP2(%a6)
    294	bras	op0_xi
    295op0_fp1:
    296	fmovemx %fp1-%fp1,USER_FP1(%a6)
    297	bras	op0_xi
    298op0_fp0:
    299	fmovemx %fp0-%fp0,USER_FP0(%a6)
    300	bras	op0_xi
    301op0_fp3:
    302	fmovemx %fp3-%fp3,USER_FP3(%a6)
    303|
    304| The frame returned is idle.  We must build a busy frame to hold
    305| the cu state information and setup etemp.
    306|
    307op0_xi:
    308	movel	#22,%d0		|clear 23 lwords
    309	clrl	(%a7)
    310op0_loop:
    311	clrl	-(%a7)
    312	dbf	%d0,op0_loop
    313	movel	#0x40600000,-(%a7)
    314	movel	L_SCR1(%a6),STAG(%a6)
    315	movel	L_SCR2(%a6),CMDREG1B(%a6)
    316	movel	L_SCR3(%a6),DTAG(%a6)
    317	moveb	#0x6,CU_SAVEPC(%a6)
    318	movel	%d1,-(%a7)		|return bsr return address
    319	bfextu	CMDREG1B(%a6){#3:#3},%d0	|get source register no
    320	movel	#7,%d1
    321	subl	%d0,%d1
    322	clrl	%d0
    323	bsetl	%d1,%d0
    324	fmovemx %d0,ETEMP(%a6)		|load source to ETEMP
    325
    326	moveb	#0x12,%d0
    327	bfins	%d0,CMDREG1B(%a6){#0:#6}	|opclass 2, extended
    328|
    329|	Set ETEMP exponent bit 15 as the opposite of ete14
    330|
    331	btst	#6,ETEMP_EX(%a6)		|check etemp exponent bit 14
    332	beq	op0_sete15
    333	bclr	#etemp15_bit,STAG(%a6)
    334	bra	finish
    335op0_sete15:
    336	bset	#etemp15_bit,STAG(%a6)
    337	bra	finish
    338
    339|
    340| The frame returned is busy.  It is not possible to reconstruct
    341| the code sequence to allow completion.  We will jump to
    342| fpsp_fmt_error and allow the kernel to kill the process.
    343|
    344op0_xb:
    345	jmp	fpsp_fmt_error
    346
    347|
    348| Check for opclass 2 and single size.  If not both, exit.
    349|
    350op2sgl:
    351	movew	CMDREG1B(%a6),%d0
    352	andiw	#0xFC00,%d0		|strip all but opclass and size
    353	cmpiw	#0x4400,%d0		|test for opclass 2 and size=sgl
    354	bne	fix_done		|if not, it is not bug 1238
    355|
    356| Check for cu dest equal to nu dest or equal to xu dest, with
    357| a cu and nu conflict taking priority an nu conflict.  If either,
    358| go and fix the bug condition.  Otherwise, exit.
    359|
    360	bfextu	CMDREG1B(%a6){#6:#3},%d0	|get 1st dest
    361	bfextu	CMDREG3B(%a6){#6:#3},%d1	|get 3rd dest
    362	cmpb	%d0,%d1			|cmp 1st dest with 3rd dest
    363	beq	op2_com			|if equal, continue bugfix
    364	bfextu	CMDREG2B(%a6){#6:#3},%d1	|get 2nd dest
    365	cmpb	%d0,%d1			|cmp 1st dest with 2nd dest
    366	bne	fix_done		|if the reg checks fail, exit
    367|
    368| We have the case in which a conflict exists between the cu src or
    369| dest and the dest of the xu.  We must clear the instruction in
    370| the cu and restore the state, allowing the instruction in the
    371| xu to complete.  Remember, the instruction in the nu
    372| was exceptional, and was completed by the appropriate handler.
    373| If the result of the xu instruction is not exceptional, we can
    374| restore the instruction from the cu to the frame and continue
    375| processing the original exception.  If the result is also
    376| exceptional, we choose to kill the process.
    377|
    378|	Items saved from the stack:
    379|
    380|		$3c stag     - L_SCR1
    381|		$40 cmdreg1b - L_SCR2
    382|		$44 dtag     - L_SCR3
    383|		etemp        - FP_SCR2
    384|
    385| The cu savepc is set to zero, and the frame is restored to the
    386| fpu.
    387|
    388op2_xu:
    389	movel	STAG(%a6),L_SCR1(%a6)
    390	movel	CMDREG1B(%a6),L_SCR2(%a6)
    391	movel	DTAG(%a6),L_SCR3(%a6)
    392	andil	#0xe0000000,L_SCR3(%a6)
    393	moveb	#0,CU_SAVEPC(%a6)
    394	movel	ETEMP(%a6),FP_SCR2(%a6)
    395	movel	ETEMP_HI(%a6),FP_SCR2+4(%a6)
    396	movel	ETEMP_LO(%a6),FP_SCR2+8(%a6)
    397	movel	(%a7)+,%d1		|save return address from bsr
    398	frestore (%a7)+
    399	fsave	-(%a7)
    400|
    401| Check if the instruction which just completed was exceptional.
    402|
    403	cmpw	#0x4060,(%a7)
    404	beq	op2_xb
    405|
    406| It is necessary to isolate the result of the instruction in the
    407| xu if it is to fp0 - fp3 and write that value to the USER_FPn
    408| locations on the stack.  The correct destination register is in
    409| cmdreg2b.
    410|
    411	bfextu	CMDREG2B(%a6){#6:#3},%d0	|get dest register no
    412	cmpil	#3,%d0
    413	bgts	op2_xi
    414	beqs	op2_fp3
    415	cmpil	#1,%d0
    416	blts	op2_fp0
    417	beqs	op2_fp1
    418op2_fp2:
    419	fmovemx %fp2-%fp2,USER_FP2(%a6)
    420	bras	op2_xi
    421op2_fp1:
    422	fmovemx %fp1-%fp1,USER_FP1(%a6)
    423	bras	op2_xi
    424op2_fp0:
    425	fmovemx %fp0-%fp0,USER_FP0(%a6)
    426	bras	op2_xi
    427op2_fp3:
    428	fmovemx %fp3-%fp3,USER_FP3(%a6)
    429|
    430| The frame returned is idle.  We must build a busy frame to hold
    431| the cu state information and fix up etemp.
    432|
    433op2_xi:
    434	movel	#22,%d0		|clear 23 lwords
    435	clrl	(%a7)
    436op2_loop:
    437	clrl	-(%a7)
    438	dbf	%d0,op2_loop
    439	movel	#0x40600000,-(%a7)
    440	movel	L_SCR1(%a6),STAG(%a6)
    441	movel	L_SCR2(%a6),CMDREG1B(%a6)
    442	movel	L_SCR3(%a6),DTAG(%a6)
    443	moveb	#0x6,CU_SAVEPC(%a6)
    444	movel	FP_SCR2(%a6),ETEMP(%a6)
    445	movel	FP_SCR2+4(%a6),ETEMP_HI(%a6)
    446	movel	FP_SCR2+8(%a6),ETEMP_LO(%a6)
    447	movel	%d1,-(%a7)
    448	bra	op2_com
    449
    450|
    451| We have the opclass 2 single source situation.
    452|
    453op2_com:
    454	moveb	#0x15,%d0
    455	bfins	%d0,CMDREG1B(%a6){#0:#6}	|opclass 2, double
    456
    457	cmpw	#0x407F,ETEMP_EX(%a6)	|single +max
    458	bnes	case2
    459	movew	#0x43FF,ETEMP_EX(%a6)	|to double +max
    460	bra	finish
    461case2:
    462	cmpw	#0xC07F,ETEMP_EX(%a6)	|single -max
    463	bnes	case3
    464	movew	#0xC3FF,ETEMP_EX(%a6)	|to double -max
    465	bra	finish
    466case3:
    467	cmpw	#0x3F80,ETEMP_EX(%a6)	|single +min
    468	bnes	case4
    469	movew	#0x3C00,ETEMP_EX(%a6)	|to double +min
    470	bra	finish
    471case4:
    472	cmpw	#0xBF80,ETEMP_EX(%a6)	|single -min
    473	bne	fix_done
    474	movew	#0xBC00,ETEMP_EX(%a6)	|to double -min
    475	bra	finish
    476|
    477| The frame returned is busy.  It is not possible to reconstruct
    478| the code sequence to allow completion.  fpsp_fmt_error causes
    479| an fline illegal instruction to be executed.
    480|
    481| You should replace the jump to fpsp_fmt_error with a jump
    482| to the entry point used to kill a process.
    483|
    484op2_xb:
    485	jmp	fpsp_fmt_error
    486
    487|
    488| Enter here if the case is not of the situations affected by
    489| bug #1238, or if the fix is completed, and exit.
    490|
    491finish:
    492fix_done:
    493	rts
    494
    495	|end