* ========== Copyright Header Begin ==========================================
* Hypervisor Software File: hv_common_cmds.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 "@(#)hv_common_cmds.s 1.3 07/05/03 SMI"
* Niagara-family common startup code
#include <sys/asm_linkage.h>
#include <sys/stack.h> /* For C environ : FIXME */
#include <sun4v/errs_defs.h>
* This function handles the receipt of a command mondo from another
* strand. Should only get here if we know that a mondo is waiting.
/* Collect the pending mondo */
mov %g1, %g2 ! ptr to mondo
cmp %g3, HXCMD_SCHED_VCPU
be,pn %xcc, schedule_vcpu_cmd
cmp %g3, HXCMD_DESCHED_VCPU
be,pn %xcc, deschedule_vcpu_cmd
be,pn %xcc, stop_vcpu_cmd
cmp %g3, HXCMD_GUEST_SHUTDOWN
be,pt %xcc, shutdown_guest_cmd
cmp %g3, HXCMD_GUEST_PANIC
be,pt %xcc, panic_guest_cmd
cmp %g3, HXCMD_STOP_GUEST
be,pt %xcc, stop_guest_cmd
HVABORT(-1, "Unknown HV mondo command")
* Handler for the HV xcall to send a shutdown request to
* a particular vcpu. This does not return to the caller.
* %g2 = ptr to command mondo
ENTRY_NP(shutdown_guest_cmd)
PRINT("shutdown_guest_cmd: strand=0x")
ldub [%g1 + STRAND_ID], %g3
* Processing of the shutdown request will occur
* on the vcpu specified in the mondo structure.
* By bypassing the strand work wheel and restoring
* the vcpu state directly, this assumes a one to
* one mapping between strands and vcpus. This will
* have to be fixed once multiple vcpus can be
* scheduled on the same strand.
ldx [%g2 + HVM_ARGS + HVM_GUESTCMD_VCPUP], %g3
SET_VCPU_STRUCT(%g3, %g4)
* Restore the vcpu state. Since this will result
* in the loss of current register state, save the
* mondo arg into the strand structure.
STRAND_PUSH(%g2, %g3, %g4)
HVCALL(vcpu_state_restore)
! load the grace period timeout
ldx [%g2 + HVM_ARGS + HVM_GUESTCMD_ARG], %g1
SET_SIZE(shutdown_guest_cmd)
* Handler for the HV xcall to send a panic request to a
* particular vcpu. This does not return to the caller.
* %g2 = ptr to command mondo
ENTRY_NP(panic_guest_cmd)
PRINT("panic_guest_cmd: strand=0x")
ldub [%g1 + STRAND_ID], %g3
* Processing of the panic request will occur on
* the vcpu specified in the mondo structure.
* By bypassing the strand work wheel and restoring
* the vcpu state directly, this assumes a one to
* one mapping between strands and vcpus. This will
* have to be fixed once multiple vcpus can be
* scheduled on the same strand.
ldx [%g2 + HVM_ARGS + HVM_SCHED_VCPUP], %g3
SET_VCPU_STRUCT(%g3, %g4)
HVCALL(vcpu_state_restore)
* Send the trap to the guest. Clear the pending
set STRAND_NRPENDING, %g2
ba nonresumable_error_trap
SET_SIZE(panic_guest_cmd)
* Queue up a resumable error packet on the current vcpu,
* requesting that the guest perform an orderly shutdown.
* %g1 = grace period for shutdown (seconds)
andn %g2, 0x7, %g2 ! align
!! %g2 = sun4v erpt buffer
* Fill in the only additional data in this erpt,
* the grace period before shutdown (seconds).
sth %g1, [%g2 + ESUN4V_G_SECS]
* Fill in the generic parts of the erpt.
stx %g4, [%g2 + ESUN4V_G_EHDL]
stx %g4, [%g2 + ESUN4V_G_STICK]
set EDESC_WARN_RESUMABLE, %g4
stw %g4, [%g2 + ESUN4V_EDESC]
set (ERR_ATTR_MODE(ERR_MODE_UNKNOWN) | EATTR_SECS), %g4
stw %g4, [%g2 + ESUN4V_ATTR]
stx %g0, [%g2 + ESUN4V_ADDR]
stw %g0, [%g2 + ESUN4V_SZ]
sth %g0, [%g2 + ESUN4V_G_CPUID]
STRAND_PUSH(%g7, %g3, %g4)
HVCALL(queue_resumable_erpt)
* Queue up a non-resumable error packet on the current
* vcpu, requesting that the guest panic immediately.
andn %g2, 0x7, %g2 ! align
!! %g2 = sun4v erpt buffer
* Fill in the generic parts of the erpt
stx %g4, [%g2 + ESUN4V_G_EHDL]
stx %g4, [%g2 + ESUN4V_G_STICK]
set EDESC_FORCED_PANIC, %g4
stw %g4, [%g2 + ESUN4V_EDESC]
set (ERR_ATTR_MODE(ERR_MODE_UNKNOWN)), %g4
stw %g4, [%g2 + ESUN4V_ATTR]
stx %g0, [%g2 + ESUN4V_ADDR]
stw %g0, [%g2 + ESUN4V_SZ]
sth %g0, [%g2 + ESUN4V_G_CPUID]
STRAND_PUSH(%g7, %g3, %g4)
HVCALL(queue_nonresumable_erpt)
* Set the pending flag used when the vbsc_rx
* handler calls this directly, i.e. when a HV
set STRAND_NRPENDING, %g3
* We get here as a HV mondo X-call
* Our working assumption is that the currently running vcpu state
* (if any) has been stashed back into its vcpu structure, and so at
* the end of this operation we bail back to start_work.
* The argument in the strand x-call mail box is the pointer
* to the vcpu to schedule. Plus a set of optional parameters
* to setup in the vcpu struct. FIXME: these parameters should
* be being set by the sender not us...
* %g2 = ptr to command mondo
/* FIXME: validate args ! */
ldx [%g3 + HVM_SCHED_VCPUP], %g4 ! vcpu ptr
! assert vcpup->strand == %g1
ldub [%g4 + CPU_STRAND_SLOT], %g5
PRINT("schedule vcpu @ 0x")
lduw [%g4 + CPU_RES_ID], %g6
ldub [%g4 + CPU_VID], %g6
mulx %g5, SCHED_SLOT_SIZE, %g3
add %g1, STRAND_SLOT, %g1
stx %g4, [%g3 + SCHED_SLOT_ARG]
mov SLOT_ACTION_RUN_VCPU, %g2
stx %g2, [%g3 + SCHED_SLOT_ACTION]
SET_SIZE(schedule_vcpu_cmd)
* We get here as a HV mondo X-call
* Our working assumption is that the currently running vcpu state
* (if any) has been stashed back into its vcpu structure, and so
* at the end of this operation we bail back to start_work.
* The argument in the strand x-call mail box is the pointer
* to the vcpu to deschedule.
* %g2 = ptr to command mondo
ENTRY(deschedule_vcpu_cmd)
ldx [%g3 + HVM_SCHED_VCPUP], %g4
SET_SIZE(deschedule_vcpu_cmd)
* Assumes running on localstrand to vcpu
* NOTE: called from deschedule_vcpu_cmd and hcall_mach_exit
/* validate arg; vcpup->strand == this strand */
ldx [%g4 + CPU_STRAND], %g5
HVABORT(-1, "deschedule cpu - vcpu not scheduled on my strand")
ldub [%g4 + CPU_STRAND_SLOT], %g5
#if DBG_DESCHEDULE /* { */
mov %g7, %g3 /* preserve return addr */
PRINT("deschedule vcpu @ 0x")
lduw [%g4 + CPU_RES_ID], %g6
ldub [%g4 + CPU_VID], %g6
mov %g3, %g7 /* restore return addr */
mulx %g5, SCHED_SLOT_SIZE, %g3
add %g1, STRAND_SLOT, %g1
stx %g2, [%g3 + SCHED_SLOT_ACTION]
mov 1, %g2 ! force alignment trap
stx %g2, [%g3 + SCHED_SLOT_ARG]
SET_SIZE(deschedule_vcpu)
* This operation terminates the execution of the specified vcpu.
* Our working assumption is that the currently
* running vcpu state (if any) has been stashed back into
* its vcpu structure, and so at the end of this operation
* we bail back to start_work.
* The argument in the strand x-call mail box is the pointer
* to the vcpu to deschedule.
* %g2 = ptr to command mondo
ldx [%g3 + HVM_SCHED_VCPUP], %g1
HVCALL(desched_n_stop_vcpu)
* We dont care about the current running state.
* It's over with. Just set the vcpu state and
SET_VCPU_STRUCT(%g1, %g2) /* force a alignment trap */
DEBUG_SPINLOCK_ENTER(%g1, %g2, %g3)
PRINT("Back to work\r\n")
* Removes a vcpu from the corresponding strand slot. It then
* calls stop_vcpu to stop a virtual cpu an clear out associated
ENTRY_NP(desched_n_stop_vcpu)
STRAND_PUSH(%g7, %g3, %g4) ! save return address
ldub [%g1 + CPU_STRAND_SLOT], %g4
mulx %g4, SCHED_SLOT_SIZE, %g3
add %g2, STRAND_SLOT, %g5
stx %g2, [%g3 + SCHED_SLOT_ACTION]
mov 1, %g2 ! force alignment trap
stx %g2, [%g3 + SCHED_SLOT_ARG]
VCPU2GUEST_STRUCT(%g1, %g2)
#endif /* CONFIG_CRYPTO */
* Clean up the (active) running state
! Default setup entry point for next time we start cpu
! Strictly speaking we should not need to do this here since
! there are only two ways a cpu can start from stopped
! 1. as the boot cpu in which case we force the start address
! 2. via a cpu_start API call in which case the start address
ldx [%g1 + CPU_RTBA], %g3
inc (TT_POR * TRAPTABLE_ENTRY_SIZE), %g3 ! Power-on-reset vector
stx %g3, [%g1 + CPU_START_PC]
STRAND_POP(%g7, %g2) ! retrieve return address
SET_SIZE(desched_n_stop_vcpu)
* C Wrapper around desched_n_stop_vcpu(). Deschedules and
* stops the vcpu passed in as a parameter.
ENTRY(c_desched_n_stop_vcpu)
STRAND_PUSH(%g2, %g6, %g7)
STRAND_PUSH(%g3, %g6, %g7)
STRAND_PUSH(%g4, %g6, %g7)
VCPU2STRAND_STRUCT(%g1, %g2)
HVCALL(desched_n_stop_vcpu)
SET_SIZE(c_desched_n_stop_vcpu)
* Called from xcall context usually from the control domain
* to exit a guest remotely. Assumes any running vcpu assigned
* to this strand already had its state saved so we can clobber
* %g1 - pointer to the current strand
* %g2 - HV xcall command mondo pointer
ldx [%g2 + HVM_ARGS + HVM_STOPGUEST_GUESTP], %g2
* Save the guest parameter because all registers
* get clobbered when setting up the C environment.
STRAND_PUSH(%g2, %g3, %g4)
! retrieve the pointer to the guest to stop
mov GUEST_EXIT_MACH_EXIT, %o1
* Configures a basic C compatible environment
* based on the current vcpu setup.
* The only working assumption here is that coming in
* the caller has already set gl and tl to 0, so we do not
* have to worry about preserving the parameters.
wrpr %g0, NWINDOWS-2, %cansave
wrpr %g0, NWINDOWS-1, %cleanwin
! Other stuff here ... pstate, gis etc. FIXME
set STRAND_STACK_SIZE - STACK_BIAS, %g2
add %g1, -SA(MINFRAME), %sp
SET_SIZE(setup_c_environ)
! %o0 = address of 32 bit value
! %o1 = value to compare against
! %o0 = value stored in location
casa [%o0]ASI_P, %o1, %o2
! %o0 = address of 64 bit value
! %o1 = value to compare against
! %o0 = value stored in location
casxa [%o0]ASI_P, %o1, %o2
! atomic swap ... compare and swap until we succeed.
! %o0 = address of 64 bit value
! %o0 = value stored in location
casxa [%o0]ASI_P, %o2, %o3
SET_SIZE(c_atomic_swap64)
! Returns a pointer to the strand_t struct
! for the strand we are currently executing on