10Sstevel@tonic-gate/* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 52973Sgovinda * Common Development and Distribution License (the "License"). 62973Sgovinda * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate/* 2210271SJason.Beloro@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate#if defined(lint) 270Sstevel@tonic-gate#include <sys/types.h> 280Sstevel@tonic-gate#include <sys/thread.h> 290Sstevel@tonic-gate#else /* lint */ 300Sstevel@tonic-gate#include "assym.h" 310Sstevel@tonic-gate#endif /* lint */ 320Sstevel@tonic-gate 330Sstevel@tonic-gate#include <sys/asm_linkage.h> 340Sstevel@tonic-gate#include <sys/machthread.h> 350Sstevel@tonic-gate#include <sys/machcpuvar.h> 360Sstevel@tonic-gate#include <sys/intreg.h> 370Sstevel@tonic-gate#include <sys/cmn_err.h> 380Sstevel@tonic-gate#include <sys/ftrace.h> 390Sstevel@tonic-gate#include <sys/machasi.h> 401457Swh94709#include <sys/scb.h> 410Sstevel@tonic-gate#include <sys/error.h> 424528Spaulsan#include <sys/mmu.h> 434528Spaulsan#include <vm/hat_sfmmu.h> 440Sstevel@tonic-gate#define INTR_REPORT_SIZE 64 450Sstevel@tonic-gate 460Sstevel@tonic-gate#ifdef TRAPTRACE 470Sstevel@tonic-gate#include <sys/traptrace.h> 480Sstevel@tonic-gate#endif /* TRAPTRACE */ 490Sstevel@tonic-gate 500Sstevel@tonic-gate#if defined(lint) 510Sstevel@tonic-gate 520Sstevel@tonic-gatevoid 530Sstevel@tonic-gatecpu_mondo(void) 540Sstevel@tonic-gate{} 550Sstevel@tonic-gate 560Sstevel@tonic-gate#else /* lint */ 570Sstevel@tonic-gate 580Sstevel@tonic-gate 590Sstevel@tonic-gate/* 600Sstevel@tonic-gate * (TT 0x7c, TL>0) CPU Mondo Queue Handler 610Sstevel@tonic-gate * Globals are the Interrupt Globals. 620Sstevel@tonic-gate */ 630Sstevel@tonic-gate ENTRY_NP(cpu_mondo) 640Sstevel@tonic-gate ! 650Sstevel@tonic-gate ! Register Usage:- 660Sstevel@tonic-gate ! %g5 PC for fasttrap TL>0 handler 670Sstevel@tonic-gate ! %g1 arg 1 680Sstevel@tonic-gate ! %g2 arg 2 690Sstevel@tonic-gate ! %g3 queue base VA 700Sstevel@tonic-gate ! %g4 queue size mask 710Sstevel@tonic-gate ! %g6 head ptr 720Sstevel@tonic-gate ! %g7 tail ptr 730Sstevel@tonic-gate mov CPU_MONDO_Q_HD, %g3 740Sstevel@tonic-gate ldxa [%g3]ASI_QUEUE, %g6 ! %g6 = head ptr 750Sstevel@tonic-gate mov CPU_MONDO_Q_TL, %g4 760Sstevel@tonic-gate ldxa [%g4]ASI_QUEUE, %g7 ! %g7 = tail ptr 770Sstevel@tonic-gate cmp %g6, %g7 784528Spaulsan be,pn %xcc, 3f ! head == tail 790Sstevel@tonic-gate nop 800Sstevel@tonic-gate 810Sstevel@tonic-gate CPU_ADDR(%g1,%g2) 820Sstevel@tonic-gate add %g1, CPU_MCPU, %g2 830Sstevel@tonic-gate ldx [%g2 + MCPU_CPU_Q_BASE], %g3 ! %g3 = queue base PA 840Sstevel@tonic-gate ldx [%g2 + MCPU_CPU_Q_SIZE], %g4 ! queue size 850Sstevel@tonic-gate sub %g4, 1, %g4 ! %g4 = queue size mask 860Sstevel@tonic-gate 870Sstevel@tonic-gate ! Load interrupt receive data registers 1 and 2 to fetch 880Sstevel@tonic-gate ! the arguments for the fast trap handler. 890Sstevel@tonic-gate ! 900Sstevel@tonic-gate ! XXX - Since the data words in the interrupt report are not defined yet 910Sstevel@tonic-gate ! we assume that the consective words contain valid data and preserve 920Sstevel@tonic-gate ! sun4u's xcall mondo arguments. 930Sstevel@tonic-gate ! Register usage: 940Sstevel@tonic-gate ! %g5 PC for fasttrap TL>0 handler 950Sstevel@tonic-gate ! %g1 arg 1 960Sstevel@tonic-gate ! %g2 arg 2 970Sstevel@tonic-gate 980Sstevel@tonic-gate ldxa [%g3 + %g6]ASI_MEM, %g5 ! get PC from q base + head 990Sstevel@tonic-gate add %g6, 0x8, %g6 ! inc head 1000Sstevel@tonic-gate ldxa [%g3 + %g6]ASI_MEM, %g1 ! read data word 1 1010Sstevel@tonic-gate add %g6, 0x8, %g6 ! inc head 1020Sstevel@tonic-gate ldxa [%g3 + %g6]ASI_MEM, %g2 ! read data word 2 1030Sstevel@tonic-gate add %g6, (INTR_REPORT_SIZE - 16) , %g6 ! inc head to next record 1040Sstevel@tonic-gate and %g6, %g4, %g6 ! and size mask for wrap around 1050Sstevel@tonic-gate mov CPU_MONDO_Q_HD, %g3 1060Sstevel@tonic-gate stxa %g6, [%g3]ASI_QUEUE ! store head pointer 1070Sstevel@tonic-gate membar #Sync 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate#ifdef TRAPTRACE 1100Sstevel@tonic-gate TRACE_PTR(%g4, %g6) 111*11172SHaik.Aftandilian@Sun.COM GET_TRACE_TICK(%g6, %g3) 1120Sstevel@tonic-gate stxa %g6, [%g4 + TRAP_ENT_TICK]%asi 1130Sstevel@tonic-gate TRACE_SAVE_TL_GL_REGS(%g4, %g6) 1140Sstevel@tonic-gate rdpr %tt, %g6 1150Sstevel@tonic-gate stha %g6, [%g4 + TRAP_ENT_TT]%asi 1160Sstevel@tonic-gate rdpr %tpc, %g6 1170Sstevel@tonic-gate stna %g6, [%g4 + TRAP_ENT_TPC]%asi 1180Sstevel@tonic-gate rdpr %tstate, %g6 1190Sstevel@tonic-gate stxa %g6, [%g4 + TRAP_ENT_TSTATE]%asi 1200Sstevel@tonic-gate stna %sp, [%g4 + TRAP_ENT_SP]%asi 1210Sstevel@tonic-gate stna %g5, [%g4 + TRAP_ENT_TR]%asi ! pc of the TL>0 handler 1220Sstevel@tonic-gate stna %g1, [%g4 + TRAP_ENT_F1]%asi ! arg1 1230Sstevel@tonic-gate stna %g2, [%g4 + TRAP_ENT_F3]%asi ! arg2 1240Sstevel@tonic-gate mov CPU_MONDO_Q_HD, %g6 1250Sstevel@tonic-gate ldxa [%g6]ASI_QUEUE, %g6 ! new head offset 1260Sstevel@tonic-gate stna %g6, [%g4 + TRAP_ENT_F2]%asi 1270Sstevel@tonic-gate stna %g7, [%g4 + TRAP_ENT_F4]%asi ! tail offset 1280Sstevel@tonic-gate TRACE_NEXT(%g4, %g6, %g3) 1290Sstevel@tonic-gate#endif /* TRAPTRACE */ 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate /* 1320Sstevel@tonic-gate * For now catch invalid PC being passed via cpu_mondo queue 1330Sstevel@tonic-gate */ 1340Sstevel@tonic-gate set KERNELBASE, %g4 1350Sstevel@tonic-gate cmp %g5, %g4 1364528Spaulsan bl,pn %xcc, 2f ! branch if bad %pc 1374528Spaulsan nop 1384528Spaulsan 1390Sstevel@tonic-gate 1404528Spaulsan /* 1414528Spaulsan * If this platform supports shared contexts and we are jumping 1424528Spaulsan * to OBP code, then we need to invalidate both contexts to prevent OBP 1434528Spaulsan * from corrupting the shared context registers. 1444528Spaulsan * 1454528Spaulsan * If shared contexts are not supported then the next two instructions 1464528Spaulsan * will be patched with: 1474528Spaulsan * 1484528Spaulsan * jmp %g5 1494528Spaulsan * nop 1504528Spaulsan * 1514528Spaulsan */ 1524528Spaulsan .global sfmmu_shctx_cpu_mondo_patch 1534528Spaulsansfmmu_shctx_cpu_mondo_patch: 1544528Spaulsan set OFW_START_ADDR, %g4 ! Check if this a call into OBP? 1554528Spaulsan cmp %g5, %g4 1564528Spaulsan bl,pt %xcc, 1f 1574528Spaulsan nop 1584528Spaulsan set OFW_END_ADDR, %g4 1594528Spaulsan cmp %g5, %g4 1604528Spaulsan bg,pn %xcc, 1f 1614528Spaulsan nop 1624528Spaulsan mov MMU_PCONTEXT, %g3 1634528Spaulsan ldxa [%g3]ASI_MMU_CTX, %g4 1644528Spaulsan cmp %g4, INVALID_CONTEXT ! Check if we are in kernel mode 1654528Spaulsan ble,pn %xcc, 1f ! or the primary context is invalid 1664528Spaulsan nop 1674528Spaulsan set INVALID_CONTEXT, %g4 ! Invalidate contexts - compatability 1684528Spaulsan stxa %g4, [%g3]ASI_MMU_CTX ! mode ensures shared contexts are also 1694528Spaulsan mov MMU_SCONTEXT, %g3 ! invalidated. 1704528Spaulsan stxa %g4, [%g3]ASI_MMU_CTX 1714528Spaulsan membar #Sync 1724528Spaulsan mov %o0, %g3 ! save output regs 1734528Spaulsan mov %o1, %g4 1744528Spaulsan mov %o5, %g6 1754528Spaulsan clr %o0 ! Invalidate tsbs, set ntsb = 0 1764528Spaulsan clr %o1 ! and HV_TSB_INFO_PA = 0 1774528Spaulsan mov MMU_TSB_CTXNON0, %o5 1784528Spaulsan ta FAST_TRAP ! set TSB info for user process 1794528Spaulsan brnz,a,pn %o0, ptl1_panic 1804528Spaulsan mov PTL1_BAD_HCALL, %g1 1814528Spaulsan mov %g3, %o0 ! restore output regs 1824528Spaulsan mov %g4, %o1 1834528Spaulsan mov %g6, %o5 1844528Spaulsan1: 1850Sstevel@tonic-gate jmp %g5 ! jump to traphandler 1860Sstevel@tonic-gate nop 1874528Spaulsan2: 1880Sstevel@tonic-gate ! invalid trap handler, discard it for now 1890Sstevel@tonic-gate set cpu_mondo_inval, %g4 1900Sstevel@tonic-gate ldx [%g4], %g5 1910Sstevel@tonic-gate inc %g5 1920Sstevel@tonic-gate stx %g5, [%g4] 1934528Spaulsan3: 1940Sstevel@tonic-gate retry 1950Sstevel@tonic-gate /* Never Reached */ 1960Sstevel@tonic-gate SET_SIZE(cpu_mondo) 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate#endif /* lint */ 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate#if defined(lint) 2010Sstevel@tonic-gate 2020Sstevel@tonic-gatevoid 2030Sstevel@tonic-gatedev_mondo(void) 2040Sstevel@tonic-gate{} 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate#else /* lint */ 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate/* 2100Sstevel@tonic-gate * (TT 0x7d, TL>0) Dev Mondo Queue Handler 2110Sstevel@tonic-gate * Globals are the Interrupt Globals. 2120Sstevel@tonic-gate * We only process one interrupt at a time causing us to keep 2130Sstevel@tonic-gate * taking this trap till the queue is empty. 2140Sstevel@tonic-gate * We really should drain the whole queue for better performance 2150Sstevel@tonic-gate * but this will do for now. 2160Sstevel@tonic-gate */ 2170Sstevel@tonic-gate ENTRY_NP(dev_mondo) 2180Sstevel@tonic-gate ! 2190Sstevel@tonic-gate ! Register Usage:- 2200Sstevel@tonic-gate ! %g5 PC for fasttrap TL>0 handler 2210Sstevel@tonic-gate ! %g1 arg 1 2220Sstevel@tonic-gate ! %g2 arg 2 2230Sstevel@tonic-gate ! %g3 queue base PA 2240Sstevel@tonic-gate ! %g4 queue size mask 2250Sstevel@tonic-gate ! %g6 head ptr 2260Sstevel@tonic-gate ! %g7 tail ptr 2270Sstevel@tonic-gate mov DEV_MONDO_Q_HD, %g3 2280Sstevel@tonic-gate ldxa [%g3]ASI_QUEUE, %g6 ! %g6 = head ptr 2290Sstevel@tonic-gate mov DEV_MONDO_Q_TL, %g4 2300Sstevel@tonic-gate ldxa [%g4]ASI_QUEUE, %g7 ! %g7 = tail ptr 2310Sstevel@tonic-gate cmp %g6, %g7 2320Sstevel@tonic-gate be,pn %xcc, 0f ! head == tail 2330Sstevel@tonic-gate nop 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate CPU_ADDR(%g1,%g2) 2360Sstevel@tonic-gate add %g1, CPU_MCPU, %g2 2370Sstevel@tonic-gate ldx [%g2 + MCPU_DEV_Q_BASE], %g3 ! %g3 = queue base PA 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate ! Register usage: 2400Sstevel@tonic-gate ! %g5 - inum 2410Sstevel@tonic-gate ! %g1 - cpu struct pointer used below in TRAPTRACE 2420Sstevel@tonic-gate ! 2430Sstevel@tonic-gate ldxa [%g3 + %g6]ASI_MEM, %g5 ! get inum from q base + head 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate ! 2460Sstevel@tonic-gate ! We verify that inum is valid ( < MAXVNUM). If it is greater 2472973Sgovinda ! than MAXVNUM, we let setvecint_tl1 take care of it. 2480Sstevel@tonic-gate ! 2490Sstevel@tonic-gate set MAXIVNUM, %g4 2500Sstevel@tonic-gate cmp %g5, %g4 2510Sstevel@tonic-gate bgeu,a,pn %xcc, 1f 2520Sstevel@tonic-gate ldx [%g2 + MCPU_DEV_Q_SIZE], %g4 ! queue size - delay slot 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate ! 2550Sstevel@tonic-gate ! Copy 64-byte payload to the *iv_payload if it is not NULL 2560Sstevel@tonic-gate ! 2572973Sgovinda set intr_vec_table, %g1 ! %g1 = intr_vec_table 2582973Sgovinda sll %g5, CPTRSHIFT, %g7 ! %g7 = offset to inum entry 2592973Sgovinda ! in the intr_vec_table 2602973Sgovinda add %g1, %g7, %g7 ! %g7 = &intr_vec_table[inum] 2612973Sgovinda ldn [%g7], %g1 ! %g1 = ptr to intr_vec_t (iv) 2623200Sgovinda 2633200Sgovinda ! 2643200Sgovinda ! Verify the pointer to first intr_vec_t for a given inum and 2653200Sgovinda ! it should not be NULL. If this pointer is NULL, then it is a 2663200Sgovinda ! spurious interrupt. In this case, just call setvecint_tl1 and 2673200Sgovinda ! it will handle this spurious interrupt. 2683200Sgovinda ! 2693200Sgovinda brz,a,pn %g1, 1f ! if %g1 is NULL 2703200Sgovinda ldx [%g2 + MCPU_DEV_Q_SIZE], %g4 ! queue size - delay slot 2713200Sgovinda 2722973Sgovinda ldx [%g1 + IV_PAYLOAD_BUF], %g1 ! %g1 = iv->iv_payload_buf 2730Sstevel@tonic-gate brz,a,pt %g1, 1f ! if it is NULL 2740Sstevel@tonic-gate ldx [%g2 + MCPU_DEV_Q_SIZE], %g4 ! queue size - delay slot 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate ! 2770Sstevel@tonic-gate ! Now move 64 byte payload from mondo queue to buf 2780Sstevel@tonic-gate ! 2790Sstevel@tonic-gate mov %g6, %g7 ! %g7 = head ptr 2800Sstevel@tonic-gate ldxa [%g3 + %g7]ASI_MEM, %g4 2810Sstevel@tonic-gate stx %g4, [%g1 + 0] ! byte 0 - 7 2820Sstevel@tonic-gate add %g7, 8, %g7 2830Sstevel@tonic-gate ldxa [%g3 + %g7]ASI_MEM, %g4 2840Sstevel@tonic-gate stx %g4, [%g1 + 8] ! byte 8 - 15 2850Sstevel@tonic-gate add %g7, 8, %g7 2860Sstevel@tonic-gate ldxa [%g3 + %g7]ASI_MEM, %g4 2870Sstevel@tonic-gate stx %g4, [%g1 + 16] ! byte 16 - 23 2880Sstevel@tonic-gate add %g7, 8, %g7 2890Sstevel@tonic-gate ldxa [%g3 + %g7]ASI_MEM, %g4 2900Sstevel@tonic-gate stx %g4, [%g1 + 24] ! byte 24 - 31 2910Sstevel@tonic-gate add %g7, 8, %g7 2920Sstevel@tonic-gate ldxa [%g3 + %g7]ASI_MEM, %g4 2930Sstevel@tonic-gate stx %g4, [%g1 + 32] ! byte 32 - 39 2940Sstevel@tonic-gate add %g7, 8, %g7 2950Sstevel@tonic-gate ldxa [%g3 + %g7]ASI_MEM, %g4 2960Sstevel@tonic-gate stx %g4, [%g1 + 40] ! byte 40 - 47 2970Sstevel@tonic-gate add %g7, 8, %g7 2980Sstevel@tonic-gate ldxa [%g3 + %g7]ASI_MEM, %g4 2990Sstevel@tonic-gate stx %g4, [%g1 + 48] ! byte 48 - 55 3000Sstevel@tonic-gate add %g7, 8, %g7 3010Sstevel@tonic-gate ldxa [%g3 + %g7]ASI_MEM, %g4 3020Sstevel@tonic-gate stx %g4, [%g1 + 56] ! byte 56 - 63 3030Sstevel@tonic-gate ldx [%g2 + MCPU_DEV_Q_SIZE], %g4 ! queue size 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate1: sub %g4, 1, %g4 ! %g4 = queue size mask 3060Sstevel@tonic-gate add %g6, INTR_REPORT_SIZE , %g6 ! inc head to next record 3070Sstevel@tonic-gate and %g6, %g4, %g6 ! and mask for wrap around 3080Sstevel@tonic-gate mov DEV_MONDO_Q_HD, %g3 3090Sstevel@tonic-gate stxa %g6, [%g3]ASI_QUEUE ! increment head offset 3100Sstevel@tonic-gate membar #Sync 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate#ifdef TRAPTRACE 3130Sstevel@tonic-gate TRACE_PTR(%g4, %g6) 314*11172SHaik.Aftandilian@Sun.COM GET_TRACE_TICK(%g6, %g3) 3150Sstevel@tonic-gate stxa %g6, [%g4 + TRAP_ENT_TICK]%asi 3160Sstevel@tonic-gate TRACE_SAVE_TL_GL_REGS(%g4, %g6) 3170Sstevel@tonic-gate rdpr %tt, %g6 3180Sstevel@tonic-gate stha %g6, [%g4 + TRAP_ENT_TT]%asi 3190Sstevel@tonic-gate rdpr %tpc, %g6 3200Sstevel@tonic-gate stna %g6, [%g4 + TRAP_ENT_TPC]%asi 3210Sstevel@tonic-gate rdpr %tstate, %g6 3220Sstevel@tonic-gate stxa %g6, [%g4 + TRAP_ENT_TSTATE]%asi 3230Sstevel@tonic-gate ! move head to sp 3240Sstevel@tonic-gate ldx [%g2 + MCPU_DEV_Q_BASE], %g6 3250Sstevel@tonic-gate stna %g6, [%g4 + TRAP_ENT_SP]%asi ! Device Queue Base PA 3260Sstevel@tonic-gate stna %g5, [%g4 + TRAP_ENT_TR]%asi ! Inum 3270Sstevel@tonic-gate mov DEV_MONDO_Q_HD, %g6 3280Sstevel@tonic-gate ldxa [%g6]ASI_QUEUE, %g6 ! New head offset 3290Sstevel@tonic-gate stna %g6, [%g4 + TRAP_ENT_F1]%asi 3300Sstevel@tonic-gate ldx [%g2 + MCPU_DEV_Q_SIZE], %g6 3310Sstevel@tonic-gate stna %g6, [%g4 + TRAP_ENT_F2]%asi ! Q Size 3320Sstevel@tonic-gate stna %g7, [%g4 + TRAP_ENT_F3]%asi ! tail offset 3330Sstevel@tonic-gate stna %g0, [%g4 + TRAP_ENT_F4]%asi 3340Sstevel@tonic-gate TRACE_NEXT(%g4, %g6, %g3) 3350Sstevel@tonic-gate#endif /* TRAPTRACE */ 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate ! 3382973Sgovinda ! setvecint_tl1 will do all the work, and finish with a retry 3390Sstevel@tonic-gate ! 3402973Sgovinda ba,pt %xcc, setvecint_tl1 3412973Sgovinda mov %g5, %g1 ! setvecint_tl1 expects inum in %g1 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate0: retry 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate /* Never Reached */ 3460Sstevel@tonic-gate SET_SIZE(dev_mondo) 3470Sstevel@tonic-gate#endif /* lint */ 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate#if defined(lint) 3500Sstevel@tonic-gateuint64_t cpu_mondo_inval; 3510Sstevel@tonic-gate#else /* lint */ 3520Sstevel@tonic-gate .seg ".data" 3530Sstevel@tonic-gate .global cpu_mondo_inval 3540Sstevel@tonic-gate .align 8 3550Sstevel@tonic-gatecpu_mondo_inval: 3560Sstevel@tonic-gate .skip 8 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate .seg ".text" 3590Sstevel@tonic-gate#endif /* lint */ 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate#if defined(lint) 3630Sstevel@tonic-gate 3640Sstevel@tonic-gatevoid 3650Sstevel@tonic-gateresumable_error(void) 3660Sstevel@tonic-gate{} 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate#else /* lint */ 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate/* 3710Sstevel@tonic-gate * (TT 0x7e, TL>0) Resumeable Error Queue Handler 3720Sstevel@tonic-gate * We keep a shadow copy of the queue in kernel buf. 3730Sstevel@tonic-gate * Read the resumable queue head and tail offset 3740Sstevel@tonic-gate * If there are entries on the queue, move them to 3750Sstevel@tonic-gate * the kernel buf, which is next to the resumable 3760Sstevel@tonic-gate * queue in the memory. Call C routine to process. 3770Sstevel@tonic-gate */ 3780Sstevel@tonic-gate ENTRY_NP(resumable_error) 3790Sstevel@tonic-gate mov CPU_RQ_HD, %g4 3800Sstevel@tonic-gate ldxa [%g4]ASI_QUEUE, %g2 ! %g2 = Q head offset 3810Sstevel@tonic-gate mov CPU_RQ_TL, %g4 3820Sstevel@tonic-gate ldxa [%g4]ASI_QUEUE, %g3 ! %g3 = Q tail offset 3830Sstevel@tonic-gate mov %g2, %g6 ! save head in %g2 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate cmp %g6, %g3 3860Sstevel@tonic-gate be,pn %xcc, 0f ! head == tail 3870Sstevel@tonic-gate nop 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate CPU_ADDR(%g1, %g4) ! %g1 = cpu struct addr 3900Sstevel@tonic-gate 3910Sstevel@tonic-gate2: set CPU_RQ_BASE_OFF, %g4 3920Sstevel@tonic-gate ldx [%g1 + %g4], %g4 ! %g4 = queue base PA 3930Sstevel@tonic-gate add %g6, %g4, %g4 ! %g4 = PA of ER in Q 3940Sstevel@tonic-gate set CPU_RQ_SIZE, %g7 3950Sstevel@tonic-gate add %g4, %g7, %g7 ! %g7=PA of ER in kernel buf 3960Sstevel@tonic-gate 3970Sstevel@tonic-gate ldxa [%g7]ASI_MEM, %g5 ! %g5=first 8 byte of ER buf 3980Sstevel@tonic-gate cmp 0, %g5 3990Sstevel@tonic-gate bne,pn %xcc, 1f ! first 8 byte is not 0 4000Sstevel@tonic-gate nop 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate /* Now we can move 64 bytes from queue to buf */ 4030Sstevel@tonic-gate set 0, %g5 4040Sstevel@tonic-gate ldxa [%g4 + %g5]ASI_MEM, %g1 4050Sstevel@tonic-gate stxa %g1, [%g7 + %g5]ASI_MEM ! byte 0 - 7 4060Sstevel@tonic-gate add %g5, 8, %g5 4070Sstevel@tonic-gate ldxa [%g4 + %g5]ASI_MEM, %g1 4080Sstevel@tonic-gate stxa %g1, [%g7 + %g5]ASI_MEM ! byte 8 - 15 4090Sstevel@tonic-gate add %g5, 8, %g5 4100Sstevel@tonic-gate ldxa [%g4 + %g5]ASI_MEM, %g1 4110Sstevel@tonic-gate stxa %g1, [%g7 + %g5]ASI_MEM ! byte 16 - 23 4120Sstevel@tonic-gate add %g5, 8, %g5 4130Sstevel@tonic-gate ldxa [%g4 + %g5]ASI_MEM, %g1 4140Sstevel@tonic-gate stxa %g1, [%g7 + %g5]ASI_MEM ! byte 24 - 31 4150Sstevel@tonic-gate add %g5, 8, %g5 4160Sstevel@tonic-gate ldxa [%g4 + %g5]ASI_MEM, %g1 4170Sstevel@tonic-gate stxa %g1, [%g7 + %g5]ASI_MEM ! byte 32 - 39 4180Sstevel@tonic-gate add %g5, 8, %g5 4190Sstevel@tonic-gate ldxa [%g4 + %g5]ASI_MEM, %g1 4200Sstevel@tonic-gate stxa %g1, [%g7 + %g5]ASI_MEM ! byte 40 - 47 4210Sstevel@tonic-gate add %g5, 8, %g5 4220Sstevel@tonic-gate ldxa [%g4 + %g5]ASI_MEM, %g1 4230Sstevel@tonic-gate stxa %g1, [%g7 + %g5]ASI_MEM ! byte 48 - 55 4240Sstevel@tonic-gate add %g5, 8, %g5 4250Sstevel@tonic-gate ldxa [%g4 + %g5]ASI_MEM, %g1 4260Sstevel@tonic-gate stxa %g1, [%g7 + %g5]ASI_MEM ! byte 56 - 63 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate set CPU_RQ_SIZE, %g5 ! %g5 = queue size 4290Sstevel@tonic-gate sub %g5, 1, %g5 ! %g5 = queu size mask 4300Sstevel@tonic-gate 4310Sstevel@tonic-gate add %g6, Q_ENTRY_SIZE, %g6 ! increment q head to next 4320Sstevel@tonic-gate and %g6, %g5, %g6 ! size mask for warp around 4330Sstevel@tonic-gate cmp %g6, %g3 ! head == tail ?? 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate bne,pn %xcc, 2b ! still have more to process 4360Sstevel@tonic-gate nop 4370Sstevel@tonic-gate 4380Sstevel@tonic-gate /* 4390Sstevel@tonic-gate * head equals to tail now, we can update the queue head 4400Sstevel@tonic-gate * and call sys_trap 4410Sstevel@tonic-gate */ 4420Sstevel@tonic-gate mov CPU_RQ_HD, %g4 4430Sstevel@tonic-gate stxa %g6, [%g4]ASI_QUEUE ! update head offset 4447718SJason.Beloro@Sun.COM membar #Sync 4450Sstevel@tonic-gate 4460Sstevel@tonic-gate /* 447623Sdavemq * Call sys_trap at PIL 14 unless we're already at PIL 15. %g2.l is 448623Sdavemq * head offset(arg2) and %g3 is tail 4490Sstevel@tonic-gate * offset(arg3). 4500Sstevel@tonic-gate */ 4510Sstevel@tonic-gate set process_resumable_error, %g1 452623Sdavemq rdpr %pil, %g4 453623Sdavemq cmp %g4, PIL_14 4540Sstevel@tonic-gate ba sys_trap 455623Sdavemq movl %icc, PIL_14, %g4 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate /* 4580Sstevel@tonic-gate * We are here because the C routine is not able to process 4590Sstevel@tonic-gate * errors in time. So the first 8 bytes of ER in buf has not 4600Sstevel@tonic-gate * been cleared. We update head to tail and call sys_trap to 4610Sstevel@tonic-gate * print out an error message 4620Sstevel@tonic-gate */ 4630Sstevel@tonic-gate 4640Sstevel@tonic-gate1: mov CPU_RQ_HD, %g4 4650Sstevel@tonic-gate stxa %g3, [%g4]ASI_QUEUE ! set head equal to tail 4667718SJason.Beloro@Sun.COM membar #Sync 4670Sstevel@tonic-gate 4680Sstevel@tonic-gate /* 4690Sstevel@tonic-gate * Set %g2 to %g6, which is current head offset. %g2 4700Sstevel@tonic-gate * is arg2 of the C routine. %g3 is the tail offset, 4710Sstevel@tonic-gate * which is arg3 of the C routine. 472623Sdavemq * Call rq_overflow at PIL 14 unless we're already at PIL 15. 4730Sstevel@tonic-gate */ 4740Sstevel@tonic-gate mov %g6, %g2 4750Sstevel@tonic-gate set rq_overflow, %g1 476623Sdavemq rdpr %pil, %g4 477623Sdavemq cmp %g4, PIL_14 4780Sstevel@tonic-gate ba sys_trap 479623Sdavemq movl %icc, PIL_14, %g4 4800Sstevel@tonic-gate 4810Sstevel@tonic-gate0: retry 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate /*NOTREACHED*/ 4840Sstevel@tonic-gate SET_SIZE(resumable_error) 4850Sstevel@tonic-gate#endif /* lint */ 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate#if defined(lint) 4880Sstevel@tonic-gate 4890Sstevel@tonic-gatevoid 4900Sstevel@tonic-gatenonresumable_error(void) 4910Sstevel@tonic-gate{} 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate#else /* lint */ 4940Sstevel@tonic-gate 4950Sstevel@tonic-gate/* 4960Sstevel@tonic-gate * (TT 0x7f, TL>0) Non-resumeable Error Queue Handler 4970Sstevel@tonic-gate * We keep a shadow copy of the queue in kernel buf. 4980Sstevel@tonic-gate * Read non-resumable queue head and tail offset 4990Sstevel@tonic-gate * If there are entries on the queue, move them to 5000Sstevel@tonic-gate * the kernel buf, which is next to the non-resumable 5010Sstevel@tonic-gate * queue in the memory. Call C routine to process. 5020Sstevel@tonic-gate */ 5030Sstevel@tonic-gate ENTRY_NP(nonresumable_error) 5040Sstevel@tonic-gate mov CPU_NRQ_HD, %g4 5050Sstevel@tonic-gate ldxa [%g4]ASI_QUEUE, %g2 ! %g2 = Q head offset 5060Sstevel@tonic-gate mov CPU_NRQ_TL, %g4 5070Sstevel@tonic-gate ldxa [%g4]ASI_QUEUE, %g3 ! %g3 = Q tail offset 5080Sstevel@tonic-gate 509817Swh94709 cmp %g2, %g3 5100Sstevel@tonic-gate be,pn %xcc, 0f ! head == tail 5110Sstevel@tonic-gate nop 5120Sstevel@tonic-gate 513817Swh94709 /* force %gl to 1 as sys_trap requires */ 514817Swh94709 wrpr %g0, 1, %gl 515817Swh94709 mov CPU_NRQ_HD, %g4 516817Swh94709 ldxa [%g4]ASI_QUEUE, %g2 ! %g2 = Q head offset 517817Swh94709 mov CPU_NRQ_TL, %g4 518817Swh94709 ldxa [%g4]ASI_QUEUE, %g3 ! %g3 = Q tail offset 519817Swh94709 mov %g2, %g6 ! save head in %g2 520817Swh94709 521817Swh94709 CPU_PADDR(%g1, %g4) ! %g1 = cpu struct paddr 5220Sstevel@tonic-gate 5230Sstevel@tonic-gate2: set CPU_NRQ_BASE_OFF, %g4 524817Swh94709 ldxa [%g1 + %g4]ASI_MEM, %g4 ! %g4 = queue base PA 5250Sstevel@tonic-gate add %g6, %g4, %g4 ! %g4 = PA of ER in Q 5260Sstevel@tonic-gate set CPU_NRQ_SIZE, %g7 5270Sstevel@tonic-gate add %g4, %g7, %g7 ! %g7 = PA of ER in kernel buf 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate ldxa [%g7]ASI_MEM, %g5 ! %g5 = first 8 byte of ER buf 5300Sstevel@tonic-gate cmp 0, %g5 5310Sstevel@tonic-gate bne,pn %xcc, 1f ! first 8 byte is not 0 5320Sstevel@tonic-gate nop 5330Sstevel@tonic-gate 53410271SJason.Beloro@Sun.COM /* Now we can move 64 bytes from queue to buf */ 5350Sstevel@tonic-gate set 0, %g5 5360Sstevel@tonic-gate ldxa [%g4 + %g5]ASI_MEM, %g1 5370Sstevel@tonic-gate stxa %g1, [%g7 + %g5]ASI_MEM ! byte 0 - 7 5380Sstevel@tonic-gate add %g5, 8, %g5 5390Sstevel@tonic-gate ldxa [%g4 + %g5]ASI_MEM, %g1 5400Sstevel@tonic-gate stxa %g1, [%g7 + %g5]ASI_MEM ! byte 8 - 15 5410Sstevel@tonic-gate add %g5, 8, %g5 5420Sstevel@tonic-gate ldxa [%g4 + %g5]ASI_MEM, %g1 5430Sstevel@tonic-gate stxa %g1, [%g7 + %g5]ASI_MEM ! byte 16 - 23 54410271SJason.Beloro@Sun.COM add %g5, 8, %g5 5450Sstevel@tonic-gate ldxa [%g4 + %g5]ASI_MEM, %g1 5460Sstevel@tonic-gate stxa %g1, [%g7 + %g5]ASI_MEM ! byte 24 - 31 5470Sstevel@tonic-gate add %g5, 8, %g5 5480Sstevel@tonic-gate ldxa [%g4 + %g5]ASI_MEM, %g1 5490Sstevel@tonic-gate stxa %g1, [%g7 + %g5]ASI_MEM ! byte 32 - 39 5500Sstevel@tonic-gate add %g5, 8, %g5 5510Sstevel@tonic-gate ldxa [%g4 + %g5]ASI_MEM, %g1 5520Sstevel@tonic-gate stxa %g1, [%g7 + %g5]ASI_MEM ! byte 40 - 47 55310271SJason.Beloro@Sun.COM add %g5, 8, %g5 5540Sstevel@tonic-gate ldxa [%g4 + %g5]ASI_MEM, %g1 5550Sstevel@tonic-gate stxa %g1, [%g7 + %g5]ASI_MEM ! byte 48 - 55 5560Sstevel@tonic-gate add %g5, 8, %g5 5570Sstevel@tonic-gate ldxa [%g4 + %g5]ASI_MEM, %g1 5580Sstevel@tonic-gate stxa %g1, [%g7 + %g5]ASI_MEM ! byte 56 - 63 5590Sstevel@tonic-gate 5600Sstevel@tonic-gate set CPU_NRQ_SIZE, %g5 ! %g5 = queue size 5610Sstevel@tonic-gate sub %g5, 1, %g5 ! %g5 = queu size mask 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate add %g6, Q_ENTRY_SIZE, %g6 ! increment q head to next 5640Sstevel@tonic-gate and %g6, %g5, %g6 ! size mask for warp around 5650Sstevel@tonic-gate cmp %g6, %g3 ! head == tail ?? 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate bne,pn %xcc, 2b ! still have more to process 5680Sstevel@tonic-gate nop 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate /* 5710Sstevel@tonic-gate * head equals to tail now, we can update the queue head 5720Sstevel@tonic-gate * and call sys_trap 5730Sstevel@tonic-gate */ 5740Sstevel@tonic-gate mov CPU_NRQ_HD, %g4 5750Sstevel@tonic-gate stxa %g6, [%g4]ASI_QUEUE ! update head offset 5767718SJason.Beloro@Sun.COM membar #Sync 5777718SJason.Beloro@Sun.COM 5787718SJason.Beloro@Sun.COM /* 5790Sstevel@tonic-gate * Call sys_trap. %g2 is TL(arg2), %g3 is head and tail 5800Sstevel@tonic-gate * offset(arg3). 5810Sstevel@tonic-gate * %g3 looks like following: 5820Sstevel@tonic-gate * +--------------------+--------------------+ 5830Sstevel@tonic-gate * | tail offset | head offset | 5840Sstevel@tonic-gate * +--------------------+--------------------+ 5850Sstevel@tonic-gate * 63 32 31 0 586623Sdavemq * 587623Sdavemq * Run at PIL 14 unless we're already at PIL 15. 5880Sstevel@tonic-gate */ 58910271SJason.Beloro@Sun.COM sllx %g3, 32, %g3 ! %g3.h = tail offset 5900Sstevel@tonic-gate or %g3, %g2, %g3 ! %g3.l = head offset 5910Sstevel@tonic-gate rdpr %tl, %g2 ! %g2 = current tl 5921457Swh94709 5931457Swh94709 /* 5941457Swh94709 * Now check if the first error that sent us here was caused 5951457Swh94709 * in user's SPILL/FILL trap. If it was, we call sys_trap to 5961457Swh94709 * kill the user process. Several considerations: 5971457Swh94709 * - If multiple nonresumable errors happen, we only check the 5981457Swh94709 * first one. Nonresumable errors cause system either panic 5991457Swh94709 * or kill the user process. So the system has already 6001457Swh94709 * panic'ed or killed user process after processing the first 6011457Swh94709 * error. Therefore, no need to check if other error packet 6021457Swh94709 * for this type of error. 6031457Swh94709 * - Errors happen in user's SPILL/FILL trap will bring us at 6041457Swh94709 * TL = 2. 6051457Swh94709 * - We need to lower TL to 1 to get the trap type and tstate. 6061457Swh94709 * We don't go back to TL = 2 so no need to save states. 6071457Swh94709 */ 6081457Swh94709 cmp %g2, 2 6091457Swh94709 bne,pt %xcc, 3f ! if tl != 2 6101457Swh94709 nop 6111457Swh94709 /* Check to see if the trap pc is in a window spill/fill handling */ 6121457Swh94709 rdpr %tpc, %g4 6131457Swh94709 /* tpc should be in the trap table */ 6141457Swh94709 set trap_table, %g5 6151457Swh94709 cmp %g4, %g5 6161457Swh94709 blu,pt %xcc, 3f 6171457Swh94709 nop 6181457Swh94709 set etrap_table, %g5 6191457Swh94709 cmp %g4, %g5 6201457Swh94709 bgeu,pt %xcc, 3f 6211457Swh94709 nop 6221457Swh94709 /* Set tl to 1 in order to read tt[1] and tstate[1] */ 6231457Swh94709 wrpr %g0, 1, %tl 6241457Swh94709 rdpr %tt, %g4 ! %g4 = tt[1] 6251457Swh94709 /* Check if tt[1] is a window trap */ 6261457Swh94709 and %g4, WTRAP_TTMASK, %g4 6271457Swh94709 cmp %g4, WTRAP_TYPE 6281457Swh94709 bne,pt %xcc, 3f 6291457Swh94709 nop 6301457Swh94709 rdpr %tstate, %g5 ! %g5 = tstate[1] 6311457Swh94709 btst TSTATE_PRIV, %g5 6321457Swh94709 bnz %xcc, 3f ! Is it from user code? 6331457Swh94709 nop 6341457Swh94709 /* 6351457Swh94709 * Now we know the error happened in user's SPILL/FILL trap. 6361457Swh94709 * Turn on the user spill/fill flag in %g2 6371457Swh94709 */ 6381457Swh94709 mov 1, %g4 6391457Swh94709 sllx %g4, ERRH_U_SPILL_FILL_SHIFT, %g4 6401457Swh94709 or %g2, %g4, %g2 ! turn on flag in %g2 6411457Swh94709 6421457Swh947093: sub %g2, 1, %g2 ! %g2.l = previous tl 6430Sstevel@tonic-gate 6440Sstevel@tonic-gate set process_nonresumable_error, %g1 645623Sdavemq rdpr %pil, %g4 646623Sdavemq cmp %g4, PIL_14 6470Sstevel@tonic-gate ba sys_trap 648623Sdavemq movl %icc, PIL_14, %g4 6490Sstevel@tonic-gate 6500Sstevel@tonic-gate /* 6510Sstevel@tonic-gate * We are here because the C routine is not able to process 6520Sstevel@tonic-gate * errors in time. So the first 8 bytes of ER in buf has not 653817Swh94709 * been cleared. We call sys_trap to panic. 654817Swh94709 * Run at PIL 14 unless we're already at PIL 15. 6550Sstevel@tonic-gate */ 656817Swh947091: set nrq_overflow, %g1 657817Swh94709 rdpr %pil, %g4 658817Swh94709 cmp %g4, PIL_14 659817Swh94709 ba sys_trap 660817Swh94709 movl %icc, PIL_14, %g4 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate0: retry 6630Sstevel@tonic-gate 6640Sstevel@tonic-gate /*NOTREACHED*/ 6650Sstevel@tonic-gate SET_SIZE(nonresumable_error) 6660Sstevel@tonic-gate#endif /* lint */ 667