/* * Copyright (c) 2003, 2004, 2005 * The Regents of The University of Michigan * All Rights Reserved * * This code is part of the M5 simulator, developed by Nathan Binkert, * Erik Hallnor, Steve Raasch, and Steve Reinhardt, with contributions * from Ron Dreslinski, Dave Greene, Lisa Hsu, Ali Saidi, and Andrew * Schultz. * * Permission is granted to use, copy, create derivative works and * redistribute this software and such derivative works for any * purpose, so long as the copyright notice above, this grant of * permission, and the disclaimer below appear in all copies made; and * so long as the name of The University of Michigan is not used in * any advertising or publicity pertaining to the use or distribution * of this software without specific, written prior authorization. * * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT, * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH * DAMAGES. */ /* Copyright 1993 Hewlett-Packard Development Company, L.P. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // build_fixed_image: not sure what means // real_mm to be replaced during rewrite // remove_save_state remove_restore_state can be remooved to save space ?? #define egore 0 #define acore 0 #define beh_model 0 #define ev5_p2 1 #define ev5_p1 0 #define ldvpte_bug_fix 1 #define spe_fix 0 #define osf_chm_fix 0 #define build_fixed_image 0 #define enable_p4_fixups 0 #define osf_svmin 1 #define enable_physical_console 0 #define fill_err_hack 0 #define icflush_on_tbix 0 #define max_cpuid 1 #define perfmon_debug 0 #define rax_mode 0 #define hw_rei_spe hw_rei #include "ev5_defs.h" #include "ev5_impure.h" #include "ev5_alpha_defs.h" #include "ev5_paldef.h" #include "ev5_osfalpha_defs.h" #include "fromHudsonMacros.h" #include "fromHudsonOsf.h" #include "dc21164FromGasSources.h" #include "cserve.h" #include "tlaser.h" #define ldlp ldl_p #define ldqp ldq_p #define stlp stl_p #define stqp stq_p #define stqpc stqp #ifdef SIMOS #define ldqpl ldq_p #define sdqpl sdq_p #else <--bomb> #endif #define pt_entInt pt_entint #define pt_entArith pt_entarith #define mchk_size ((mchk_cpu_base + 7 + 8) &0xfff8) #define mchk_flag CNS_Q_FLAG #define mchk_sys_base 56 #define mchk_cpu_base (CNS_Q_LD_LOCK + 8) #define mchk_offsets CNS_Q_EXC_ADDR #define mchk_mchk_code 8 #define mchk_ic_perr_stat CNS_Q_ICPERR_STAT #define mchk_dc_perr_stat CNS_Q_DCPERR_STAT #define mchk_sc_addr CNS_Q_SC_ADDR #define mchk_sc_stat CNS_Q_SC_STAT #define mchk_ei_addr CNS_Q_EI_ADDR #define mchk_bc_tag_addr CNS_Q_BC_TAG_ADDR #define mchk_fill_syn CNS_Q_FILL_SYN #define mchk_ei_stat CNS_Q_EI_STAT #define mchk_exc_addr CNS_Q_EXC_ADDR #define mchk_ld_lock CNS_Q_LD_LOCK #define osfpcb_q_Ksp pcb_q_ksp #define pal_impure_common_size ((0x200 + 7) & 0xfff8) #ifdef BIG_TSUNAMI #define MAXPROC 0x3f #define IPIQ_addr 0x800 #define IPIQ_shift 0 #define IPIR_addr 0x840 #define IPIR_shift 0 #define RTC_addr 0x880 #define RTC_shift 0 #define DIR_addr 0xa2 #else #define MAXPROC 0x3 #define IPIQ_addr 0x080 #define IPIQ_shift 12 #define IPIR_addr 0x080 #define IPIR_shift 8 #define RTC_addr 0x080 #define RTC_shift 4 #define DIR_addr 0xa0 #endif #define ALIGN_BLOCK \ .align 5 #define ALIGN_BRANCH \ .align 3 #define EXPORT(_x) \ .align 5; \ .globl _x; \ _x: // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // XXX the following is 'made up' // XXX bugnion // XXX bugnion not sure how to align 'quad' #define ALIGN_QUAD \ .align 3 #define ALIGN_128 \ .align 7 #define GET_IMPURE(_r) mfpr _r,pt_impure #define GET_ADDR(_r1,_off,_r2) lda _r1,_off(_r2) #define BIT(_x) (1<<(_x)) // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // XXX back to original code // .sbttl "System specific code - beh model version" // // Entry points // SYS$CFLUSH - Cache flush // SYS$CSERVE - Console service // SYS$WRIPIR - interprocessor interrupts // SYS$HALT_INTERRUPT - Halt interrupt // SYS$PASSIVE_RELEASE - Interrupt, passive release // SYS$INTERRUPT - Interrupt // SYS$RESET - Reset // SYS$ENTER_CONSOLE // // Macro to read TLINTRSUMx // // Based on the CPU_NUMBER, read either the TLINTRSUM0 or TLINTRSUM1 register // // Assumed register usage: // rsum TLINTRSUMx contents // raddr node space address // scratch scratch register // .macro Read_TLINTRSUMx rsum, raddr, scratch, ?label1, ?label2 // // nop // mfpr 'scratch', pt_whami // Get our whami (VID) // // extbl 'scratch', #1, 'scratch' // shift down to bit 0 // lda 'raddr', ^xff88(r31) // Get base node space address bits // // sll 'raddr', #24, 'raddr' // Shift up to proper position // srl 'scratch', #1, 'rsum' // Shift off the cpu number // // sll 'rsum', #22, 'rsum' // Get our node offset // addq 'raddr', 'rsum', 'raddr' // Get our base node space address // // blbs 'scratch', label1 // lda 'raddr', ('raddr') // // br r31, label2 //label1: lda 'raddr', ('raddr') // //label2: ldlp 'rsum', 0('raddr') // read the right tlintrsum reg //.endm #define Read_TLINTRSUMx(_rsum,_raddr,_scratch) \ nop; \ mfpr _scratch,pt_whami; \ extbl _scratch,1,_scratch; \ lda _raddr,0xff88(zero); \ sll _raddr,24,_raddr; \ srl _scratch,1,_rsum; \ sll _rsum,22,_rsum; \ addq _raddr,_rsum,_raddr; \ blbs _scratch,1f; \ lda _raddr,0x1180(_raddr); \ br r31,2f; \ 1: \ lda _raddr,0x11c0(_raddr); \ 2: ldlp _rsum,0(_raddr) // // Macro to write TLINTRSUMx // // Based on the CPU_NUMBER, write either the TLINTRSUM0 or TLINTRSUM1 register // // Assumed register usage: // rsum TLINTRSUMx write data // raddr node space address // scratch scratch register // .macro Write_TLINTRSUMx rsum, raddr, whami, ?label1, ?label2 // // nop // mfpr 'whami', pt_whami // Get our whami (VID) // // extbl 'whami', #1, 'whami' // shift down to bit 0 // lda 'raddr', ^xff88(r31) // Get base node space address bits // // sll 'raddr', #24, 'raddr' // Shift up to proper position // blbs 'whami', label1 // // lda 'raddr', ('raddr') // br r31, label2 // // label1: lda 'raddr', ('raddr') // label2: srl 'whami', #1, 'whami' // Shift off the cpu number // // sll 'whami', #22, 'whami' // Get our node offset // addq 'raddr', 'whami', 'raddr' // Get our base node space address // // mb // stqp 'rsum', 0('raddr') // write the right tlintrsum reg // mb // ldqp 'rsum', 0('raddr') // dummy read to tlintrsum // bis 'rsum', 'rsum', 'rsum' // needed to complete the ldqp above -jpo // .endm #define Write_TLINTRSUMx(_rsum,_raddr,_whami) \ nop; \ mfpr _whami,pt_whami; \ extbl _whami,1,_whami; \ lda _raddr,0xff88(zero); \ sll _raddr,24,_raddr; \ blbs _whami,1f; \ lda _raddr,0x1180(_raddr);\ br zero,2f; \ 1: lda _raddr,0x11c0(_raddr);\ 2: srl _whami,1,_whami; \ addq _raddr,_whami,_raddr; \ mb; \ stqp _rsum,0(_raddr); \ ldqp _rsum,0(_raddr); \ bis _rsum,_rsum,_rsum // // Macro to determine highest priority TIOP Node ID from interrupt pending mask // // Assumed register usage: // rmask - TLINTRSUMx contents, shifted to isolate IOx bits // rid - TLSB Node ID of highest TIOP //.macro Intr_Find_TIOP rmask, rid, ?l1, ?l2, ?l3, ?l4, ?l5, ?l6 // srl 'rmask', #4, 'rid' // check IOP8 // blbc 'rid', l1 // not IOP8 // // lda 'rid', 8(r31) // IOP8 // br r31, l6 // // l1: srl 'rmask', #3, 'rid' // check IOP7 // blbc 'rid', l2 // not IOP7 // // lda 'rid', 7(r31) // IOP7 // br r31, l6 // // l2: srl 'rmask', #2, 'rid' // check IOP6 // blbc 'rid', l3 // not IOP6 // // lda 'rid', 6(r31) // IOP6 // br r31, l6 // // l3: srl 'rmask', #1, 'rid' // check IOP5 // blbc 'rid', l4 // not IOP5 // // lda 'rid', 5(r31) // IOP5 // br r31, l6 // // l4: srl 'rmask', #0, 'rid' // check IOP4 // blbc 'rid', l5 // not IOP4 // // lda r14, 4(r31) // IOP4 // br r31, l6 // // l5: lda r14, 0(r31) // passive release // l6: // .endm #define Intr_Find_TIOP(_rmask,_rid) \ srl _rmask,3,_rid; \ blbc _rid,1f; \ lda _rid,8(zero); \ br zero,6f; \ 1: srl _rmask,3,_rid; \ blbc _rid, 2f; \ lda _rid, 7(r31); \ br r31, 6f; \ 2: srl _rmask, 2, _rid; \ blbc _rid, 3f; \ lda _rid, 6(r31); \ br r31, 6f; \ 3: srl _rmask, 1, _rid; \ blbc _rid, 4f; \ lda _rid, 5(r31); \ br r31, 6f; \ 4: srl _rmask, 0, _rid; \ blbc _rid, 5f; \ lda r14, 4(r31); \ br r31, 6f; \ 5: lda r14, 0(r31); \ 6: // // Macro to calculate base node space address for given node id // // Assumed register usage: // rid - TLSB node id // raddr - base node space address //.macro Get_TLSB_Node_Address rid, raddr // sll 'rid', #22, 'rid' // Get offset of IOP node // lda 'raddr', ^xff88(r31) // Get base node space address bits // // sll 'raddr', #24, 'raddr' // Shift up to proper position // addq 'raddr', 'rid', 'raddr' // Get TIOP node space address // .iif ne turbo_pcia_intr_fix, srl 'rid', #22, 'rid' // Restore IOP node id //.endm #define turbo_pcia_intr_fix 0 #if turbo_pcia_intr_fix != 0 #define Get_TLSB_Node_Address(_rid,_raddr) \ sll _rid,22,_rid; \ lda _raddr,0xff88(zero); \ sll _raddr,24,_raddr; \ addq _raddr,_rid,_raddr; \ srl _rid,22,_rid #else #define Get_TLSB_Node_Address(_rid,_raddr) \ sll _rid,22,_rid; \ lda _raddr,0xff88(zero); \ sll _raddr,24,_raddr; \ addq _raddr,_rid,_raddr #endif // .macro mchk$TLEPstore rlog, rs, rs1, nodebase, tlepreg, clr, tlsb, crd // .iif eq tlsb, lda 'rs1',(r31) // .iif ne tlsb, lda 'rs1',(r31) // or 'rs1', 'nodebase', 'rs1' // ldlp 'rs', 0('rs1') // .iif eq crd, stlp 'rs', mchk$'tlepreg'('rlog') // store in frame // .iif ne crd, stlp 'rs', mchk$crd_'tlepreg'('rlog') // store in frame // .iif ne clr, stlp 'rs',0('rs1') // optional write to clear // .endm // .macro OSFmchk$TLEPstore tlepreg, clr=0, tlsb=0 // mchk$TLEPstore r14, r8, r4, r13, , , , crd=0 // .endm #define CONCAT(_a,_b) _a ## _b #define OSFmchk_TLEPstore_1(_rlog,_rs,_rs1,_nodebase,_tlepreg) \ lda _rs1,CONCAT(tlep_,_tlepreg)(zero); \ or _rs1,_nodebase,_rs1; \ ldlp _rs1,0(_rs1); \ stlp _rs,CONCAT(mchk_,_tlepreg)(_rlog) #define OSFmchk_TLEPstore(_tlepreg) OSFmchk_TLEPstore_1(r14,r8,r4,r13,_tlepreg) // .macro OSFcrd$TLEPstore tlepreg, clr=0, tlsb=0 // mchk$TLEPstore r14, r10, r1, r0, , , , crd=1 // .endm #define OSFcrd_TLEPstore_1(_rlog,_rs,_rs1,_nodebase,_tlepreg) \ lda _rs1,CONCAT(tlep_,_tlepreg)(zero); \ or _rs1,_nodebase,_rs1; \ ldlp _rs1,0(_rs1); \ stlp _rs,CONCAT(mchk_crd_,_tlepreg)(_rlog) #define OSFcrd_TLEPstore_tlsb_1(_rlog,_rs,_rs1,_nodebase,_tlepreg) \ lda _rs1,CONCAT(tlsb_,_tlepreg)(zero); \ or _rs1,_nodebase,_rs1; \ ldlp _rs1,0(_rs1); \ stlp _rs,CONCAT(mchk_crd_,_tlepreg)(_rlog) #define OSFcrd_TLEPstore_tlsb_clr_1(_rlog,_rs,_rs1,_nodebase,_tlepreg) \ lda _rs1,CONCAT(tlsb_,_tlepreg)(zero); \ or _rs1,_nodebase,_rs1; \ ldlp _rs1,0(_rs1); \ stlp _rs,CONCAT(mchk_crd_,_tlepreg)(_rlog); \ stlp _rs,0(_rs1) #define OSFcrd_TLEPstore(_tlepreg) OSFcrd_TLEPstore_1(r14,r8,r4,r13,_tlepreg) #define OSFcrd_TLEPstore_tlsb(_tlepreg) OSFcrd_TLEPstore_tlsb_1(r14,r8,r4,r13,_tlepreg) #define OSFcrd_TLEPstore_tlsb_clr(_tlepreg) OSFcrd_TLEPstore_tlsb_clr_1(r14,r8,r4,r13,_tlepreg) // .macro save_pcia_intr irq // and r13, #^xf, r25 // isolate low 4 bits // addq r14, #4, r14 // format the TIOP Node id field // sll r14, #4, r14 // shift the TIOP Node id // or r14, r25, r10 // merge Node id/hose/HPC // mfpr r14, pt14 // get saved value // extbl r14, #'irq', r25 // confirm none outstanding // bne r25, sys$machine_check_while_in_pal // insbl r10, #'irq', r10 // align new info // or r14, r10, r14 // merge info // mtpr r14, pt14 // save it // bic r13, #^xf, r13 // clear low 4 bits of vector // .endm #define save_pcia_intr(_irq) \ and r13, 0xf, r25; \ addq r14, 4, r14; \ sll r14, 4, r14; \ or r14, r25, r10; \ mfpr r14, pt14; \ extbl r14, _irq, r25; \ bne r25, sys_machine_check_while_in_pal; \ insbl r10, _irq, r10; \ or r14, r10, r14; \ mtpr r14, pt14; \ bic r13, 0xf, r13 ALIGN_BLOCK // .sbttl "wripir - PALcode for wripir instruction" //orig SYS$WRIPIR: // R16 has the processor number. EXPORT(sys_wripir) //++ // Convert the processor number to a CPU mask //-- and r16,MAXPROC, r14 // mask the top stuff (4 or 64 CPUs supported) bis r31,0x1,r16 // get a one sll r16,r14,r14 // shift the bit to the right place sll r14,IPIQ_shift,r14 //++ // Build the Broadcast Space base address //-- lda r16,0xf01(r31) sll r16,32,r16 ldah r13,0xa0(r31) sll r13,8,r13 bis r16,r13,r16 lda r16,IPIQ_addr(r16) //++ // Send out the IP Intr //-- stqp r14, 0(r16) // Tsunami MISC Register wmb // Push out the store hw_rei ALIGN_BLOCK // .sbttl "CFLUSH- PALcode for CFLUSH instruction" //+ // SYS$CFLUSH // Entry: // // R16 - contains the PFN of the page to be flushed // // Function: // Flush all Dstream caches of 1 entire page // //- EXPORT(sys_cflush) // #convert pfn to addr, and clean off <63:20> // #sll r16, +<63-20>>, r12 sll r16, page_offset_size_bits+(63-20),r12 // #ldah r13,<<1@22>+32768>@-16(r31)// + xxx<31:16> // # stolen from srcmax code. XXX bugnion lda r13, 0x10(r31) // assume 16Mbytes of cache sll r13, 20, r13 // convert to bytes srl r12, 63-20, r12 // shift back to normal position xor r12, r13, r12 // xor addr<18> or r31, 8192/(32*8), r13 // get count of loads nop cflush_loop: subq r13, 1, r13 // decr counter mfpr r25, ev5__intid // Fetch level of interruptor ldqp r31, 32*0(r12) // do a load ldqp r31, 32*1(r12) // do next load ldqp r31, 32*2(r12) // do next load ldqp r31, 32*3(r12) // do next load ldqp r31, 32*4(r12) // do next load ldqp r31, 32*5(r12) // do next load ldqp r31, 32*6(r12) // do next load ldqp r31, 32*7(r12) // do next load mfpr r14, ev5__ipl // Fetch current level lda r12, (32*8)(r12) // skip to next cache block addr cmple r25, r14, r25 // R25 = 1 if intid .less than or eql ipl beq r25, 1f // if any int's pending, re-queue CFLUSH -- need to check for hlt interrupt??? bne r13, cflush_loop // loop till done hw_rei // back to user ALIGN_BRANCH 1: // Here if interrupted mfpr r12, exc_addr subq r12, 4, r12 // Backup PC to point to CFLUSH mtpr r12, exc_addr nop mfpr r31, pt0 // Pad exc_addr write hw_rei ALIGN_BLOCK // .sbttl "CSERVE- PALcode for CSERVE instruction" //+ // SYS$CSERVE // // Function: // Various functions for private use of console software // // option selector in r0 // arguments in r16.... // // // r0 = 0 unknown // // r0 = 1 ldqp // r0 = 2 stqp // args, are as for normal STQP/LDQP in VMS PAL // // r0 = 3 dump_tb's // r16 = detination PA to dump tb's to. // // r0<0> = 1, success // r0<0> = 0, failure, or option not supported // r0<63:1> = (generally 0, but may be function dependent) // r0 - load data on ldqp // //- EXPORT(sys_cserve) #ifdef SIMOS /* taken from scrmax */ cmpeq r18, CSERVE_K_RD_IMPURE, r0 bne r0, Sys_Cserve_Rd_Impure cmpeq r18, CSERVE_K_JTOPAL, r0 bne r0, Sys_Cserve_Jtopal call_pal 0 or r31, r31, r0 hw_rei // and back we go Sys_Cserve_Rd_Impure: mfpr r0, pt_impure // Get base of impure scratch area. hw_rei ALIGN_BRANCH Sys_Cserve_Jtopal: bic a0, 3, t8 // Clear out low 2 bits of address bis t8, 1, t8 // Or in PAL mode bit mtpr t8,exc_addr hw_rei #else /* SIMOS */ cmpeq r16, cserve_ldlp, r12 // check for ldqp bne r12, 1f // br if cmpeq r16, cserve_stlp, r12 // check for stqp bne r12, 2f // br if cmpeq r16, cserve_callback, r12 // check for callback entry bne r12, csrv_callback // br if cmpeq r16, cserve_identify, r12 // check for callback entry bne r12, csrv_identify // br if or r31, r31, r0 // set failure nop // pad palshadow write hw_rei // and back we go #endif /* SIMOS */ // ldqp ALIGN_QUAD 1: ldqp r0,0(r17) // get the data nop // pad palshadow write hw_rei // and back we go // stqp ALIGN_QUAD 2: stqp r18, 0(r17) // store the data #ifdef SIMOS lda r0,17(r31) // bogus #else lda r0, CSERVE_SUCCESS(r31) // set success #endif hw_rei // and back we go ALIGN_QUAD csrv_callback: ldq r16, 0(r17) // restore r16 ldq r17, 8(r17) // restore r17 lda r0, hlt_c_callback(r31) br r31, sys_enter_console csrv_identify: mfpr r0, pal_base ldqp r0, 8(r0) hw_rei // dump tb's ALIGN_QUAD 0: // DTB PTEs - 64 entries addq r31, 64, r0 // initialize loop counter nop 1: mfpr r12, ev5__dtb_pte_temp // read out next pte to temp mfpr r12, ev5__dtb_pte // read out next pte to reg file subq r0, 1, r0 // decrement loop counter nop // Pad - no Mbox instr in cycle after mfpr stqp r12, 0(r16) // store out PTE addq r16, 8 ,r16 // increment pointer bne r0, 1b ALIGN_BRANCH // ITB PTEs - 48 entries addq r31, 48, r0 // initialize loop counter nop 2: mfpr r12, ev5__itb_pte_temp // read out next pte to temp mfpr r12, ev5__itb_pte // read out next pte to reg file subq r0, 1, r0 // decrement loop counter nop // stqp r12, 0(r16) // store out PTE addq r16, 8 ,r16 // increment pointer bne r0, 2b or r31, 1, r0 // set success hw_rei // and back we go // .sbttl "SYS$INTERRUPT - Interrupt processing code" //+ // SYS$INTERRUPT // // Current state: // Stack is pushed // ps, sp and gp are updated // r12, r14 - available // r13 - INTID (new EV5 IPL) // r25 - ISR // r16, r17, r18 - available // //- EXPORT(sys_interrupt) cmpeq r13, 31, r12 bne r12, sys_int_mchk_or_crd // Check for level 31 interrupt (machine check or crd) cmpeq r13, 30, r12 bne r12, sys_int_powerfail // Check for level 30 interrupt (powerfail) cmpeq r13, 29, r12 bne r12, sys_int_perf_cnt // Check for level 29 interrupt (performance counters) cmpeq r13, 23, r12 bne r12, sys_int_23 // Check for level 23 interrupt // IPI in Tsunami cmpeq r13, 22, r12 bne r12, sys_int_22 // Check for level 22 interrupt // timer interrupt cmpeq r13, 21, r12 bne r12, sys_int_21 // Check for level 21 interrupt // I/O cmpeq r13, 20, r12 bne r12, sys_int_20 // Check for level 20 interrupt (might be corrected // system error interrupt) mfpr r14, exc_addr // ooops, something is wrong br r31, pal_pal_bug_check_from_int //+ //sys$int_2* // Routines to handle device interrupts at IPL 23-20. // System specific method to ack/clear the interrupt, detect passive release, // detect interprocessor (22), interval clock (22), corrected // system error (20) // // Current state: // Stack is pushed // ps, sp and gp are updated // r12, r14 - available // r13 - INTID (new EV5 IPL) // r25 - ISR // // On exit: // Interrupt has been ack'd/cleared // a0/r16 - signals IO device interrupt // a1/r17 - contains interrupt vector // exit to ent_int address // //- ALIGN_BRANCH sys_int_23: or r31,0,r16 // IPI interrupt A0 = 0 lda r12,0xf01(r31) // build up an address for the MISC register sll r12,16,r12 lda r12,0xa000(r12) sll r12,16,r12 lda r12,IPIR_addr(r12) mfpr r10, pt_whami // get CPU ID extbl r10, 1, r10 // Isolate just whami bits or r31,0x1,r14 // load r14 with bit to clear sll r14,r10,r14 // left shift by CPU ID sll r14,IPIR_shift,r14 stq_p r14, 0(r12) // clear the ipi interrupt br r31, pal_post_interrupt // Notify the OS ALIGN_BRANCH sys_int_22: or r31,1,r16 // a0 means it is a clock interrupt lda r12,0xf01(r31) // build up an address for the MISC register sll r12,16,r12 lda r12,0xa000(r12) sll r12,16,r12 lda r12,RTC_addr(r12) mfpr r10, pt_whami // get CPU ID extbl r10, 1, r10 // Isolate just whami bits or r31,0x1,r14 // load r14 with bit to clear sll r14,r10,r14 // left shift by CPU ID sll r14,RTC_shift,r14 // put the bits in the right position stq_p r14, 0(r12) // clear the rtc interrupt br r31, pal_post_interrupt // Tell the OS ALIGN_BRANCH sys_int_20: Read_TLINTRSUMx(r13,r10,r14) // read the right TLINTRSUMx srl r13, 12, r13 // shift down to examine IPL15 Intr_Find_TIOP(r13,r14) beq r14, 1f Get_TLSB_Node_Address(r14,r10) lda r10, 0xa40(r10) // Get base TLILID address ldlp r13, 0(r10) // Read the TLILID register #if turbo_pcia_intr_fix == 0 //orig .if eq turbo_pcia_intr_fix bne r13, pal_post_dev_interrupt //orig .iff beq r13, 1f and r13, 0x3, r10 // check for PCIA bits beq r10, pal_post_dev_interrupt // done if nothing set save_pcia_intr(1) br r31, pal_post_dev_interrupt // // orig .endc #endif /* turbo_pcia_intr_fix == 0 */ 1: lda r16, osfint_c_passrel(r31) // passive release br r31, pal_post_interrupt // ALIGN_BRANCH sys_int_21: lda r12,0xf01(r31) // calculate DIRn address sll r12,32,r12 ldah r13,DIR_addr(r31) sll r13,8,r13 bis r12,r13,r12 mfpr r13, pt_whami // get CPU ID extbl r13, 1, r13 // Isolate just whami bits #ifdef BIG_TSUNAMI sll r13,4,r13 or r12,r13,r12 #else lda r12,0x0080(r12) and r13,0x1,r14 // grab LSB and shift left 6 sll r14,6,r14 and r13,0x2,r10 // grabl LSB+1 and shift left 9 sll r10,9,r10 mskbl r12,0,r12 // calculate DIRn address lda r13,0x280(r31) bis r12,r13,r12 or r12,r14,r12 or r12,r10,r12 #endif ldqp r13, 0(r12) // read DIRn or r31,1,r14 // set bit 55 (ISA Interrupt) sll r14,55,r14 and r13, r14, r14 // check if bit 55 is set lda r16,0x900(r31) // load offset for normal into r13 beq r14, normal_int // if not compute the vector normally lda r16,0x800(r31) // replace with offset for pic lda r12,0xf01(r31) // build an addr to access PIC sll r12,32,r12 // at f01fc000000 ldah r13,0xfc(r31) sll r13,8,r13 bis r12,r13,r12 ldqp r13,0x0020(r12) // read PIC1 ISR for interrupting dev normal_int: //ctlz r13,r14 // count the number of leading zeros // EV5 doesn't have ctlz, but we do, so lets use it .byte 0x4e .byte 0x06 .byte 0xed .byte 0x73 lda r10,63(r31) subq r10,r14,r17 // subtract from lda r13,0x10(r31) mulq r17,r13,r17 // compute 0x900 + (0x10 * Highest DIRn-bit) addq r17,r16,r17 or r31,3,r16 // a0 means it is a I/O interrupt br r31, pal_post_interrupt ALIGN_BRANCH pal_post_dev_interrupt: or r13, r31, r17 // move vector to a1 or r31, osfint_c_dev, r16 // a0 signals IO device interrupt pal_post_interrupt: mfpr r12, pt_entint mtpr r12, exc_addr nop nop hw_rei_spe //+ // sys_passive_release // Just pretend the interrupt never occurred. //- EXPORT(sys_passive_release) mtpr r11, ev5__dtb_cm // Restore Mbox current mode for ps nop mfpr r31, pt0 // Pad write to dtb_cm hw_rei //+ //sys_int_powerfail // A powerfail interrupt has been detected. The stack has been pushed. // IPL and PS are updated as well. // // I'm not sure what to do here, I'm treating it as an IO device interrupt // //- ALIGN_BLOCK sys_int_powerfail: lda r12, 0xffc4(r31) // get GBUS_MISCR address bits sll r12, 24, r12 // shift to proper position ldqp r12, 0(r12) // read GBUS_MISCR srl r12, 5, r12 // isolate bit <5> blbc r12, 1f // if clear, no missed mchk // Missed a CFAIL mchk lda r13, 0xffc7(r31) // get GBUS$SERNUM address bits sll r13, 24, r13 // shift to proper position lda r14, 0x40(r31) // get bit <6> mask ldqp r12, 0(r13) // read GBUS$SERNUM or r12, r14, r14 // set bit <6> stqp r14, 0(r13) // clear GBUS$SERNUM<6> mb mb 1: br r31, sys_int_mchk // do a machine check lda r17, scb_v_pwrfail(r31) // a1 to interrupt vector mfpr r25, pt_entint lda r16, osfint_c_dev(r31) // a0 to device code mtpr r25, exc_addr nop // pad exc_addr write nop hw_rei_spe //+ // sys$halt_interrupt // A halt interrupt has been detected. Pass control to the console. // // //- EXPORT(sys_halt_interrupt) ldah r13, 0x1800(r31) // load Halt/^PHalt bits Write_TLINTRSUMx(r13,r10,r14) // clear the ^PHalt bits mtpr r11, dtb_cm // Restore Mbox current mode nop nop mtpr r0, pt0 #ifndef SIMOS pvc_jsr updpcb, bsr=1 bsr r0, pal_update_pcb // update the pcb #endif lda r0, hlt_c_hw_halt(r31) // set halt code to hw halt br r31, sys_enter_console // enter the console //+ // sys$int_mchk_or_crd // // Current state: // Stack is pushed // ps, sp and gp are updated // r12 // r13 - INTID (new EV5 IPL) // r14 - exc_addr // r25 - ISR // r16, r17, r18 - available // //- ALIGN_BLOCK sys_int_mchk_or_crd: srl r25, isr_v_mck, r12 blbs r12, sys_int_mchk //+ // Not a Machine check interrupt, so must be an Internal CRD interrupt //- mb //Clear out Cbox prior to reading IPRs srl r25, isr_v_crd, r13 //Check for CRD blbc r13, pal_pal_bug_check_from_int //If CRD not set, shouldn't be here!!! lda r9, 1(r31) sll r9, hwint_clr_v_crdc, r9 // get ack bit for crd mtpr r9, ev5__hwint_clr // ack the crd interrupt or r31, r31, r12 // clear flag lda r9, mchk_c_ecc_c(r31) // Correctable error MCHK code sys_merge_sys_corr: ldah r14, 0xfff0(r31) mtpr r0, pt0 // save r0 for scratch zap r14, 0xE0, r14 // Get Cbox IPR base mtpr r1, pt1 // save r0 for scratch ldqp r0, ei_addr(r14) // EI_ADDR IPR ldqp r10, fill_syn(r14) // FILL_SYN IPR bis r0, r10, r31 // Touch lds to make sure they complete before doing scrub blbs r12, 1f // no scrubbing for IRQ0 case // XXX bugnion pvc_jsr crd_scrub_mem, bsr=1 bsr r13, sys_crd_scrub_mem // and go scrub // ld/st pair in scrub routine will have finished due // to ibox stall of stx_c. Don't need another mb. ldqp r8, ei_stat(r14) // EI_STAT, unlock EI_ADDR, BC_TAG_ADDR, FILL_SYN or r8, r31, r12 // Must only be executed once in this flow, and must br r31, 2f // be after the scrub routine. 1: ldqp r8, ei_stat(r14) // EI_STAT, unlock EI_ADDR, BC_TAG_ADDR, FILL_SYN // For IRQ0 CRD case only - meaningless data. 2: mfpr r13, pt_mces // Get MCES srl r12, ei_stat_v_ei_es, r14 // Isolate EI_STAT:EI_ES blbc r14, 6f // branch if 630 srl r13, mces_v_dsc, r14 // check if 620 reporting disabled blbc r14, 5f // branch if enabled or r13, r31, r14 // don't set SCE if disabled br r31, 8f // continue 5: bis r13, BIT(mces_v_sce), r14 // Set MCES bit br r31, 8f 6: srl r13, mces_v_dpc, r14 // check if 630 reporting disabled blbc r14, 7f // branch if enabled or r13, r31, r14 // don't set PCE if disabled br r31, 8f // continue 7: bis r13, BIT(mces_v_pce), r14 // Set MCES bit // Setup SCB if dpc is not set 8: mtpr r14, pt_mces // Store updated MCES srl r13, mces_v_sce, r1 // Get SCE srl r13, mces_v_pce, r14 // Get PCE or r1, r14, r1 // SCE OR PCE, since they share // the CRD logout frame // Get base of the logout area. GET_IMPURE(r14) // addr of per-cpu impure area GET_ADDR(r14,(pal_logout_area+mchk_crd_base),r14) blbc r1, sys_crd_write_logout_frame // If pce/sce not set, build the frame // Set the 2nd error flag in the logout area: lda r1, 3(r31) // Set retry and 2nd error flags sll r1, 30, r1 // Move to bits 31:30 of logout frame flag longword stlp r1, mchk_crd_flag+4(r14) // store flag longword br sys_crd_ack sys_crd_write_logout_frame: // should only be here if neither the pce or sce bits are set //+ // Write the mchk code to the logout area //- stqp r9, mchk_crd_mchk_code(r14) //+ // Write the first 2 quadwords of the logout area: //- lda r1, 1(r31) // Set retry flag sll r1, 63, r9 // Move retry flag to bit 63 lda r1, mchk_crd_size(r9) // Combine retry flag and frame size stqp r1, mchk_crd_flag(r14) // store flag/frame size #ifndef SIMOS /* needed? bugnion */ lda r1, mchk_crd_sys_base(r31) // sys offset sll r1, 32, r1 lda r1, mchk_crd_cpu_base(r1) // cpu offset stqp r1, mchk_crd_offsets(r14) // store sys offset/cpu offset into logout frame #endif //+ // Write error IPRs already fetched to the logout area //- stqp r0, mchk_crd_ei_addr(r14) stqp r10, mchk_crd_fill_syn(r14) stqp r8, mchk_crd_ei_stat(r14) stqp r25, mchk_crd_isr(r14) //+ // Log system specific info here //- crd_storeTLEP_: lda r1, 0xffc4(r31) // Get GBUS$MISCR address sll r1, 24, r1 ldqp r1, 0(r1) // Read GBUS$MISCR sll r1, 16, r1 // shift up to proper field mfpr r10, pt_whami // get our node id extbl r10, 1, r10 // shift to bit 0 or r1, r10, r1 // merge MISCR and WHAMI stlp r1, mchk_crd_whami(r14) // write to crd logout area srl r10, 1, r10 // shift off cpu number Get_TLSB_Node_Address(r10,r0) // compute our nodespace address OSFcrd_TLEPstore_tlsb(tldev) OSFcrd_TLEPstore_tlsb_clr(tlber) OSFcrd_TLEPstore_tlsb_clr(tlesr0) OSFcrd_TLEPstore_tlsb_clr(tlesr1) OSFcrd_TLEPstore_tlsb_clr(tlesr2) OSFcrd_TLEPstore_tlsb_clr(tlesr3) sys_crd_ack: mfpr r0, pt0 // restore r0 mfpr r1, pt1 // restore r1 srl r12, ei_stat_v_ei_es, r12 blbc r12, 5f srl r13, mces_v_dsc, r10 // logging enabled? br r31, 6f 5: srl r13, mces_v_dpc, r10 // logging enabled? 6: blbc r10, sys_crd_post_interrupt // logging enabled -- report it // logging not enabled -- // Get base of the logout area. GET_IMPURE(r13) // addr of per-cpu impure area GET_ADDR(r13,(pal_logout_area+mchk_crd_base),r13) ldlp r10, mchk_crd_rsvd(r13) // bump counter addl r10, 1, r10 stlp r10, mchk_crd_rsvd(r13) mb br r31, sys_crd_dismiss_interrupt // just return //+ // The stack is pushed. Load up a0,a1,a2 and vector via entInt // //- ALIGN_BRANCH sys_crd_post_interrupt: lda r16, osfint_c_mchk(r31) // flag as mchk/crd in a0 lda r17, scb_v_proc_corr_err(r31) // a1 <- interrupt vector blbc r12, 1f lda r17, scb_v_sys_corr_err(r31) // a1 <- interrupt vector 1: subq r31, 1, r18 // get a -1 mfpr r25, pt_entInt srl r18, 42, r18 // shift off low bits of kseg addr mtpr r25, exc_addr // load interrupt vector sll r18, 42, r18 // shift back into position or r14, r18, r18 // EV4 algorithm - pass pointer to mchk frame as kseg address hw_rei_spe // done //+ // The stack is pushed. Need to back out of it all. //- sys_crd_dismiss_interrupt: br r31, Call_Pal_Rti // .sbttl sys_crd_scrub_mem //+ // // sys_crd_scrub_mem // called // jsr r13, sys$crd_scrub_mem // r0 = addr of cache block // //- ALIGN_BLOCK // align for branch target sys_crd_scrub_mem: // now find error in memory, and attempt to scrub that cache block // This routine just scrubs the failing octaword // Only need to "touch" one quadword per octaword to accomplish the scrub srl r0, 39, r8 // get high bit of bad pa blbs r8, 1f // don't attempt fixup on IO space addrs nop // needed to align the ldqpl to octaword boundary nop // " ldqpl r8, 0(r0) // attempt to read the bad memory // location // (Note bits 63:40,3:0 of ei_addr // are set to 1, but as long as // we are doing a phys ref, should // be ok) nop // Needed to keep the Ibox from swapping the ldqpl into E1 stqpc r8, 0(r0) // Store it back if it is still there. // If store fails, location already // scrubbed by someone else nop // needed to align the ldqpl to octaword boundary lda r8, 0x20(r31) // flip bit 5 to touch next hexaword xor r8, r0, r0 nop // needed to align the ldqpl to octaword boundary nop // " ldqpl r8, 0(r0) // attempt to read the bad memory // location // (Note bits 63:40,3:0 of ei_addr // are set to 1, but as long as // we are doing a phys ref, should // be ok) nop // Needed to keep the Ibox from swapping the ldqpl into E1 stqpc r8, 0(r0) // Store it back if it is still there. // If store fails, location already // scrubbed by someone else lda r8, 0x20(r31) // restore r0 to original address xor r8, r0, r0 //at this point, ei_stat could be locked due to a new corr error on the ld, //so read ei_stat to unlock AFTER this routine. // XXX bugnion pvc$jsr crd_scrub_mem, bsr=1, dest=1 1: ret r31, (r13) // and back we go // .sbttl "SYS$INT_MCHK - MCHK Interrupt code" //+ // Machine check interrupt from the system. Setup and join the // regular machine check flow. // On exit: // pt0 - saved r0 // pt1 - saved r1 // pt4 - saved r4 // pt5 - saved r5 // pt6 - saved r6 // pt10 - saved exc_addr // pt_misc<47:32> - mchk code // pt_misc<31:16> - scb vector // r14 - base of Cbox IPRs in IO space // MCES is set //- ALIGN_BLOCK sys_int_mchk: lda r14, mchk_c_sys_hrd_error(r31) mfpr r12, exc_addr addq r14, 1, r14 // Flag as interrupt nop sll r14, 32, r14 // Move mchk code to position mtpr r12, pt10 // Stash exc_addr mfpr r12, pt_misc // Get MCES and scratch mtpr r0, pt0 // Stash for scratch zap r12, 0x3c, r12 // Clear scratch blbs r12, sys_double_machine_check // MCHK halt if double machine check or r12, r14, r12 // Combine mchk code lda r14, scb_v_sysmchk(r31) // Get SCB vector sll r14, 16, r14 // Move SCBv to position or r12, r14, r14 // Combine SCBv bis r14, BIT(mces_v_mchk), r14 // Set MCES bit mtpr r14, pt_misc // Save mchk code!scbv!whami!mces ldah r14, 0xfff0(r31) mtpr r1, pt1 // Stash for scratch zap r14, 0xE0, r14 // Get Cbox IPR base mtpr r4, pt4 mtpr r5, pt5 #if beh_model // .if ne beh_model ldah r25, 0xC000(r31) // Get base of demon space lda r25, 0x340(r25) // Add interrupt demon offset ldqp r13, 0(r25) // Read the control register nop and r13, 0x10, r8 // For debug, check that the interrupt is expected beq r8, interrupt_not_expected bic r13, 0x10, r13 stqp r13, 0(r25) // Ack and clear the interrupt // XXX bugnion pvc$violate 379 // stqp can't trap except replay. mt ipr only problem if mf same ipr in same shadow .endc #endif mtpr r6, pt6 br r31, sys_mchk_collect_iprs // Join common machine check flow // .sbttl "SYS$INT_PERF_CNT - Performance counter interrupt code" //+ //sys$int_perf_cnt // // A performance counter interrupt has been detected. The stack has been pushed. // IPL and PS are updated as well. // // on exit to interrupt entry point ENTINT:: // a0 = osfint$c_perf // a1 = scb$v_perfmon (650) // a2 = 0 if performance counter 0 fired // a2 = 1 if performance counter 1 fired // a2 = 2 if performance counter 2 fired // (if more than one counter overflowed, an interrupt will be // generated for each counter that overflows) // // //- ALIGN_BLOCK sys_int_perf_cnt: // Performance counter interrupt lda r17, scb_v_perfmon(r31) // a1 to interrupt vector mfpr r25, pt_entint lda r16, osfint_c_perf(r31) // a0 to perf counter code mtpr r25, exc_addr //isolate which perf ctr fired, load code in a2, and ack mfpr r25, isr or r31, r31, r18 // assume interrupt was pc0 srl r25, isr_v_pc1, r25 // isolate cmovlbs r25, 1, r18 // if pc1 set, load 1 into r14 srl r25, 1, r25 // get pc2 cmovlbs r25, 2, r18 // if pc2 set, load 2 into r14 lda r25, 1(r31) // get a one sll r25, r18, r25 sll r25, hwint_clr_v_pc0c, r25 // ack only the perf counter that generated the interrupt mtpr r25, hwint_clr hw_rei_spe ALIGN_BLOCK // .sbttl "System specific RESET code" //+ // RESET code // On entry: // r1 = pal_base +8 // // Entry state on trap: // r0 = whami // r2 = base of scratch area // r3 = halt code // and the following 3 if init_cbox is enabled: // r5 = sc_ctl // r6 = bc_ctl // r7 = bc_cnfg // // Entry state on switch: // r17 - new PC // r18 - new PCBB // r19 - new VPTB // //- #if rax_mode==0 .globl sys_reset sys_reset: // mtpr r31, ic_flush_ctl // do not flush the icache - done by hardware before SROM load mtpr r31, itb_ia // clear the ITB mtpr r31, dtb_ia // clear the DTB lda r1, -8(r1) // point to start of code mtpr r1, pal_base // initialize PAL_BASE // Interrupts mtpr r31, astrr // stop ASTs mtpr r31, aster // stop ASTs mtpr r31, sirr // clear software interrupts mtpr r0, pt1 // r0 is whami (unless we entered via swp) //orig ldah r1, <<1@> ! <1@> ! <2@>>(r31) ldah r1,(BIT(icsr_v_sde-16)|BIT(icsr_v_fpe-16)|BIT(icsr_v_spe-16+1))(zero) #if disable_crd == 0 // .if eq disable_crd bis r31, 1, r0 sll r0, icsr_v_crde, r0 // A 1 in iscr or r0, r1, r1 // Set the bit #endif mtpr r1, icsr // ICSR - Shadows enabled, Floating point enable, // super page enabled, correct read per assembly option // Mbox/Dcache init //orig lda r1, <1@>(r31) lda r1,BIT(mcsr_v_sp1)(zero) mtpr r1, mcsr // MCSR - Super page enabled lda r1, BIT(dc_mode_v_dc_ena)(r31) ALIGN_BRANCH // mtpr r1, dc_mode // turn Dcache on nop mfpr r31, pt0 // No Mbox instr in 1,2,3,4 mfpr r31, pt0 mfpr r31, pt0 mfpr r31, pt0 mtpr r31, dc_flush // flush Dcache // build PS (IPL=7,CM=K,VMM=0,SW=0) lda r11, 0x7(r31) // Set shadow copy of PS - kern mode, IPL=7 lda r1, 0x1F(r31) mtpr r1, ipl // set internal =1F mtpr r31, ev5__ps // set new ps=0, Ibox copy mtpr r31, dtb_cm // set new ps=0, Mbox copy // Create the PALtemp pt_intmask - // MAP: // OSF IPL EV5 internal IPL(hex) note // 0 0 // 1 1 // 2 2 // 3 14 device // 4 15 device // 5 16 device // 6 1E device,performance counter, powerfail // 7 1F // ldah r1, 0x1f1E(r31) // Create upper lw of int_mask lda r1, 0x1615(r1) sll r1, 32, r1 ldah r1, 0x1402(r1) // Create lower lw of int_mask lda r1, 0x0100(r1) mtpr r1, pt_intmask // Stash in PALtemp // Unlock a bunch of chip internal IPRs mtpr r31, exc_sum // clear out exeception summary and exc_mask mfpr r31, va // unlock va, mmstat //rig lda r8, <<1@icperr_stat$v_dpe> ! <1@icperr_stat$v_tpe> ! <1@icperr_stat$v_tmr>>(r31) lda r8,(BIT(icperr_stat_v_dpe)|BIT(icperr_stat_v_tpe)|BIT(icperr_stat_v_tmr))(zero) mtpr r8, icperr_stat // Clear Icache parity error & timeout status //orig lda r8, <<1@dcperr_stat$v_lock> ! <1@dcperr_stat$v_seo>>(r31) lda r8,(BIT(dcperr_stat_v_lock)|BIT(dcperr_stat_v_seo))(r31) mtpr r8, dcperr_stat // Clear Dcache parity error status rc r0 // clear intr_flag mtpr r31, pt_trap mfpr r0, pt_misc srl r0, pt_misc_v_switch, r1 blbs r1, sys_reset_switch // see if we got here from swppal // Rest of the "real" reset flow // ASN mtpr r31, dtb_asn mtpr r31, itb_asn lda r1, 0x67(r31) sll r1, hwint_clr_v_pc0c, r1 mtpr r1, hwint_clr // Clear hardware interrupt requests lda r1, BIT(mces_v_dpc)(r31) // 1 in disable processor correctable error mfpr r0, pt1 // get whami insbl r0, 1, r0 // isolate whami in correct pt_misc position or r0, r1, r1 // combine whami and mces mtpr r1, pt_misc // store whami and mces, swap bit clear zapnot r3, 1, r0 // isolate halt code mtpr r0, pt0 // save entry type // Cycle counter or r31, 1, r9 // get a one sll r9, 32, r9 // shift to <32> mtpr r31, cc // clear Cycle Counter mtpr r9, cc_ctl // clear and enable the Cycle Counter mtpr r31, pt_scc // clear System Cycle Counter // Misc PALtemps mtpr r31, maf_mode // no mbox instructions for 3 cycles or r31, 1, r1 // get bogus scbb value mtpr r1, pt_scbb // load scbb mtpr r31, pt_prbr // clear out prbr #ifdef SIMOS // yes, this is ugly, but you figure out a better // way to get the address of the kludge_initial_pcbb // in r1 with an uncooperative assembler --ali br r1, kludge_getpcb_addr br r31, kludge_initial_pcbb kludge_getpcb_addr: ldqp r19, 0(r1) sll r19, 44, r19 srl r19, 44, r19 mulq r19,4,r19 addq r19, r1, r1 addq r1,4,r1 // or zero,kludge_initial_pcbb,r1 // GET_ADDR(r1, (kludge_initial_pcbb-pal_base), r1) #else mfpr r1, pal_base //orig sget_addr r1, (kludge_initial_pcbb-pal$base), r1, verify=0// get address for temp pcbb GET_ADDR(r1, (kludge_initial_pcbb-pal_base), r1) #endif mtpr r1, pt_pcbb // load pcbb lda r1, 2(r31) // get a two sll r1, 32, r1 // gen up upper bits mtpr r1, mvptbr mtpr r1, ivptbr mtpr r31, pt_ptbr // Performance counters mtpr r31, pmctr #if init_cbox != 0 // .if ne init_cbox // Only init the Scache and the Bcache if there have been no previous // cacheable dstream loads or stores. // // Inputs: // r5 - sc_ctl // r6 - bc_ctl // r7 - bc_cnfg ldah r0, 0xfff0(r31) zap r0, 0xE0, r0 // Get Cbox IPR base ldqp r19, ev5__sc_ctl(r0) // read current sc_ctl temp = <<<1@bc_ctl$v_ei_dis_err> + <1@bc_ctl$v_ei_ecc_or_parity> + <1@bc_ctl$v_corr_fill_dat>>@-1> lda r20, temp(r31) // create default bc_ctl (bc disabled, errors disabled, ecc mode) sll r20, 1, r20 temp = 0x017441 // default bc_config get_addr r21, temp, r31 // create default bc_config lda r23, <1@sc_ctl_v_sc_flush>(r31) //set flag to invalidate scache in set_sc_bc_ctl // XXX bugnion pvc$jsr scbcctl, bsr=1 bsr r10, set_sc_bc_ctl update_bc_ctl_shadow r6, r23 // update bc_ctl shadow using r6 as input// r23 gets adjusted impure pointer store_reg1 bc_config, r7, r23, ipr=1 // update bc_config shadow in impure area // .endc #endif // Clear pmctr_ctl in impure area #ifndef SIMOS // can't assemble ??? update_pmctr_ctl r31, r1 // clear pmctr_ctl // r1 trashed #endif ldah r14, 0xfff0(r31) zap r14, 0xE0, r14 // Get Cbox IPR base #ifndef SIMOS ldqp r31, sc_stat(r14) // Clear sc_stat and sc_addr ldqp r31, ei_stat(r14) ldqp r31, ei_stat(r14) // Clear ei_stat, ei_addr, bc_tag_addr, fill_syn #endif GET_IMPURE(r13) stqpc r31, 0(r13) // Clear lock_flag mfpr r0, pt0 // get entry type br r31, sys_enter_console // enter the cosole #endif /* rax_mode == 0 */ //.if ne rax_mode #if rax_mode != 0 // For RAX: // r0 - icsr at first, then used for cbox ipr base offset // r2 - mcsr // r3 - dc_mode // r4 - maf_mode // r5 - sc_ctl // r6 - bc_ctl // r7 - bc_cnfg .globl sys_reset sys_reset: mtpr r31, ev5__dtb_cm // set mbox mode to kernel mtpr r31, ev5__ps // set Ibox mode to kernel - E1 mtpr r0, ev5__icsr // Load ICSR - E1 mtpr r2, ev5__mcsr mfpr r8, pal_base ldah r0, 0xfff0(r31) zap r0, 0xE0, r0 // Get Cbox IPR base mtpr r31, ev5__itb_asn // clear asn - E1 ldqp r19, ev5__sc_ctl(r0) // read current sc_ctl temp = <<<1@bc_ctl$v_ei_dis_err> + <1@bc_ctl$v_ei_ecc_or_parity> + <1@bc_ctl$v_corr_fill_dat>>@-1> lda r20, temp(r31) // create default bc_ctl (bc disabled, errors disabled, ecc mode) sll r20, 1, r20 temp = 0x017441 // default bc_config get_addr r21, temp, r31 // create default bc_config lda r23, <1@sc_ctl_v_sc_flush>(r31) //set flag to invalidate scache in set_sc_bc_ctl // XXX bugnion pvc$jsr scbcctl, bsr=1 bsr r10, set_sc_bc_ctl update_bc_ctl_shadow r6, r2 // initialize bc_ctl shadow// adjusted impure pointer in r2 store_reg1 pmctr_ctl, r31, r2, ipr=1 // clear pmctr_ctl store_reg1 bc_config, r7, r2, ipr=1 // initialize bc_config shadow mtpr r3, ev5__dc_mode // write dc_mode mtpr r31, ev5__dc_flush // flush dcache mtpr r31, ev5__exc_sum // clear exc_sum - E1 mtpr r31, ev5__exc_mask // clear exc_mask - E1 ldah r2, 4(r31) // For EXC_ADDR mtpr r2, ev5__exc_addr // EXC_ADDR to 40000 (hex) mtpr r31, ev5__sirr // Clear SW interrupts (for ISP) mtpr r4, ev5__maf_mode // write maf_mode mtpr r31, ev5__alt_mode // set alt_mode to kernel mtpr r31, ev5__itb_ia // clear ITB - E1 lda r1, 0x1F(r31) // For IPL mtpr r1, ev5__ipl // IPL to 1F mtpr r31, ev5__hwint_clr // clear hardware interrupts mtpr r31, ev5__aster // disable AST interrupts mtpr r31, ev5__astrr // clear AST requests mtpr r31, ev5__dtb_ia // clear dtb nop mtpr r31, pt_trap srl r2, page_offset_size_bits, r9 // Start to make PTE for address 40000 sll r9, 32, r9 lda r9, 0x7F01(r9) // Make PTE, V set, all RE set, all but UWE set nop mtpr r9, dtb_pte // ACORE hack, load TB with 1-1 translation for address 40000 mtpr r2, itb_tag // ACORE hack, load TB with 1-1 translation for address 40000 mtpr r2, dtb_tag mtpr r9, itb_pte and r31, r31, r0 // clear deposited registers, note: r2 already overwritten and r31, r31, r3 and r31, r31, r4 and r31, r31, r5 and r31, r31, r6 and r31, r31, r7 hw_rei //May need to be a rei_stall since //we write to TB's above //However, it currently works ok. (JH) // .endc #endif /*rax_mode != 0 */ // swppal entry // r0 - pt_misc // r17 - new PC // r18 - new PCBB // r19 - new VPTB sys_reset_switch: or r31, 1, r9 sll r9, pt_misc_v_switch, r9 bic r0, r9, r0 // clear switch bit mtpr r0, pt_misc rpcc r1 // get cyccounter ldqp r22, osfpcb_q_fen(r18) // get new fen/pme ldlp r23, osfpcb_l_cc(r18) // get cycle counter ldlp r24, osfpcb_l_asn(r18) // get new asn ldqp r25, osfpcb_q_Mmptr(r18)// get new mmptr sll r25, page_offset_size_bits, r25 // convert pfn to pa mtpr r25, pt_ptbr // load the new mmptr mtpr r18, pt_pcbb // set new pcbb bic r17, 3, r17 // clean use pc mtpr r17, exc_addr // set new pc mtpr r19, mvptbr mtpr r19, ivptbr ldqp r30, osfpcb_q_Usp(r18) // get new usp mtpr r30, pt_usp // save usp sll r24, dtb_asn_v_asn, r8 mtpr r8, dtb_asn sll r24, itb_asn_v_asn, r24 mtpr r24, itb_asn mfpr r25, icsr // get current icsr lda r24, 1(r31) sll r24, icsr_v_fpe, r24 // 1 in icsr position bic r25, r24, r25 // clean out old fpe and r22, 1, r22 // isolate new fen bit sll r22, icsr_v_fpe, r22 or r22, r25, r25 // or in new fpe mtpr r25, icsr // update ibox ipr subl r23, r1, r1 // gen new cc offset insll r1, 4, r1 // << 32 mtpr r1, cc // set new offset or r31, r31, r0 // set success ldqp r30, osfpcb_q_Ksp(r18) // get new ksp mfpr r31, pt0 // stall hw_rei_stall // .sbttl "SYS_MACHINE_CHECK - Machine check PAL" ALIGN_BLOCK //+ //sys$machine_check // A machine_check trap has occurred. The Icache has been flushed. // //- EXPORT(sys_machine_check) // Need to fill up the refill buffer (32 instructions) and // then flush the Icache again. // Also, due to possible 2nd Cbox register file write for // uncorrectable errors, no register file read or write for 7 cycles. nop mtpr r0, pt0 // Stash for scratch -- OK if Cbox overwrites r0 later nop nop nop nop nop nop nop nop // 10 instructions// 5 cycles nop nop nop nop // Register file can now be written lda r0, scb_v_procmchk(r31) // SCB vector mfpr r13, pt_mces // Get MCES sll r0, 16, r0 // Move SCBv to correct position // bis r13, #<1@mces$v_mchk>, r14 // Set MCES bit bis r13, BIT(mces_v_mchk), r14 // Set MCES bit zap r14, 0x3C, r14 // Clear mchk_code word and SCBv word mtpr r14, pt_mces // 20 instructions nop or r14, r0, r14 // Insert new SCB vector lda r0, mchk_c_proc_hrd_error(r31) // MCHK code mfpr r12, exc_addr sll r0, 32, r0 // Move MCHK code to correct position mtpr r4, pt4 or r14, r0, r14 // Insert new MCHK code mtpr r14, pt_misc // Store updated MCES, MCHK code, and SCBv ldah r14, 0xfff0(r31) mtpr r1, pt1 // Stash for scratch - 30 instructions zap r14, 0xE0, r14 // Get Cbox IPR base mtpr r12, pt10 // Stash exc_addr mtpr r31, ic_flush_ctl // Second Icache flush, now it is really flushed. blbs r13, sys_double_machine_check // MCHK halt if double machine check mtpr r6, pt6 mtpr r5, pt5 // Look for the powerfail cases here.... mfpr r4, isr srl r4, isr_v_pfl, r4 blbc r4, sys_mchk_collect_iprs // skip if no powerfail interrupt pending lda r4, 0xffc4(r31) // get GBUS$MISCR address bits sll r4, 24, r4 // shift to proper position ldqp r4, 0(r4) // read GBUS$MISCR srl r4, 5, r4 // isolate bit <5> blbc r4, sys_mchk_collect_iprs // skip if already cleared // No missed CFAIL mchk lda r5, 0xffc7(r31) // get GBUS$SERNUM address bits sll r5, 24, r5 // shift to proper position lda r6, 0x40(r31) // get bit <6> mask ldqp r4, 0(r5) // read GBUS$SERNUM or r4, r6, r6 // set bit <6> stqp r6, 0(r5) // clear GBUS$SERNUM<6> mb mb //+ // Start to collect the IPRs. Common entry point for mchk flows. // // Current state: // pt0 - saved r0 // pt1 - saved r1 // pt4 - saved r4 // pt5 - saved r5 // pt6 - saved r6 // pt10 - saved exc_addr // pt_misc<47:32> - mchk code // pt_misc<31:16> - scb vector // r14 - base of Cbox IPRs in IO space // r0, r1, r4, r5, r6, r12, r13, r25 - available // r8, r9, r10 - available as all loads are physical // MCES is set // //- EXPORT(sys_mchk_collect_iprs) mb // MB before reading Scache IPRs mfpr r1, icperr_stat mfpr r8, dcperr_stat mtpr r31, dc_flush // Flush the Dcache mfpr r31, pt0 // Pad Mbox instructions from dc_flush mfpr r31, pt0 nop nop ldqp r9, sc_addr(r14) // SC_ADDR IPR bis r9, r31, r31 // Touch ld to make sure it completes before // read of SC_STAT ldqp r10, sc_stat(r14) // SC_STAT, also unlocks SC_ADDR ldqp r12, ei_addr(r14) // EI_ADDR IPR ldqp r13, bc_tag_addr(r14) // BC_TAG_ADDR IPR ldqp r0, fill_syn(r14) // FILL_SYN IPR bis r12, r13, r31 // Touch lds to make sure they complete before reading EI_STAT bis r0, r0, r31 // Touch lds to make sure they complete before reading EI_STAT ldqp r25, ei_stat(r14) // EI_STAT, unlock EI_ADDR, BC_TAG_ADDR, FILL_SYN ldqp r31, ei_stat(r14) // Read again to insure it is unlocked //+ // Look for nonretryable cases // In this segment: // r5<0> = 1 means retryable // r4, r6, and r14 are available for scratch // //- bis r31, r31, r5 // Clear local retryable flag srl r25, ei_stat_v_bc_tperr, r25 // Move EI_STAT status bits to low bits lda r4, 1(r31) sll r4, icperr_stat_v_tmr, r4 and r1, r4, r4 // Timeout reset bne r4, sys_cpu_mchk_not_retryable and r8, BIT(dcperr_stat_v_lock), r4 // DCache parity error locked bne r4, sys_cpu_mchk_not_retryable lda r4, 1(r31) sll r4, sc_stat_v_sc_scnd_err, r4 and r10, r4, r4 // 2nd Scache error occurred bne r4, sys_cpu_mchk_not_retryable bis r31, 0xa3, r4 // EI_STAT Bcache Tag Parity Error, Bcache Tag Control // Parity Error, Interface Parity Error, 2nd Error and r25, r4, r4 bne r4, sys_cpu_mchk_not_retryable // bis r31, #<1@>, r4 bis r31, BIT((ei_stat_v_unc_ecc_err-ei_stat_v_bc_tperr)), r4 and r25, r4, r4 // Isolate the Uncorrectable Error Bit // bis r31, #<1@>, r6 bis r31, BIT((ei_stat_v_fil_ird-ei_stat_v_bc_tperr)), r6 // Isolate the Iread bit cmovne r6, 0, r4 // r4 = 0 if IRD or if No Uncorrectable Error bne r4, sys_cpu_mchk_not_retryable lda r4, 7(r31) and r10, r4, r4 // Isolate the Scache Tag Parity Error bits bne r4, sys_cpu_mchk_not_retryable // All Scache Tag PEs are not retryable lda r4, 0x7f8(r31) and r10, r4, r4 // Isolate the Scache Data Parity Error bits srl r10, sc_stat_v_cbox_cmd, r6 and r6, 0x1f, r6 // Isolate Scache Command field subq r6, 1, r6 // Scache Iread command = 1 cmoveq r6, 0, r4 // r4 = 0 if IRD or if No Parity Error bne r4, sys_cpu_mchk_not_retryable // Look for the system unretryable cases here.... mfpr r4, isr // mchk_interrupt pin asserted srl r4, isr_v_mck, r4 blbs r4, sys_cpu_mchk_not_retryable //+ // Look for retryable cases // In this segment: // r5<0> = 1 means retryable // r6 - holds the mchk code // r4 and r14 are available for scratch // //- // Within the chip, the retryable cases are Istream errors lda r4, 3(r31) sll r4, icperr_stat_v_dpe, r4 and r1, r4, r4 cmovne r4, 1, r5 // Retryable if just Icache parity error lda r4, 0x7f8(r31) and r10, r4, r4 // Isolate the Scache Data Parity Error bits srl r10, sc_stat_v_cbox_cmd, r14 and r14, 0x1f, r14 // Isolate Scache Command field subq r14, 1, r14 // Scache Iread command = 1 cmovne r4, 1, r4 // r4 = 1 if Scache data parity error bit set cmovne r14, 0, r4 // r4 = 1 if Scache PE and Iread bis r4, r5, r5 // Accumulate bis r31, BIT((ei_stat_v_unc_ecc_err-ei_stat_v_bc_tperr)), r4 and r25, r4, r4 // Isolate the Uncorrectable Error Bit and r25, BIT((ei_stat_v_fil_ird-ei_stat_v_bc_tperr)), r14 // Isolate the Iread bit cmovne r4, 1, r4 // r4 = 1 if uncorr error cmoveq r14, 0, r4 // r4 = 1 if uncorr and Iread bis r4, r5, r5 // Accumulate mfpr r6, pt_misc extwl r6, 4, r6 // Fetch mchk code bic r6, 1, r6 // Clear flag from interrupt flow cmovne r5, mchk_c_retryable_ird, r6 // Set mchk code // In the system, the retryable cases are ... // (code here handles beh model read NXM) #if beh_model != 0 // .if ne beh_model ldah r4, 0xC000(r31) // Get base of demon space lda r4, 0x550(r4) // Add NXM demon flag offset ldqp r4, 0(r4) // Read the demon register lda r14, mchk_c_read_nxm(r31) cmovlbs r4, r14, r6 // Set mchk code if read NXM cmovlbs r4, 1, r4 bis r4, r5, r5 // Accumulate retry bit #endif //+ // Write the logout frame // // Current state: // r0 - fill_syn // r1 - icperr_stat // r4 - available // r5<0> - retry flag // r6 - mchk code // r8 - dcperr_stat // r9 - sc_addr // r10 - sc_stat // r12 - ei_addr // r13 - bc_tag_addr // r14 - available // r25 - ei_stat (shifted) // pt0 - saved r0 // pt1 - saved r1 // pt4 - saved r4 // pt5 - saved r5 // pt6 - saved r6 // pt10 - saved exc_addr // //- sys_mchk_write_logout_frame: // Get base of the logout area. GET_IMPURE(r14) // addr of per-cpu impure area GET_ADDR(r14,pal_logout_area+mchk_mchk_base,r14) // Write the first 2 quadwords of the logout area: sll r5, 63, r5 // Move retry flag to bit 63 lda r4, mchk_size(r5) // Combine retry flag and frame size stqp r4, mchk_flag(r14) // store flag/frame size lda r4, mchk_sys_base(r31) // sys offset sll r4, 32, r4 lda r4, mchk_cpu_base(r4) // cpu offset stqp r4, mchk_offsets(r14) // store sys offset/cpu offset into logout frame //+ // Write the mchk code to the logout area // Write error IPRs already fetched to the logout area // Restore some GPRs from PALtemps //- mfpr r5, pt5 stqp r6, mchk_mchk_code(r14) mfpr r4, pt4 stqp r1, mchk_ic_perr_stat(r14) mfpr r6, pt6 stqp r8, mchk_dc_perr_stat(r14) mfpr r1, pt1 stqp r9, mchk_sc_addr(r14) stqp r10, mchk_sc_stat(r14) stqp r12, mchk_ei_addr(r14) stqp r13, mchk_bc_tag_addr(r14) stqp r0, mchk_fill_syn(r14) mfpr r0, pt0 sll r25, ei_stat_v_bc_tperr, r25 // Move EI_STAT status bits back to expected position // retrieve lower 28 bits again from ei_stat and restore before storing to logout frame ldah r13, 0xfff0(r31) zapnot r13, 0x1f, r13 ldqp r13, ei_stat(r13) sll r13, 64-ei_stat_v_bc_tperr, r13 srl r13, 64-ei_stat_v_bc_tperr, r13 or r25, r13, r25 stqp r25, mchk_ei_stat(r14) //+ // complete the CPU-specific part of the logout frame //- #ifndef SIMOS // cant' assemble.Where is the macro ? mchk_logout mm_stat mchk_logout va // Unlocks VA and MM_STAT mchk_logout isr mchk_logout icsr mchk_logout pal_base mchk_logout exc_mask mchk_logout exc_sum #endif ldah r13, 0xfff0(r31) zap r13, 0xE0, r13 // Get Cbox IPR base ldqp r13, ld_lock(r13) // Get ld_lock IPR stqp r13, mchk_ld_lock(r14) // and stash it in the frame //+ // complete the PAL-specific part of the logout frame //- #ifdef vms t = 0 .repeat 24 pt_mchk_logout \t t = t + 1 .endr #endif #ifndef SIMOS //can't assemble ? pt_mchk_logout 0 pt_mchk_logout 1 pt_mchk_logout 2 pt_mchk_logout 3 pt_mchk_logout 4 pt_mchk_logout 5 pt_mchk_logout 6 pt_mchk_logout 7 pt_mchk_logout 8 pt_mchk_logout 9 pt_mchk_logout 10 pt_mchk_logout 11 pt_mchk_logout 12 pt_mchk_logout 13 pt_mchk_logout 14 pt_mchk_logout 15 pt_mchk_logout 16 pt_mchk_logout 17 pt_mchk_logout 18 pt_mchk_logout 19 pt_mchk_logout 20 pt_mchk_logout 21 pt_mchk_logout 22 pt_mchk_logout 23 #endif //+ // Log system specific info here //- #if alpha_fw != 0 // .if ne alpha_fw storeTLEP_: lda r13, 0xffc4(r31) // Get GBUS$MISCR address sll r13, 24, r13 ldqp r13, 0(r13) // Read GBUS$MISCR sll r13, 16, r13 // shift up to proper field mfpr r8, pt_whami // get our node id extbl r8, 1, r8 // shift to bit 0 or r13, r8, r13 // merge MISCR and WHAMI stlp r13, mchk$gbus(r14) // write to logout area srl r8, 1, r8 // shift off cpu number Get_TLSB_Node_Address r8,r13 // compute our nodespace address OSFmchk_TLEPstore tldev, tlsb=1 OSFmchk_TLEPstore tlber, tlsb=1, clr=1 OSFmchk_TLEPstore tlcnr, tlsb=1 OSFmchk_TLEPstore tlvid, tlsb=1 OSFmchk_TLEPstore tlesr0, tlsb=1, clr=1 OSFmchk_TLEPstore tlesr1, tlsb=1, clr=1 OSFmchk_TLEPstore tlesr2, tlsb=1, clr=1 OSFmchk_TLEPstore tlesr3, tlsb=1, clr=1 OSFmchk_TLEPstore tlmodconfig OSFmchk_TLEPstore tlepaerr, clr=1 OSFmchk_TLEPstore tlepderr, clr=1 OSFmchk_TLEPstore tlepmerr, clr=1 OSFmchk_TLEPstore tlintrmask0 OSFmchk_TLEPstore tlintrmask1 OSFmchk_TLEPstore tlintrsum0 OSFmchk_TLEPstore tlintrsum1 OSFmchk_TLEPstore tlep_vmg // .endc #endif /*alpha_fw != 0 */ // Unlock IPRs lda r8, (BIT(dcperr_stat_v_lock)|BIT(dcperr_stat_v_seo))(r31) mtpr r8, dcperr_stat // Clear Dcache parity error status lda r8, (BIT(icperr_stat_v_dpe)|BIT(icperr_stat_v_tpe)|BIT(icperr_stat_v_tmr))(r31) mtpr r8, icperr_stat // Clear Icache parity error & timeout status 1: ldqp r8, mchk_ic_perr_stat(r14) // get ICPERR_STAT value GET_ADDR(r0,0x1800,r31) // get ICPERR_STAT value and r0, r8, r0 // compare beq r0, 2f // check next case if nothing set lda r0, mchk_c_retryable_ird(r31) // set new MCHK code br r31, do_670 // setup new vector 2: ldqp r8, mchk_dc_perr_stat(r14) // get DCPERR_STAT value GET_ADDR(r0,0x3f,r31) // get DCPERR_STAT value and r0, r8, r0 // compare beq r0, 3f // check next case if nothing set lda r0, mchk_c_dcperr(r31) // set new MCHK code br r31, do_670 // setup new vector 3: ldqp r8, mchk_sc_stat(r14) // get SC_STAT value GET_ADDR(r0,0x107ff,r31) // get SC_STAT value and r0, r8, r0 // compare beq r0, 4f // check next case if nothing set lda r0, mchk_c_scperr(r31) // set new MCHK code br r31, do_670 // setup new vector 4: ldqp r8, mchk_ei_stat(r14) // get EI_STAT value GET_ADDR(r0,0x30000000,r31) // get EI_STAT value and r0, r8, r0 // compare beq r0, 5f // check next case if nothing set lda r0, mchk_c_bcperr(r31) // set new MCHK code br r31, do_670 // setup new vector 5: ldlp r8, mchk_tlber(r14) // get TLBER value GET_ADDR(r0,0xfe01,r31) // get high TLBER mask value sll r0, 16, r0 // shift into proper position GET_ADDR(r1,0x03ff,r31) // get low TLBER mask value or r0, r1, r0 // merge mask values and r0, r8, r0 // compare beq r0, 6f // check next case if nothing set GET_ADDR(r0, 0xfff0, r31) // set new MCHK code br r31, do_660 // setup new vector 6: ldlp r8, mchk_tlepaerr(r14) // get TLEPAERR value GET_ADDR(r0,0xff7f,r31) // get TLEPAERR mask value and r0, r8, r0 // compare beq r0, 7f // check next case if nothing set GET_ADDR(r0, 0xfffa, r31) // set new MCHK code br r31, do_660 // setup new vector 7: ldlp r8, mchk_tlepderr(r14) // get TLEPDERR value GET_ADDR(r0,0x7,r31) // get TLEPDERR mask value and r0, r8, r0 // compare beq r0, 8f // check next case if nothing set GET_ADDR(r0, 0xfffb, r31) // set new MCHK code br r31, do_660 // setup new vector 8: ldlp r8, mchk_tlepmerr(r14) // get TLEPMERR value GET_ADDR(r0,0x3f,r31) // get TLEPMERR mask value and r0, r8, r0 // compare beq r0, 9f // check next case if nothing set GET_ADDR(r0, 0xfffc, r31) // set new MCHK code br r31, do_660 // setup new vector 9: ldqp r8, mchk_ei_stat(r14) // get EI_STAT value GET_ADDR(r0,0xb,r31) // get EI_STAT mask value sll r0, 32, r0 // shift to upper lw and r0, r8, r0 // compare beq r0, 1f // check next case if nothing set GET_ADDR(r0,0xfffd,r31) // set new MCHK code br r31, do_660 // setup new vector 1: ldlp r8, mchk_tlepaerr(r14) // get TLEPAERR value GET_ADDR(r0,0x80,r31) // get TLEPAERR mask value and r0, r8, r0 // compare beq r0, cont_logout_frame // check next case if nothing set GET_ADDR(r0, 0xfffe, r31) // set new MCHK code br r31, do_660 // setup new vector do_670: lda r8, scb_v_procmchk(r31) // SCB vector br r31, do_6x0_cont do_660: lda r8, scb_v_sysmchk(r31) // SCB vector do_6x0_cont: sll r8, 16, r8 // shift to proper position mfpr r1, pt_misc // fetch current pt_misc GET_ADDR(r4,0xffff, r31) // mask for vector field sll r4, 16, r4 // shift to proper position bic r1, r4, r1 // clear out old vector field or r1, r8, r1 // merge in new vector mtpr r1, pt_misc // save new vector field stlp r0, mchk_mchk_code(r14) // save new mchk code cont_logout_frame: // Restore some GPRs from PALtemps mfpr r0, pt0 mfpr r1, pt1 mfpr r4, pt4 mfpr r12, pt10 // fetch original PC blbs r12, sys_machine_check_while_in_pal // MCHK halt if machine check in pal //XXXbugnion pvc_jsr armc, bsr=1 bsr r12, sys_arith_and_mchk // go check for and deal with arith trap mtpr r31, exc_sum // Clear Exception Summary mfpr r25, pt10 // write exc_addr after arith_and_mchk to pickup new pc stqp r25, mchk_exc_addr(r14) //+ // Set up the km trap //- sys_post_mchk_trap: mfpr r25, pt_misc // Check for flag from mchk interrupt extwl r25, 4, r25 blbs r25, sys_mchk_stack_done // Stack from already pushed if from interrupt flow bis r14, r31, r12 // stash pointer to logout area mfpr r14, pt10 // get exc_addr sll r11, 63-3, r25 // get mode to msb bge r25, 3f mtpr r31, dtb_cm mtpr r31, ev5__ps mtpr r30, pt_usp // save user stack mfpr r30, pt_ksp 3: lda sp, 0-osfsf_c_size(sp) // allocate stack space nop stq r18, osfsf_a2(sp) // a2 stq r11, osfsf_ps(sp) // save ps stq r14, osfsf_pc(sp) // save pc mfpr r25, pt_entint // get the VA of the interrupt routine stq r16, osfsf_a0(sp) // a0 lda r16, osfint_c_mchk(r31) // flag as mchk in a0 stq r17, osfsf_a1(sp) // a1 mfpr r17, pt_misc // get vector stq r29, osfsf_gp(sp) // old gp mtpr r25, exc_addr // or r31, 7, r11 // get new ps (km, high ipl) subq r31, 1, r18 // get a -1 extwl r17, 2, r17 // a1 <- interrupt vector bis r31, ipl_machine_check, r25 mtpr r25, ipl // Set internal ipl srl r18, 42, r18 // shift off low bits of kseg addr sll r18, 42, r18 // shift back into position mfpr r29, pt_kgp // get the kern r29 or r12, r18, r18 // EV4 algorithm - pass pointer to mchk frame as kseg address hw_rei_spe // out to interrupt dispatch routine //+ // The stack is pushed. Load up a0,a1,a2 and vector via entInt // //- ALIGN_BRANCH sys_mchk_stack_done: lda r16, osfint_c_mchk(r31) // flag as mchk/crd in a0 lda r17, scb_v_sysmchk(r31) // a1 <- interrupt vector subq r31, 1, r18 // get a -1 mfpr r25, pt_entInt srl r18, 42, r18 // shift off low bits of kseg addr mtpr r25, exc_addr // load interrupt vector sll r18, 42, r18 // shift back into position or r14, r18, r18 // EV4 algorithm - pass pointer to mchk frame as kseg address hw_rei_spe // done ALIGN_BRANCH sys_cpu_mchk_not_retryable: mfpr r6, pt_misc extwl r6, 4, r6 // Fetch mchk code br r31, sys_mchk_write_logout_frame // //+ //sys$double_machine_check - a machine check was started, but MCES was // already set. We will now double machine check halt. // // pt0 - old R0 // //+ EXPORT(sys_double_machine_check) #ifndef SIMOS pvc$jsr updpcb, bsr=1 bsr r0, pal_update_pcb // update the pcb #endif lda r0, hlt_c_dbl_mchk(r31) br r31, sys_enter_console //+ //sys$machine_check_while_in_pal - a machine check was started, exc_addr points to // a PAL PC. We will now machine check halt. // // pt0 - old R0 // //+ sys_machine_check_while_in_pal: stqp r12, mchk_exc_addr(r14) // exc_addr has not yet been written #ifndef SIMOS pvc$jsr updpcb, bsr=1 bsr r0, pal_update_pcb // update the pcb #endif lda r0, hlt_c_mchk_from_pal(r31) br r31, sys_enter_console //ARITH and MCHK // Check for arithmetic errors and build trap frame, // but don't post the trap. // on entry: // pt10 - exc_addr // r12 - return address // r14 - logout frame pointer // r13 - available // r8,r9,r10 - available except across stq's // pt0,1,6 - available // // on exit: // pt10 - new exc_addr // r17 = exc_mask // r16 = exc_sum // r14 - logout frame pointer // ALIGN_BRANCH sys_arith_and_mchk: mfpr r13, ev5__exc_sum srl r13, exc_sum_v_swc, r13 bne r13, handle_arith_and_mchk // XXX bugnion pvc$jsr armc, bsr=1, dest=1 ret r31, (r12) // return if no outstanding arithmetic error handle_arith_and_mchk: mtpr r31, ev5__dtb_cm // Set Mbox current mode to kernel - // no virt ref for next 2 cycles mtpr r14, pt0 mtpr r1, pt1 // get a scratch reg and r11, osfps_m_mode, r1 // get mode bit bis r11, r31, r25 // save ps beq r1, 1f // if zero we are in kern now bis r31, r31, r25 // set the new ps mtpr r30, pt_usp // save user stack mfpr r30, pt_ksp // get kern stack 1: mfpr r14, exc_addr // get pc into r14 in case stack writes fault lda sp, 0-osfsf_c_size(sp) // allocate stack space mtpr r31, ev5__ps // Set Ibox current mode to kernel mfpr r1, pt_entArith stq r14, osfsf_pc(sp) // save pc stq r17, osfsf_a1(sp) mfpr r17, ev5__exc_mask // Get exception register mask IPR - no mtpr exc_sum in next cycle stq r29, osfsf_gp(sp) stq r16, osfsf_a0(sp) // save regs bis r13, r31, r16 // move exc_sum to r16 stq r18, osfsf_a2(sp) stq r11, osfsf_ps(sp) // save ps mfpr r29, pt_kgp // get the kern gp mfpr r14, pt0 // restore logout frame pointer from pt0 bis r25, r31, r11 // set new ps mtpr r1, pt10 // Set new PC mfpr r1, pt1 // XXX bugnion pvc$jsr armc, bsr=1, dest=1 ret r31, (r12) // return if no outstanding arithmetic error // .sbttl "SYS$ENTER_CONSOLE - Common PALcode for ENTERING console" ALIGN_BLOCK // SYS$enter_console // // Entry: // Entered when PAL wants to enter the console. // usually as the result of a HALT instruction or button, // or catastrophic error. // // Regs on entry... // // R0 = halt code // pt0 <- r0 // // Function: // // Save all readable machine state, and "call" the console // // Returns: // // // Notes: // // In these routines, once the save state routine has been executed, // the remainder of the registers become scratchable, as the only // "valid" copy of them is the "saved" copy. // // Any registers or PTs that are modified before calling the save // routine will have there data lost. The code below will save all // state, but will loose pt 0,4,5. // //- EXPORT(sys_enter_console) mtpr r1, pt4 mtpr r3, pt5 #ifdef SIMOS subq r31, 1, r1 sll r1, 42, r1 ldah r1, 1(r1) #else /* SIMOS */ lda r3, pal_enter_console_ptr(r31) //find stored vector ldqp r1, 0(r3) #endif /* SIMOS */ #ifdef SIMOS /* taken from scrmax, seems like the obvious thing to do */ mtpr r1, exc_addr mfpr r1, pt4 mfpr r3, pt5 STALL STALL hw_rei_stall #else pvc$violate 1007 jmp r31, (r1) // off to common routine #endif // .sbttl "SYS$EXIT_CONSOLE - Common PALcode for ENTERING console" //+ // sys$exit_console // // Entry: // Entered when console wants to reenter PAL. // usually as the result of a CONTINUE. // // // Regs' on entry... // // // Function: // // Restore all readable machine state, and return to user code. // // // //- ALIGN_BLOCK sys_exit_console: //Disable physical mode: #if enable_physical_console != 0 // .if ne enable_physical_console mfpr r25, pt_ptbr bic r25, 1, r25 // clear physical console flag mtpr r25, pt_ptbr #endif GET_IMPURE(r1) // clear lock and intr_flags prior to leaving console rc r31 // clear intr_flag // lock flag cleared by restore_state #ifndef SIMOS pvc$jsr rststa, bsr=1 bsr r3, pal_restore_state // go restore all state // note, R1 and R3 are NOT restored // by restore_state. #endif // TB's have been flushed ldqp r3, (cns_gpr+(8*3))(r1) // restore r3 ldqp r1, (cns_gpr+8)(r1) // restore r1 hw_rei_stall // back to user #if turbo_pcia_intr_fix != 0 // .if ne turbo_pcia_intr_fix check_pcia_intr: mfpr r14, pt14 // fetch saved PCIA interrupt info beq r14, check_done // don't bother checking if no info mfpr r13, ipl // check the current IPL bic r13, 3, r25 // isolate ipl<5:2> cmpeq r25, 0x14, r25 // is it an I/O interrupt? beq r25, check_done // no, return and r13, 3, r25 // get I/O interrupt index extbl r14, r25, r13 // extract info for this interrupt beq r13, check_done // if no info, return // This is an RTI from a PCIA interrupt lda r12, 1(r31) // get initial bit mask sll r12, r25, r25 // shift to select interrupt index zap r14, r25, r14 // clear out info from this interrupt mtpr r14, pt14 // and save it and r13, 3, r25 // isolate HPC field subq r25, 1, r25 // subtract 1 to get HPC number srl r13, 2, r13 // generate base register address sll r13, 6, r13 // get slot/hose address bits lda r13, 0x38(r13) // insert other high bits sll r13, 28, r13 // shift high bits into position // Read the IPROGx register sll r25, 21, r14 // HPC address bit position or r13, r14, r14 // add in upper bits lda r14, 0x400(r14) // add in lower bits ldqp r14, 0(r14) // read IPROG srl r14, 4, r12 // check the In Progress bit blbc r12, 1f // skip if none in progress and r14, 0xf, r14 // isolate interrupt source lda r12, 1(r31) // make initial mask sll r12, r14, r14 // shift to make new intr source mask br r31, 2f // Write the SMPLIRQx register 1: or r31, r31, r14 // default interrupt source mask 2: GET_ADDR(r12, 0xffff, r31) // default SMPLIRQx data bic r12, r14, r12 // clear any interrupts in progres //orig lda r14, <0xbffc@-2>(r31) // get register address bits lda r14,(0xbffc>>2)(r31) sll r14, 10, r14 // shift into position or r14, r13, r14 // add in upper bits sll r25, 8, r25 // shift HPC number into position or r14, r25, r14 // add in lower bits stqp r12, 0(r14) // write SMPLIRQx register mb ldqp r12, 0(r14) // read it back bis r12, r12, r12 // touch register to insure completion check_done: // do these now and return lda r25, osfsf_c_size(sp) // get updated sp bis r25, r31, r14 // touch r14,r25 to stall mf exc_addr br r31, pcia_check_return #endif // .sbttl KLUDGE_INITIAL_PCBB - PCB for Boot use only ALIGN_128 .globl kludge_initial_pcbb kludge_initial_pcbb: // PCB is 128 bytes long // .repeat 16 // .quad 0 // .endr nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop // .sbttl "SET_SC_BC_CTL subroutine" // // Subroutine to set the SC_CTL, BC_CONFIG, and BC_CTL registers and flush the Scache // There must be no outstanding memory references -- istream or dstream -- when // these registers are written. EV5 prefetcher is difficult to turn off. So, // this routine needs to be exactly 32 instructions long// the final jmp must // be in the last octaword of a page (prefetcher doesn't go across page) // // // Register expecations: // r0 base address of CBOX iprs // r5 value to set sc_ctl to (flush bit is added in) // r6 value to set bc_ctl to // r7 value to set bc_config to // r10 return address // r19 old sc_ctl value // r20 old value of bc_ctl // r21 old value of bc_config // r23 flush scache flag // Register usage: // r17 sc_ctl with flush bit cleared // r22 loop address // // #ifndef SIMOS align_page <32*4> // puts start of routine at next page boundary minus 32 longwords. #endif set_sc_bc_ctl: #ifndef SIMOS br r22, sc_ctl_loop //this branch must be in the same 4 instruction block as it's dest sc_ctl_loop: // XXX bugnion pvc$jsr scloop, dest=1 mb mb bis r5, r23, r5 //r5 <- same sc_ctl with flush bit set (if flag set in r23) stqp r19, ev5__sc_ctl(r0) // write sc_ctl stqp r20, ev5__bc_ctl(r0) // write bc_ctl bis r31, r6, r20 // update r20 with new bc_ctl for 2nd time through loop stqp r21, bc_config(r0) // write bc_config register bis r31, r7, r21 // update r21 with new bc_config for 2nd time through loop bic r19, BIT(sc_ctl_v_sc_flush), r17 //r17 <- same sc_ctl without flush bit set //NOTE: only works because flush bit is in lower 16 bits wmb // don't merge with other writes stqp r17, ev5__sc_ctl(r0) // write sc_ctl without flush bit ldqp r17, ev5__sc_ctl(r0) // read sc_ctl bis r17, r17, r17 // stall until the data comes back bis r31, r5, r19 // update r19 with new sc_ctl for 2nd time through loop // fill with requisite number of nops (unops ok) to make exactly 32 instructions in loop t = 0 .repeat 15 unop t = t + 1 .endr $opdef mnemonic= myjmp, - format= , - encoding= <26:31=0x1A, 21:25=%OP1,16:20=%OP2,14:15=0x00,0:13=%op3> // XXXbugnion pvc$jsr scloop myjmp r22,r22,sc_ctl_loop // first time, jump to sc_ctl_loop (hint will cause prefetcher to go to loop instead // of straight) // r22 gets sc_ctl_done // 2nd time, code continues at sc_ctl_done (I hope) sc_ctl_done: // XXX bugnion pvc$jsr scloop, dest=1 // XXX bugnion pvc$jsr scbcctl #endif /*SIMOS*/ ret r31, (r10) // return to where we came from .end