* ========== Copyright Header Begin ==========================================
* Hypervisor Software File: subr.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 "@(#)subr.s 1.30 07/09/11 SMI"
* Various support routines
#include <sys/asm_linkage.h>
#include <devices/pc16550.h>
* memscrub - zero memory using Niagara blk-init stores
* Assumes cache-line alignment and counts
* Note that the block initializing store only zeros the
* whole cacheline if the address is at the start of the
* cacheline and the line is not in the L2 cache. Otherwise
* the existing cacheline contents are retained other
* than the specifically stored value.
#if defined(CONFIG_FPGA) || defined(T1_FPGA) /* running on real hardware */
#ifndef T1_FPGA_MEMORY_PREINIT
stxa %g0, [%g1 + 0x00]%asi
stxa %g0, [%g1 + 0x08]%asi
stxa %g0, [%g1 + 0x10]%asi
stxa %g0, [%g1 + 0x18]%asi
stxa %g0, [%g1 + 0x20]%asi
stxa %g0, [%g1 + 0x28]%asi
stxa %g0, [%g1 + 0x30]%asi
stxa %g0, [%g1 + 0x38]%asi
#endif /* ifndef T1_FPGA_MEMORY_PREINIT */
#endif /* if defined(CONFIG_FPGA) || defined(T1_FPGA) */
* Assumes 8-byte alignment and counts
#ifdef CONFIG_LEGIONBCOPY
* Use a legion magic-trap to do the copy
* do alignment test to catch programming errors
ta %xcc, LEGION_MAGICTRAP_PABCOPY
brz %g4, 2f ! %g4 == 0 successful
#ifdef CONFIG_LEGIONBCOPY
* bcopy - short byte-aligned copies
#ifdef CONFIG_LEGIONBCOPY
* Use a legion magic-trap to do the copy
ta %xcc, LEGION_MAGICTRAP_PABCOPY
brz %g4, 2f ! %g4 == 0 successful
#ifdef CONFIG_LEGIONBCOPY
* bzero - short byte-aligned zero operations
* NOTE: If we ever need to bzero larger chunks of memory
* we need to adapt this to do a more optimized bzero operation
SMALL_ZERO_MACRO(%g1, %g2)
* Puts - print a string on the debug uart
* Check if enough initialization has
* taken place to send the message to
* the vbsc hypervisor console.
brz,pn %g2, .puts_try_hvuart
STRAND_PUSH(%g7, %g2, %g3)
setx FPGA_UART_BASE, %g3, %g2
ldub [%g2 + LSR_ADDR], %g3
ldub [%g2 + LSR_ADDR], %g3
* putx - print a 64-bit xword on the debug uart
* Check if enough initialization has
* taken place to send the message to
* the vbsc hypervisor console.
brz,pn %g2, .putx_try_hvuart
STRAND_PUSH(%g7, %g2, %g3)
STRAND_PUSH(%g6, %g2, %g3)
setx FPGA_UART_BASE, %g3, %g2
ldub [%g2 + LSR_ADDR], %g4
.ascii "0123456789abcdef"
ldub [%g2 + LSR_ADDR], %g5
* uart_init - initialize the debug uart
* Supports only 16550 UART
* %g1 is UART base address
ldub [%g1 + LSR_ADDR], %g2 ! read LSR
stb %g0, [%g1 + IER_ADDR] ! clear IER
stb %g0, [%g1 + FCR_ADDR] ! clear FCR, disable FIFO
mov (FCR_XMIT_RESET | FCR_RCVR_RESET), %g3
stb %g3, [%g1 + FCR_ADDR] ! reset FIFOs in FCR
stb %g3, [%g1 + FCR_ADDR] ! FCR enable FIFO
mov (LCR_DLAB | LCR_8N1), %g3
stb %g3, [%g1 + LCR_ADDR] ! set LCR for 8-n-1, set DLAB
#ifdef UART_CLOCK_MULTIPLIER
mulx %g3, UART_CLOCK_MULTIPLIER, %g3
stb %g3, [%g1 + DLL_ADDR] ! set baud rate = 9600
stb %g0, [%g1 + DLM_ADDR] ! set MS = 0
mov LCR_8N1, %g3 ! set LCR for 8-n-1, unset DLAB
stb %g3, [%g1 + LCR_ADDR] ! set LCR for 8-n-1, unset DLAB
#endif /* CONFIG_HVUART */
* These routines are called from softtrap handlers.
* We do this so that debug printing does not trample all over
* the registers you are using.
* Save the state of a virtual cpu into a save area
* * Move this code into platform specific area - or at least a
* portion of it. Platform specific CPUs may have additional state
* * Clobber tick interrupts - don't care about tick_cmr register.
* * Handle stick interrupts .. a stick interrupt may have retired while
* state was saved - in which case we must manually create the
* * Save and restore the floating point registers .. dont forget to
* to look and see if pstate.pef etc are enabled ...
* ... capture any deferred traps if there are any on a given cpu.
* * Save and restore graphics status.
* * Save and restore the 4v queue registers.
* * Fix to save all the G's and trap stack registers from tl=0 to maxptl
* clobbers: Everything - returns back with TL & GL=0 and
ENTRY_NP(vcpu_state_save)
set CPU_STATE_SAVE_AREA, %g1
! First step - save trap stack and registers
add %g1, VS_TRAPSTACK, %g2
mulx %g3, VCPUTRAPSTATE_SIZE, %g4
stx %g5, [%g4 + VCTS_TPC]
stx %g5, [%g4 + VCTS_TNPC]
stx %g5, [%g4 + VCTS_TSTATE]
stx %g5, [%g4 + VCTS_HTSTATE]
#if 0 /* { FIXME: workaround fp-diabled trap */
stx %g2, [%g1 + VS_STICK]
stx %g2, [%g1 + VS_STICKCOMPARE]
! IMPORTANT: We save softint last just incase a tick compare
! got triggered between when we saved stick and stick compare
stx %g2, [%g1 + VS_SOFTINT]
#define STORESCRATCH(regnum) \
mov ((regnum) * 8), %g3 ;\
ldxa [%g3]ASI_SCRATCHPAD, %g2 ;\
stx %g2, [%g1 + VS_SCRATCHPAD + ((regnum) * 8)]
! scratchpads 4 & 5 dont exist for a Niagara
* NOTE: FIXME saving and restoring the Q registers is postoned until
* we actually want to context switch. The reason is simply that
* the current LDC and x-call code deliver their mondos by
* manipulating the head and tail registers of the local strand
* and if we end up sending a message to ourselves (say in the
* hvctl code) then we end up restoring the old Q values and not
* So for now the Q values stay on the chip until the mondo
* delivery schemes (LDC x-call etc.) have been modified
! Save the queue registers
! Now we restore the queue registers
set _name/**/_QUEUE_HEAD, %g2 ;\
ldxa [%g2]ASI_QUEUE, %g2 ;\
sth %g2, [%g1 + VS_/**/_name/**/_HEAD] ;\
set _name/**/_QUEUE_TAIL, %g2 ;\
ldxa [%g2]ASI_QUEUE, %g2 ;\
sth %g2, [%g1 + VS_/**/_name/**/_TAIL]
STOREQ(ERROR_NONRESUMABLE)
stx %g2, [%g1 + VS_WSTATE]
stx %g2, [%g1 + VS_CANSAVE]
stx %g2, [%g1 + VS_CANRESTORE]
stx %g2, [%g1 + VS_OTHERWIN]
stx %g2, [%g1 + VS_CLEANWIN]
stx %l2, [%g3 + (10 * 8)]
stx %l3, [%g3 + (11 * 8)]
stx %l4, [%g3 + (12 * 8)]
stx %l5, [%g3 + (13 * 8)]
stx %l6, [%g3 + (14 * 8)]
stx %l7, [%g3 + (15 * 8)]
add %g3, RWINDOW_SIZE, %g3
mov %g7, %l1 ! preserve callers return address
rdpr %gl, %l2 ! preserve original %gl
! Stash all the globals except the current ones
add %l4, VCPU_GLOBALS_SIZE, %l4
SET_SIZE(vcpu_state_save)
* Restore guest partition from save area
* clobbers: Everything ..
* We retore in the reverse order to the save, and
* We return back to the caller using the address in %g7
* This function changes gl and tl back to the values
* stored in the vcpus save area.
* We enter with the pointer to the vcpu to be restored
* in the vcpu hscratch register - the assumption is that that
* has already been set correctly.
ENTRY_NP(vcpu_state_restore)
set CPU_STATE_SAVE_AREA, %l1
! Restore all the globals up to but NOT including the save GL
add %l4, VCPU_GLOBALS_SIZE, %l4
! We land here with the globals restored
! and gl set to the hypervisors Gs above
! the vcpu context - move all the register
! values from locals back to Gs.
mov %l7, %g7 ! return address
mov %l0, %g6 ! vcpu struct
mov %l1, %g1 ! vcpu struct save area
! Now restore all the register windows
ldx [%g3 + (10 * 8)], %l2
ldx [%g3 + (11 * 8)], %l3
ldx [%g3 + (12 * 8)], %l4
ldx [%g3 + (13 * 8)], %l5
ldx [%g3 + (14 * 8)], %l6
ldx [%g3 + (15 * 8)], %l7
add %g3, RWINDOW_SIZE, %g3
! restore the window management registers
ldx [%g1 + VS_CLEANWIN], %g2
ldx [%g1 + VS_OTHERWIN], %g2
ldx [%g1 + VS_CANRESTORE], %g2
ldx [%g1 + VS_CANSAVE], %g2
ldx [%g1 + VS_WSTATE], %g2
#if 0 /* { FIXME: See note in state_save about Q registers */
! Now we restore the queue registers
#define RESTOREQ(_name) \
lduh [%g1 + VS_/**/_name/**/_HEAD], %g2 ;\
set _name/**/_QUEUE_HEAD, %g3 ;\
stxa %g2, [%g3]ASI_QUEUE ;\
lduh [%g1 + VS_/**/_name/**/_TAIL], %g2 ;\
set _name/**/_QUEUE_TAIL, %g3 ;\
RESTOREQ(ERROR_RESUMABLE)
RESTOREQ(ERROR_NONRESUMABLE)
! Restore the scratchpads
#define RESTORESCRATCH(regnum) \
ldx [%g1 + VS_SCRATCHPAD + ((regnum) * 8)], %g2 ;\
mov ((regnum) * 8), %g3 ;\
stxa %g2, [%g3]ASI_SCRATCHPAD
! scratchpads 4 & 5 dont exist for a Niagara
#if 0 /* { FIXME: workaround fp disabled trap */
ldx [%g1 + VS_SOFTINT], %g2
ldx [%g1 + VS_STICKCOMPARE], %g2 ! FIXME: check me
! restoration has side effects ... if stick has passed stick compare
! since we saved, then we manually set the softint bit, since
! the HW will have missed the event while the vcpu was
! NOTE softint has to already be setup first
! NOTE stick compare is already setup so we get a match while were
! fiddling with this, the HW will set the match bit for us
! We ignore tick_cmpr since it's not part of the sun4v
! If stick cmp int_dis is 1 then stick interrupts are
! disabled, so no further action is necessary
brlz %g2, 1f ! int_dis is bit 63 (sign bit)
! Nothing to do if stick had already passed stick_cmpr
ldx [%g1 + VS_STICK], %g3
srlx %g3, 1, %g3 ! ignore the npt bit
! Nothing to do if stick hasn't reached stick_cmpr yet
sethi %hi(SOFTINT_SM_BIT), %g4
! Now we restore the trapstack back up to TL
add %g1, VS_TRAPSTACK, %g3
ldx [%g3 + VCTS_TPC], %g5
ldx [%g3 + VCTS_TNPC], %g5
ldx [%g3 + VCTS_TSTATE], %g5
ldx [%g3 + VCTS_HTSTATE], %g5
add %g3, VCPUTRAPSTATE_SIZE, %g3
!wait for changes to take effect
SET_SIZE(vcpu_state_restore)
* Print contents of important registers.
PRINT("tl 0x"); rdpr %tl, %g1; PRINTX(%g1)
PRINT(" gl 0x"); rdpr %gl, %g1; PRINTX(%g1)
PRINT(" tt 0x"); rdpr %tt, %g1; PRINTX(%g1)
PRINT(" tpc 0x"); rdpr %tpc, %g1; PRINTX(%g1)
PRINT(" tnpc 0x"); rdpr %tnpc, %g1; PRINTX(%g1)
PRINT(" tstate 0x"); rdpr %tstate, %g1; PRINTX(%g1)
PRINT(" htstate 0x"); rdhpr %htstate, %g1; PRINTX(%g1)
PRINT(" wstate 0x"); rdpr %wstate, %g1; PRINTX(%g1)
PRINT(" cansave 0x"); rdpr %cansave, %g1; PRINTX(%g1)
PRINT(" canrestore 0x");rdpr %canrestore, %g1;PRINTX(%g1)
PRINT(" otherwin 0x"); rdpr %otherwin, %g1; PRINTX(%g1)
PRINT(" cleanwin 0x"); rdpr %cleanwin, %g1; PRINTX(%g1)
PRINT(" cwp 0x"); rdpr %cwp, %g1; PRINTX(%g1)
PRINT(" tba 0x"); rdpr %tba, %g1; PRINTX(%g1)
PRINT(" y 0x"); rd %y, %g1; PRINTX(%g1)
PRINT(" asi 0x"); rd %asi, %g1; PRINTX(%g1)
#if 0 /* { FIXME: work around fp disabled trap*/
PRINT(" gsr 0x"); rd %gsr, %g1; PRINTX(%g1)
PRINT(" pil 0x"); rdpr %pil, %g1; PRINTX(%g1)
PRINT(" stickcmp 0x"); rd STICKCMP, %g1; PRINTX(%g1)
PRINT(" softint 0x"); rd %softint, %g1; PRINTX(%g1)
PRINT(" sc0 0x"); mov (0*8),%g1;ldxa [%g1]ASI_SCRATCHPAD,%g1;PRINTX(%g1)
PRINT(" sc1 0x"); mov (1*8),%g1;ldxa [%g1]ASI_SCRATCHPAD,%g1;PRINTX(%g1)
PRINT(" sc2 0x"); mov (2*8),%g1;ldxa [%g1]ASI_SCRATCHPAD,%g1;PRINTX(%g1)
PRINT(" sc3 0x"); mov (3*8),%g1;ldxa [%g1]ASI_SCRATCHPAD,%g1;PRINTX(%g1)
PRINT(" sc6 0x"); mov (6*8),%g1;ldxa [%g1]ASI_SCRATCHPAD,%g1;PRINTX(%g1)
PRINT(" sc7 0x"); mov (7*8),%g1;ldxa [%g1]ASI_SCRATCHPAD,%g1;PRINTX(%g1)
rdpr %cwp, %g3 ! preserve
PRINT("Window 0x"); PRINTX(%g2); PRINT("\r\n");
PRINT("i0 0x"); PRINTX(%i0); PRINT(" ")
PRINT("i1 0x"); PRINTX(%i1); PRINT(" ")
PRINT("i2 0x"); PRINTX(%i2); PRINT(" ")
PRINT("i3 0x"); PRINTX(%i3); PRINT(" ")
PRINT("i4 0x"); PRINTX(%i4); PRINT(" ")
PRINT("i5 0x"); PRINTX(%i5); PRINT(" ")
PRINT("i6 0x"); PRINTX(%i6); PRINT(" ")
PRINT("i7 0x"); PRINTX(%i7); PRINT(" ")
PRINT("l0 0x"); PRINTX(%l0); PRINT(" ")
PRINT("l1 0x"); PRINTX(%l1); PRINT(" ")
PRINT("l2 0x"); PRINTX(%l2); PRINT(" ")
PRINT("l3 0x"); PRINTX(%l3); PRINT(" ")
PRINT("l4 0x"); PRINTX(%l4); PRINT(" ")
PRINT("l5 0x"); PRINTX(%l5); PRINT(" ")
PRINT("l6 0x"); PRINTX(%l6); PRINT(" ")
PRINT("l7 0x"); PRINTX(%l7); PRINT(" ")
* spinlock_enter(uint64_t *lock)
* For calling from C code. In asm code use the SPINLOCK_ENTER macro.
ldub [%o1 + STRAND_ID], %o2
* spinlock_exit(uint64_t *lock)
* For calling from C code. In asm code use the SPINLOCK_EXIT macro.
* Get the stick value from the current strand