summaryrefslogblamecommitdiffstats
path: root/private/ntos/nthals/halsnip/mips/cacherr.s
blob: c0ea2990839bdecdb4314a4d4540fcc0c35a7d76 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645




































































































































































































































































































































































































































































































































































































































































                                                                                                                                             
//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/cacherr.s,v 1.2 1996/02/23 17:55:12 pierre Exp $")
//      TITLE("Cache Error Handling")
//++
//
// Copyright (c) 1993  Microsoft Corporation
//
// Module Name:
//
//    cacherr.s
//
// Abstract:
//
//    This module implements cache error handling. It is entered in KSEG1
//    directly from the cache error vector wiht ERL set in the processor
//    state.
//
//    No correction is done. We only try to get the physical address
//    that causes this exception
//
// Environment:
//
//    Kernel mode only.
//
// Revision History:
//
//--

#include "halmips.h"

    .globl  HalpCacheErrFirst       
    .globl  HalpErrCacheMsg       // cache error
    .globl  HalpParityErrMsg      // parity error
    .globl  HalpAddrErrMsg        // no addr found
    .globl  HalpComputeNum        // compute memory sip number
    .globl  HalpKeBugCheck0
    .globl  HalpKeBugCheck1
    .globl  HalpKeBugCheck2
    .globl  HalpKeBugCheck3
    .globl  HalpKeBugCheck4
    .globl  HalpBugCheckNumber

#define  CACHE_ERR_ER      0x80000000
#define  CACHE_ERR_EC      0x40000000
#define  CACHE_ERR_ED      0x20000000
#define  CACHE_ERR_ET      0x10000000
#define  CACHE_ERR_ES      0x08000000
#define  CACHE_ERR_EE      0x04000000
#define  CACHE_ERR_EB      0x02000000
#define  CACHE_ERR_EI      0x01000000
#define  CACHE_ERR_SIDX    0x003ffff8
#define  CACHE_ERR_PIDX    0x00000007
#define  PIDX_PD_MASK      0x00001000  // cache size 8k 

#define HALP_OPCODE_MASK     0xfc000000
#define HALP_OPCODE_SHIFT    24        // because we test opcode number on 8 bits
#define HALP_RT1_REG         0x001f0000
#define HALP_RT1_SHIFT       16
#define HALP_RT2_REG         0x03e00000
#define HALP_RT2_SHIFT       21

#define HALP_SWC1   0xe4 //
#define HALP_SDC1   0xf4 //
#define HALP_LWC1   0xc4 //
#define HALP_LDC1   0xd4 //
#define HALP_LB     0x80 //
#define HALP_LH     0x82 //
#define HALP_LW     0x8c //
#define HALP_LD     0xdc //
#define HALP_LBU    0x90 //
#define HALP_LHU    0x94 //
#define HALP_SB     0xa0 //
#define HALP_SH     0xa4 //
#define HALP_SW     0xac //
#define HALP_SD     0xfc //
#define HALP_LWL    0x88 //
#define HALP_LWR    0x98 //
#define HALP_LDL    0x68 //
#define HALP_LDR    0x6c //
#define HALP_LWU    0x9c //
#define HALP_SDL    0xb0 //
#define HALP_SDR    0xb4 //
#define HALP_LL     0xc0 //
#define HALP_LLD    0xd0 //
#define HALP_SC     0xe0 //
#define HALP_SCD    0xf0 //
//
// Define local save area for register state.
//

        .data
SavedAt:.space  4                       // saved  registers
SavedV0:.space  4                       //
SavedV1:.space  4                       //
SavedA0:.space  4                       //
SavedA1:.space  4                       //
SavedA2:.space  4                       //
SavedA3:.space  4                       //
SavedT0:.space  4                       //
SavedT1:.space  4                       //
SavedT2:.space  4                       //
SavedT3:.space  4                       //
SavedT4:.space  4                       //
SavedT5:.space  4                       //
SavedT6:.space  4                       //
SavedT7:.space  4                       //
SavedS0:.space  4                       //
SavedS1:.space  4                       //
SavedS2:.space  4                       //
SavedS3:.space  4                       //
SavedS4:.space  4                       //
SavedS5:.space  4                       //
SavedS6:.space  4                       //
SavedS7:.space  4                       //
SavedT8:.space  4                       //
SavedT9:.space  4                       //
SavedK0:.space  4                       //
SavedK1:.space  4                       //
SavedGP:.space  4                       //
SavedSP:.space  4                       //
SavedS8:.space  4                       //
SavedRA:.space  4                       //
SavedErrorEpc:.space  4                 //
SavedCacheError:.space 4                //

//++
//
// VOID
// HalpCacheErrorRoutine (
//    VOID
//    )
//
// Routine Description:
//
//    This function is entered from the cache error vector executing
//    in KSEG1 and with finished with a fatal system error :
//
//    Msg Hal : CACHE ERROR - PARITY ERROR - ADDR IN ERROR NOT FOUND
//    KeBugCheckEx :
//          a0 = 0x80 Hardware malfunction
//          a1 = 18 (parity pb) or 19 (cache error)
//          a2 = physical address in error (or 0x00)
//          a3 = sim number   
//          a4 = cacheerror register contents
//    
//
//    N.B. No state has been saved when this routine is entered.
//
// Arguments:
//
//    None.
//
// Return Value:
//
//    None.
//
//--
	.struct 0

        .struct 0
CiArgs0:.space  4                       // saved arguments
CiArgs1:.space  4                       // saved arguments
CiArgs2:.space  4                       // saved arguments
CiRa:   .space  4                       // saved return address
CiFrameLength:                          //

        NESTED_ENTRY(HalpCacheErrorRoutine, CiFrameLength, zero)


        subu    sp,sp,CiFrameLength     // allocate stack frame
        sw      ra,CiRa(sp)             // save return address

        PROLOGUE_END

//
// Save  volatile registers needed to fix cache error.
//

        .set    noreorder

//
// Protection to avoid to execute twice in multipro 
// (modif of psr doesn't seem very effective)
//

        la      k0,HalpCacheErrFirst
        li      k1,KSEG1_BASE           // convert address of KSEG1 address
        or      k1,k0,k1                //
        lw      k0,0(k1)
        nop
        beq     k0,zero,1f
        nop

//  cache error during cache error routine
        lw      ra,CiRa(sp)             // save return address
        addu    sp,sp,CiFrameLength     // allocate stack frame
        eret                            // hope we don't need k0 and k1...
        nop
    
1:      add     k0,k0,0x01
        sw      k0,0(k1)

//
//  Save all the registers
//

        la      k0,SavedAt              // get address of register save area
        li      k1,KSEG1_BASE           // convert address of KSEG1 address
        or      k0,k0,k1                //
        .set noat
        sw      AT,0(k0)                // save registers AT - a3
        .set at
        sw      v0,4(k0)                //
        sw      v1,8(k0)                //
        sw      a0,12(k0)               //
        sw      a1,16(k0)               //
        sw      a2,20(k0)               //
        sw      a3,24(k0)               //
        sw      t0,28(k0)               //
        sw      t1,32(k0)               //
        sw      t2,36(k0)               //
        sw      t3,40(k0)               //
        sw      t4,44(k0)               //
        sw      t5,48(k0)               //
        sw      t6,52(k0)               //
        sw      t7,56(k0)               //
        sw      s0,60(k0)               //
        sw      s1,64(k0)               //
        sw      s2,68(k0)               //
        sw      s3,72(k0)               //
        sw      s4,76(k0)               //
        sw      s5,80(k0)               //
        sw      s6,84(k0)               //
        sw      s7,88(k0)               //
        sw      t8,92(k0)               //
        sw      t9,96(k0)               //
        sw      s8,100(k0)               //
        sw      k0,104(k0)               //
        sw      k1,108(k0)               //
        sw      gp,112(k0)               //
        sw      sp,116(k0)               //
        sw      s8,120(k0)               //
        sw      ra,124(k0)               //

        mfc0    a1,cacheerr             // get cache error state
        nop
        nop
        nop
        nop
        nop
        nop
        mfc0    a0,errorepc             // get error address
        nop
        nop
        nop
        nop
        nop
        nop
        la      k0,SavedErrorEpc            // get address of register save area
        li      k1,KSEG1_BASE               // convert address of KSEG1 address
        or      k0,k0,k1                    //
        sw      a0,0(k0)                    // save errorepc  register
        sw      a1,4(k0)                    // save cache error register
//
// Disable ECC and parity detection  (HalpCacheFirstErr will help...)
//

        mfc0    k0,psr                  // get current processor state
        nop
        nop
        nop
        nop
        nop
        or      k0,k0,0x00010000                 // disable ECC and Parity detection
        and     k0,k0,0xfffffffe              // disable interrupt
        mtc0    k0,psr
        and     k0,k0,0xffff00e0
        mtc0    k0,psr


// Analysis of cacheerror register

        la      k0,SavedCacheError          // get address of register save area
        li      k1,KSEG1_BASE               // convert address of KSEG1 address
        or      k0,k0,k1                    //
        lw      t0,0(k0)                    // restore cache error register in t0

        and     t1,t0,CACHE_ERR_EE          // parity error
        bne     t1,zero,ParityError
        nop

//
// Cache error message
//

    	la	    a0,HalpErrCacheMsg
        and     a0,a0,0x1fffffff
        or      a0,a0,0xa0000000
        la      t0,HalDisplayString
        li      k1,KSEG1_BASE               // convert address of KSEG1 address
        or      t0,t0,k1                    //
        jal     t0                          // 
        nop

        la      k0,SavedCacheError          // get address of register save area
        li      k1,KSEG1_BASE               // convert address of KSEG1 address
        or      k0,k0,k1                    //
        lw      t0,0(k0)                    // restore cache error register in t0

        and     t1,t0,CACHE_ERR_SIDX        // grab low bits of PAddr
        lw      t2,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size
        subu    t2,t2,1
        not     t2
        and     t1,t2                       // t1=PAddre(21..scache_block_size); SCache index
//        lw      t2,KiPcr + PcSecondLevelDcacheSize(zero) // get 2nd size
//        subu    t2,t2,1
//        and     t1,t2                       // t1=PAddre(21..scache_block_size); SCache index

        and     t5,t0,CACHE_ERR_PIDX
        sll     t5,t5,0xc                       // align PIDX (bits 15:13)
        and     t2,t1,~(PIDX_PD_MASK)       // suppress PIDX bits for VAddr
        or      t2,t5                       // t2=VAddr(15..scache_block_size);PCache base index

        or      t1,0x80000000               // SCache index with K0SEG address
        or      t2,0x80000000                   // PCache base index with K0SEG address

        and     t5,t0,CACHE_ERR_EC          // Cache level of the error (0=primary, 1=secondary)
        bne     zero,t5,3f                    // if EC=0, Primary Cache Parity Error
        nop

1:      // primary cache

        // int error
        and     t5,t0,CACHE_ERR_ER          // data or instruction flag
        bne     zero,t5,2f                  // if ER=1 Data error
        nop

        move    a2,t2
        // primary cache - inst
        cache   INDEX_LOAD_TAG_I,0(t2) 

        nop
        mfc0    a3,taglo
        b       5f
        nop

2:      // primary cache - data
        move    a2,t2
        cache   INDEX_LOAD_TAG_D,0(t2) 

        nop
        mfc0    a3,taglo
        b       5f
        nop

3:      // secondary cache - inst/data
        move    a2,t1
        cache   INDEX_LOAD_TAG_SD,0(t1) 

        nop
        mfc0    a3,taglo
5:

// maybe a3 will be the erroneous physical address...

	    li	    a0,0x80                     // harware error
        la      k0,SavedErrorEpc            // get address of register save area
        li      k1,KSEG1_BASE               // convert address of KSEG1 address
        or      k0,k0,k1                    //
        li      a1,19                       // restore error epc register 
        lw      a2,4(k0)                    // restore cache error register 
        la      t1,HalpKeBugCheck0
        sw      a0,0(t1)
        la      t1,HalpKeBugCheck1
        sw      a1,0(t1)
        la      t1,HalpKeBugCheck2
        sw      a2,0(t1)
        la      t1,HalpKeBugCheck3
        sw      a3,0(t1)
        la      t1,HalpKeBugCheck4
        sw      zero,0(t1)
        la      t1,HalpBugCheckNumber
        sw      a1,0(t1)
        la      t0,KeBugCheckEx
        li      k1,KSEG1_BASE               // convert address of KSEG1 address
        or      t0,t0,k1                    //
        jal     t0                          // 
        sw      zero,0x10(sp)
        lw      ra,CiRa(sp)             // save return address
        addu    sp,sp,CiFrameLength     // allocate stack frame
        eret 
        nop

ParityError:

//
// cacheerr contents are not usable if parity error. 
// Then we must disassemble the errorepc code, get the used register
// and get the contents of this register which must cause the error. 
//

//
// Parity Error Msg
//

    	la	    a0,HalpParityErrMsg
        and     a0,a0,0x1fffffff
        or      a0,a0,0xa0000000
        la      t0,HalDisplayString
        li      k1,KSEG1_BASE               // convert address of KSEG1 address
        or      t0,t0,k1                    //
        jal     t0                          // 
        nop

//
// disasm
//
        la      k0,SavedErrorEpc            // get address of register save area
        li      k1,KSEG1_BASE               // convert address of KSEG1 address
        or      k0,k0,k1                    //
        lw      a0,0(k0)
        li      a2,0x00                     // init for one loop
        move    t0,a0

10:     lw      a0,0(a0)                    // instruction
        move    a1,a0                       // instruction saved in a1
        li      a3,HALP_OPCODE_MASK
        and     a0,a0,a3
        srl     a0,a0,HALP_OPCODE_SHIFT
        li      a2,0x00
        beq     a0,HALP_SWC1,8f
        nop
        beq     a0,HALP_SDC1,8f
        nop
        beq     a0,HALP_LWC1,8f
        nop
        beq     a0,HALP_LDC1,8f
        nop
        beq     a0,HALP_LB,8f
        nop
        beq     a0,HALP_LH,8f
        nop
        beq     a0,HALP_LW,8f
        nop
        beq     a0,HALP_LD,8f
        nop
        beq     a0,HALP_LBU,8f
        nop
        beq     a0,HALP_LHU,8f
        nop
        beq     a0,HALP_SB,8f
        nop
        beq     a0,HALP_SH,8f
        nop
        beq     a0,HALP_SW,8f
        nop
        beq     a0,HALP_SD,8f
        nop
        beq     a0,HALP_LWL,8f
        nop
        beq     a0,HALP_LWR,8f
        nop
        beq     a0,HALP_LDL,8f
        nop
        beq     a0,HALP_LDR,8f
        nop
        beq     a0,HALP_LWU,8f
        nop
        beq     a0,HALP_SDL,8f
        nop
        beq     a0,HALP_SDR,8f
        nop
        beq     a0,HALP_LWU,8f
        nop
        beq     a0,HALP_SDL,8f
        nop
        beq     a0,HALP_SDR,8f
        nop
        beq     a0,HALP_LL,8f
        nop
        beq     a0,HALP_SC,8f
        nop
        beq     a0,HALP_SCD,8f
        nop
        move    a0,t0
        addu    a0,a0,4
        beq     a2,zero,10b         // try the next instruction (case of branch...)
        addu    a2,a2,1

        beq     zero,zero,NotFoundAddr

8:  // a1 = inst en erreur

        move    a2,a1

        li      a3,HALP_RT2_REG
        and     a2,a2,a3
        srl     a3,a2,HALP_RT2_SHIFT

        subu    a3,1                    // reg at has 1 as number   
        sll     a3,a3,0x2                  // *4

        la      k0,SavedAt              // get address of register save area
        li      k1,KSEG1_BASE           // convert address of KSEG1 address
        or      k0,k0,k1                //
        addu    k0,k0,a3
        lw      a3,0(k0)                // contents of the register
// 
// Try To find the physical address
// a3 = virtual address
//

        move    a0,a3
        srl     a0,a0,30            // two upper bits
        li      a2,0x2              // binary 10 
        beq     a0,a2,FoundAddr     // KSEG0 or KSEG1 addr  
        nop
// mapped address => try to find it in the TLB
        move    a0,a3
        mfc0    t1,entryhi              // get current PID and VPN2
        srl     t2,a0,ENTRYHI_VPN2      // isolate VPN2 of virtual address
        sll     t2,t2,ENTRYHI_VPN2      //
        and     t1,t1,PID_MASK << ENTRYHI_PID // isolate current PID
        or      t2,t2,t1                // merge PID with VPN2 of virtual address
        mtc0    t2,entryhi              // set VPN2 and PID for probe
        nop                             // 3 cycle hazzard
        nop                             //
        nop                             //
        tlbp                            // probe for entry in TB
        nop                             // 2 cycle hazzard
        nop                             //
        mfc0    t3,index                // read result of probe
        nop
        bltz    t3,NotFoundAddr         // if ltz, entry is not in TB
        sll     a0,a0,0x1f - (ENTRYHI_VPN2 - 1) // shift VPN<12> into sign
        tlbr                            // read entry from TB
        nop                             // 3 cycle hazzard
        nop                             //
        nop                             //
        bltz    a0,11f                  // if ltz, check second PTE
        mfc0    t2,entrylo1             // get second PTE for probe
        mfc0    t2,entrylo0             // get first PTE for probe
11:     mtc0    t1,entryhi              // restore current PID
        mtc0    zero,pagemask           // restore page mask register
// t2 = entrylo
        srl     t2,t2,ENTRYLO_PFN
        sll     t2,t2,PAGE_SHIFT
        li      a2,PAGE_SIZE
        subu    a2,a2,1
        and     a3,a3,a2
        or      a3,a3,t2

FoundAddr:
// a3 = Physical addr 
        li      a2,0x1fffffff
        and     a3,a3,a2                    // 3 upper bits deleted   
        la      k0,SavedErrorEpc            // get address of register save area
        li      k1,KSEG1_BASE               // convert address of KSEG1 address
        or      k0,k0,k1                    //
        lw      a1,0(k0)                    // load error epc register
        lw      a2,4(k0)                    // load cache error register

        // compute sip num
        sw      a3,CiArgs0(sp)
        sw      a1,CiArgs1(sp)
        sw      a2,CiArgs2(sp)
        move    a0,a3
        la      t0,HalpComputeNum
        li      k1,KSEG1_BASE               // convert address of KSEG1 address
        or      t0,t0,k1                    //
        jal     t0                          // compute sip num
        nop
        lw      a3,CiArgs2(sp)
        sw      a3,0x10(sp)
        li      a1,18
        lw      a2,CiArgs0(sp)
ShowMsg:
        li	    a0,0x80

        la      t1,HalpKeBugCheck0
        sw      a0,0(t1)
        la      t1,HalpKeBugCheck1
        sw      a1,0(t1)
        la      t1,HalpKeBugCheck2
        sw      a2,0(t1)
        la      t1,HalpKeBugCheck3
        sw      v0,0(t1)
        la      t1,HalpKeBugCheck4
        sw      a3,0(t1)
        la      t1,HalpBugCheckNumber
        sw      a1,0(t1)
        la      t0,KeBugCheckEx
        li      k1,KSEG1_BASE               // convert address of KSEG1 address
        or      t0,t0,k1                    //
        jal     t0                          // 
        move    a3,v0                      // sip num

        lw      ra,CiRa(sp)             // save return address
        addu    sp,sp,CiFrameLength     // allocate stack frame
        eret                            //

NotFoundAddr:

    	la	    a0,HalpAddrErrMsg
        and     a0,a0,0x1fffffff
        or      a0,a0,0xa0000000
        la      t0,HalDisplayString
        li      k1,KSEG1_BASE               // convert address of KSEG1 address
        or      t0,t0,k1                    //
        jal     t0                          // 
        nop

        move    a3,a1
        li	    a0,0x80
        la      k0,SavedErrorEpc            // get address of register save area
        li      k1,KSEG1_BASE               // convert address of KSEG1 address
        or      k0,k0,k1                    //
        li      a1,18
        li      a2,0x00
        lw      a3,4(k0)
        sw      a3,0x10(sp)
        la      t1,HalpKeBugCheck0
        sw      a0,0(t1)
        la      t1,HalpKeBugCheck1
        sw      a1,0(t1)
        la      t1,HalpKeBugCheck2
        sw      a2,0(t1)
        la      t1,HalpKeBugCheck3
        sw      v0,0(t1)
        la      t1,HalpKeBugCheck4
        sw      a3,0(t1)
        la      t1,HalpBugCheckNumber
        sw      a1,0(t1)
        la      t0,KeBugCheckEx
        li      k1,KSEG1_BASE               // convert address of KSEG1 address
        or      t0,t0,k1                    //
        jal     t0                          // 
        li      a3,0xff

        lw      ra,CiRa(sp)             // save return address
        addu    sp,sp,CiFrameLength     // allocate stack frame
        eret                            //

        .set    reorder

        .end    HalpCacheErrorRoutine