* ========== Copyright Header Begin ==========================================
* Hypervisor Software File: svc_vbsc.s
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* - Do no alter or remove copyright notices
* - Redistribution and use of this software in source and binary forms, with
* or without modification, are permitted provided that the following
* - Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of Sun Microsystems, Inc. or the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
* MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN
* OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR
* FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* You acknowledge that this software is not designed, licensed or
* intended for use in the design, construction, operation or maintenance of
* ========== Copyright Header End ============================================
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
.ident "@(#)svc_vbsc.s 1.28 07/05/29 SMI"
#if defined(CONFIG_SVC) && defined(CONFIG_VBSC_SVC)
#include <sys/asm_linkage.h>
#include <sparcv9/misc.h>
#include <sun4v/errs_defs.h>
* vbsc_send_polled - send a command to vbsc using polled I/O
* If VBSC does not accept the packet then
ENTRY_NP(vbsc_send_polled)
.vbsc_send_polled_resend:
setx FPGA_Q3OUT_BASE, %g4, %g5
setx FPGA_BASE + FPGA_SRAM_BASE, %g4, %g6
lduh [%g5 + FPGA_Q_BASE], %g4
!! %g6 = sram buffer words
stb %g4, [%g5 + FPGA_Q_SEND]
* Wait for a non-zero status. If we get an ACK then we're done.
* Otherwise re-send the packet. Failure is not an option, even
* to hv_abort we need to send a message to vbsc. So keep trying.
.vbsc_send_polled_wait_for_ack:
ldub [%g5 + FPGA_Q_STATUS], %g4
andcc %g4, (QINTR_ACK | QINTR_NACK | QINTR_BUSY | QINTR_ABORT), %g4
bz,pn %xcc, .vbsc_send_polled_wait_for_ack
bz,pt %xcc, .vbsc_send_polled_resend
stb %g4, [%g5 + FPGA_Q_STATUS] ! clear status bits
SET_SIZE(vbsc_send_polled)
* vbsc_hv_start - notify VBSC that the hypervisor has started
* Called from setup environment
setx VBSC_HV_START, %g2, %g1
* vbsc_hv_abort - notify VBSC that hv has aborted
* %g1 contains reason for the abort
setx VBSC_HV_ABORT, %g3, %g1
/* spin until the vbsc powers us down */
* vbsc_hv_plxreset - notify VBSC that the hypervisor has requested
* a special reset due to PLX link training problems. VBSC knows to
* do this quietly and prevent it from looping forever.
* %g1 plx link failure bitmask
* Called from setup environment
ENTRY_NP(vbsc_hv_plxreset)
setx VBSC_HV_PLXRESET, %g3, %g1
SET_SIZE(vbsc_hv_plxreset)
* vbsc_guest_start - notify VBSC that a guest has started
ENTRY_NP(vbsc_guest_start)
setx VBSC_GUEST_ON, %g2, %g1
add %g2, XPID_GUESTBASE, %g2
SET_SIZE(vbsc_guest_start)
* vbsc_guest_exit - notify VBSC that a guest has exited
ENTRY_NP(vbsc_guest_exit)
setx VBSC_GUEST_OFF, %g2, %g1
add %g2, XPID_GUESTBASE, %g2
ldx [%o2 + GUEST_TOD_OFFSET], %g3
/* spin until the vbsc powers us down */
SET_SIZE(vbsc_guest_exit)
* vbsc_guest_sir - notify vbsc that a guest requested a reset
setx VBSC_GUEST_RESET, %g2, %g1
add %g2, XPID_GUESTBASE, %g2
ldx [%o2 + GUEST_TOD_OFFSET], %g3
/* spin until the vbsc powers us down */
* vbsc_guest_wdexpire - notify vbsc that a guest's watchdog timer expired
* Service Processor policy dictates what happens next.
ENTRY_NP(vbsc_guest_wdexpire)
setx VBSC_GUEST_WDEXPIRE, %g2, %g1
add %g2, XPID_GUESTBASE, %g2
ldx [%g6 + GUEST_TOD_OFFSET], %g3
ba,a vbsc_send_polled ! tail call, returns to caller
SET_SIZE(vbsc_guest_wdexpire)
* vbsc_guest_tod_offset - notify VBSC of a guest's TOD offset
* We don't retry here, failures are ignored.
* Called from guest hcall environment
/* FIXME: Use a better buffer to send from ... */
/* Better yet this function / operation goes away entirely for LDoms */
ENTRY_NP(vbsc_guest_tod_offset)
add %g3, XPID_GUESTBASE, %g3
ldx [%g1 + GUEST_TOD_OFFSET], %g3
setx VBSC_GUEST_TODOFFSET, %g4, %g3
ldx [%g1 + CONFIG_VBSC_SVCH], %g1
ba,pt %xcc, svc_internal_send ! tail call, returns to caller
SET_SIZE(vbsc_guest_tod_offset)
#define SIM_IRU_DIAG_ERPT(erpt_vbsc, reg1, reg2) \
set ERPT_TYPE_CPU, reg1 ;\
stx reg1, [erpt_vbsc + EVBSC_REPORT_TYPE] ;\
setx 0x10000000000001, reg2, reg1 ;\
stx reg1, [erpt_vbsc + EVBSC_EHDL] ;\
setx 0x002a372a4, reg2, reg1 ;\
stx reg1, [erpt_vbsc + EVBSC_STICK] ;\
setx 0x3e002310000607, reg2, reg1 ;\
stx reg1, [erpt_vbsc + EVBSC_CPUVER] ;\
setx 0x000000000, reg2, reg1 ;\
stx reg1, [erpt_vbsc + EVBSC_CPUSERIAL] ;\
setx 0x000010000, reg2, reg1 ;\
stx reg1, [erpt_vbsc + EVBSC_SPARC_AFSR] ;\
setx 0x000830550, reg2, reg1 ;\
stx reg1, [erpt_vbsc + EVBSC_SPARC_AFAR] ;\
setx 0x400000402, reg2, reg1 ;\
stx reg1, [erpt_vbsc + EVBSC_TSTATE] ;\
setx 0x000000800, reg2, reg1 ;\
stx reg1, [erpt_vbsc + EVBSC_HTSTATE] ;\
setx 0x000800610, reg2, reg1 ;\
stx reg1, [erpt_vbsc + EVBSC_TPC] ;\
stuh reg1, [erpt_vbsc + EVBSC_CPUID] ;\
stuh reg1, [erpt_vbsc + EVBSC_TT] ;\
stub reg1, [erpt_vbsc + EVBSC_TL] ;\
stub reg1, [erpt_vbsc + EVBSC_ERREN]
#define SIM_IRC_DIAG_ERPT(erpt_vbsc, reg1, reg2) \
set ERPT_TYPE_CPU, reg1 ;\
stx reg1, [erpt_vbsc + EVBSC_REPORT_TYPE] ;\
setx 0x10000000000002, reg2, reg1 ;\
stx reg1, [erpt_vbsc + EVBSC_EHDL] ;\
setx 0x002a372a4, reg2, reg1 ;\
stx reg1, [erpt_vbsc + EVBSC_STICK] ;\
setx 0x3e002310000607, reg2, reg1 ;\
stx reg1, [erpt_vbsc + EVBSC_CPUVER] ;\
setx 0x000000000, reg2, reg1 ;\
stx reg1, [erpt_vbsc + EVBSC_CPUSERIAL] ;\
setx 0x000020000, reg2, reg1 ;\
stx reg1, [erpt_vbsc + EVBSC_SPARC_AFSR] ;\
setx 0x000830550, reg2, reg1 ;\
stx reg1, [erpt_vbsc + EVBSC_SPARC_AFAR] ;\
setx 0x400000402, reg2, reg1 ;\
stx reg1, [erpt_vbsc + EVBSC_TSTATE] ;\
setx 0x000000800, reg2, reg1 ;\
stx reg1, [erpt_vbsc + EVBSC_HTSTATE] ;\
setx 0x000800610, reg2, reg1 ;\
stx reg1, [erpt_vbsc + EVBSC_TPC] ;\
stuh reg1, [erpt_vbsc + EVBSC_CPUID] ;\
stuh reg1, [erpt_vbsc + EVBSC_TT] ;\
stub reg1, [erpt_vbsc + EVBSC_TL] ;\
stub reg1, [erpt_vbsc + EVBSC_ERREN]
* %g1 callback cookie (guest struct?XXX)
ldx [%g1 + CONFIG_VBSC_SVCH], %g1
PRINT("vbsc_rx: "); PRINTX(%g1); PRINT("\r\n");
* We don't defer packets so clear the recv pending flag.
* This is called on the cpu handling the interrupts so
* the contents of the buffer will not get clobbered until
ld [%g2 + SVC_CTRL_STATE], %g3
andn %g3, SVC_FLAGS_RI, %g3
st %g3, [%g2 + SVC_CTRL_STATE] ! clear RECV pending
ldx [%g2 + SVC_CTRL_RECV + SVC_LINK_PA], %g2
inc SVC_PKT_SIZE, %g2 ! skip the header
cmp %g4, VBSC_CMD_GUEST_STATE
be,pn %xcc, gueststatecmd
cmp %g4, VBSC_CMD_READMEM
cmp %g4, VBSC_CMD_WRITEMEM
cmp %g4, VBSC_CMD_SENDERR
be,pn %xcc, dbg_send_error
* hvcmd - Hypervisor Command
* hvcmd_ping - nop, just respond
/* FIXME: find better scratch buffer */
setx VBSC_ACK(VBSC_CMD_HV, 'I'), %g4, %g3
ba,pt %xcc, svc_internal_send ! returns to caller!!!!
* gueststatecmd - Request from VBSC to change guest state
cmp %g4, GUEST_STATE_CMD_SHUTREQ
cmp %g4, GUEST_STATE_CMD_DCOREREQ
* The use of XID is deprecated. The target of
* the request is always the control domain.
CTRL_DOMAIN(%g1, %g3, %g4)
be,pn %xcc, vbsc_rx_finished
* Check if the current vcpu is in the control
* domain and running. If so, the state command
* can be executed on the local strand.
!! %g1 = control domain guestp
ldx [%g3 + CPU_GUEST], %g4
ldx [%g3 + CPU_STATUS], %g4
cmp %g4, CPU_STATE_RUNNING
!! %g1 = control domain guestp
* Loop through the vcpus in the control domain
* until one is found that is running. If none
* are found, the domain is not in an appropriate
* state for the request so the request is dropped.
bgu,pn %xcc, vbsc_rx_finished ! no appropriate vcpu, ignore request
sllx %g4, GUEST_VCPUS_SHIFT, %g3
add %g3, GUEST_VCPUS, %g3
brz,a %g3, 1b ! skip any empty entries
ldx [%g3 + CPU_STATUS], %g5
cmp %g5, CPU_STATE_RUNNING
VCPU2STRAND_STRUCT(%g3, %g4)
cmp %g5, GUEST_STATE_CMD_SHUTREQ
be,pn %xcc, hvcmd_guest_shutdown_request
cmp %g5, GUEST_STATE_CMD_DCOREREQ
be,pn %xcc, hvcmd_guest_dcore_request
hvcmd_guest_shutdown_request:
PRINT("Control Domain shutdown request, target strand=0x")
ldub [%g4 + STRAND_ID], %g6
! retrieve the command argument from the packet
!! %g2 = command argument (grace period in seconds)
* Perform the action locally if the current
* strand is the specified target.
be,a,pt %xcc, guest_shutdown ! tail call, does not return here
mov %g2, %g1 ! the required argument
* Send a mondo to the specified strand to
add %g4, STRAND_HV_TXMONDO, %g5
mov HXCMD_GUEST_SHUTDOWN, %g6
stx %g6, [%g5 + HVM_FROM_STRANDP]
stx %g3, [%g5 + HVM_ARGS + HVM_GUESTCMD_VCPUP]
stx %g2, [%g5 + HVM_ARGS + HVM_GUESTCMD_ARG]
mov %g4, %g1 ! arg1 = target strandp
mov %g5, %g2 ! arg2 = strand mondop
STRAND_PUSH(%g7, %g3, %g4)
hvcmd_guest_dcore_request:
PRINT("Control Domain panic request, target strand=0x")
ldub [%g4 + STRAND_ID], %g6
* Perform the action locally if the current
* strand is the specified target.
be,a,pt %xcc, guest_panic ! tail call, does not return here
* Send a mondo to the specified strand to
add %g4, STRAND_HV_TXMONDO, %g5
mov HXCMD_GUEST_PANIC, %g6
stx %g6, [%g5 + HVM_FROM_STRANDP]
stx %g3, [%g5 + HVM_ARGS + HVM_GUESTCMD_VCPUP]
mov %g4, %g1 ! arg1 = target strandp
mov %g5, %g2 ! arg2 = strand mondop
STRAND_PUSH(%g7, %g3, %g4)
* dbgrd - perform read transaction on behalf of vbsc
ldx [%g2 + 8], %g3 ! ADDR
ldub [%g2 + 7], %g6 ! size
ldub [%g2 + 5], %g4 ! asi?
sllx %g6, 2, %g6 ! offset
add %g6, 4*4, %g6 ! offset of ASIs
srlx %g3, 8, %g3 ! bits 0-56
jmp %g4 + %g6 ! CTI COUPLE!!
nop ! NEVER EXECUTED!! DONT DELETE
.word 0 ! data buffer - upper 32 bits
.word 0 ! data buffer - lower 32 bits
st %g6, [%g2 + 4] ! low bits
st %g6, [%g2 + 0] ! upper bits
ba svc_internal_send ! returns to caller!!!!
* dbgwr - perform write transaction on behalf of vbsc
ldx [%g2 + 0x10], %g3 ! ADDR
ldub [%g2 + 7], %g6 ! size
ldub [%g2 + 5], %g1 ! asi?
sllx %g6, 2, %g6 ! offset
add %g6, 4*4, %g6 ! offset of ASIs
srlx %g3, 8, %g3 ! bits0-56
ldx [%g2 + 8], %g1 ! get data
jmp %g4 + %g6 ! CTI COUPLE!!
* dbg_send_error - send a fake error transaction back to vbsc
* Fill the error reports with valid information to
* help test interaction with the FERG on the vbsc
add %g3, STRAND_CE_RPT + STRAND_VBSC_ERPT, %g4
SIM_IRC_DIAG_ERPT(%g4, %g5, %g7)
add %g3, STRAND_UE_RPT + STRAND_VBSC_ERPT, %g4
SIM_IRU_DIAG_ERPT(%g4, %g5, %g7)
CPU_PUSH(%g7, %g1, %g2, %g3)
add %g1, STRAND_CE_RPT + STRAND_UNSENT_PKT, %g2
ldx [%g1 + STRAND_CONFIGP], %g6
* Send one error and mark another buffer to be
stx %g7, [%g6 + CONFIG_ERRS_TO_SEND]
set STRAND_UE_RPT + STRAND_UNSENT_PKT, %g3
add %g1, STRAND_CE_RPT + STRAND_VBSC_ERPT, %g1
CPU_POP(%g7, %g1, %g2, %g3)
* vbsc_puts - print string on hypervisor console
CPU_PUSH(%g7, %g2, %g3, %g4)
CPU_PUSH(%g6, %g2, %g3, %g4)
CPU_PUSH(%g5, %g2, %g3, %g4)
CPU_PUSH(%l0, %g2, %g3, %g4)
!! %g2 = debug-puthex arg1
or %g2, %g3, %g2 ! arg1 = (arg1 << 8) | char
setx VBSC_HV_PUTCHARS, %g3, %g1
setx VBSC_HV_PUTCHARS, %g3, %g1
CPU_POP(%l0, %g1, %g2, %g3)
CPU_POP(%g5, %g1, %g2, %g3)
CPU_POP(%g6, %g1, %g2, %g3)
CPU_POP(%g7, %g1, %g2, %g3)
* vbsc_putx - print hex number on hypervisor console
setx VBSC_HV_PUTHEX, %g3, %g1
/* tail call, returns directly to caller */
#endif /* CONFIG_SVC && CONFIG_VBSC_SVC */