cpr_resume_setup.s revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#if defined(lint)
#include <sys/types.h>
#else /* lint */
#include "assym.h"
#endif /* lint */
#include <sys/asm_linkage.h>
#include <sys/machthread.h> /* for reg definition */
#include <sys/machasi.h> /* sun4u ASI */
#include <sys/mmu.h>
#include <sys/privregs.h>
#include <sys/machparam.h>
#include <vm/hat_sfmmu.h>
#include <sys/cpr_impl.h>
#include <sys/intreg.h>
#include <sys/clock.h>
/*
* resume kernel entry point from cprboot
* 1. restore I/D TSB registers
* 2. restore primary and secondary context registers
* 3. initialize cpu state registers
* 4. set up the thread and lwp registers for the cpr process
* 5. switch to kernel trap
* 6. restore checkpoint pc and stack pointer
* 7. longjmp back to kernel
*
* registers from cprboot:exit_to_kernel()
* %o0 prom cookie
* %o1 struct sun4u_machdep *mdp
*
* Any change to this register assignment
* require changes to cprboot_srt0.s
*/
#if defined(lint)
/* ARGSUSED */
void
i_cpr_resume_setup(void *cookie, csu_md_t *mdp)
{}
/* ARGSUSED */
int
i_cpr_cif_wrapper(void *args)
{ return (0); }
/* ARGSUSED */
void
dtlb_wr_entry(uint_t index, tte_t *tte, uint64_t *va_tag)
{}
/* ARGSUSED */
void
itlb_wr_entry(uint_t index, tte_t *tte, uint64_t *va_tag)
{}
#else /* lint */
!
! reserve 4k for cpr tmp stack; tstack should be first,
! any new data symbols should be added after tstack.
!
.seg ".data"
.global i_cpr_data_page, i_cpr_tstack_size
.global i_cpr_orig_cif
.align MMU_PAGESIZE
i_cpr_data_page:
.skip 4096
i_cpr_tstack:
.word 0
i_cpr_tstack_size:
.word 4096
.align 8
prom_tba:
.word 0, 0
i_cpr_orig_cif:
.nword 0
i_cpr_tmp_cif:
.nword 0
!
! set text to begin at a page boundary so we can
! map this one page and jump to it from cprboot
!
.seg ".text"
.align MMU_PAGESIZE
ENTRY(i_cpr_resume_setup)
!
! save %o args to locals
!
mov %o0, %l4
mov %o1, %l5
!
! Restore PCONTEXT
!
sethi %hi(FLUSH_ADDR), %g3
ld [%l5 + CPR_MD_PRI], %g1 ! mdp->mmu_ctx_pri
set MMU_PCONTEXT, %g2
stxa %g1, [%g2]ASI_DMMU
flush %g3
!
! Restore SCONTEXT. We do not need to set up the TSB
! registers. Since we are restoring INVALID_CONTEXT into
! the secondary context the HAT will do that for us.
!
ld [%l5 + CPR_MD_SEC], %g1 ! mdp->mmu_ctx_sec
set MMU_SCONTEXT, %g2
stxa %g1, [%g2]ASI_DMMU
flush %g3
!
! Allow user rdtick, and rdstick if applicable
!
CLEARTICKNPT
!
! copy saved thread pointer to %g7
!
ldx [%l5 + CPR_MD_THRP], THREAD_REG ! mdp->thrp
!
! since csu_md_t lives in a cprboot data page,
! copy select data to registers for later use
! before freeing cprboot text/data pages
!
ldx [%l5 + CPR_MD_QSAV_PC], %l7 ! l7 = mdp->qsav_pc
ldx [%l5 + CPR_MD_QSAV_SP], %l6 ! l6 = mdp->qsav_sp
!
! save cookie from the new/tmp prom
!
set i_cpr_tmp_cif, %g1
stn %l4, [%g1]
!
! save prom tba
!
set prom_tba, %g1
rdpr %tba, %g2
stx %g2, [%g1]
!
! start slave cpus, pause them within kernel text,
! and restore the original prom pages
!
call i_cpr_mp_setup
nop
!
! since this routine is entered only by a jmp from cprboot,
! we can set cpr_suspend_succeeded here
!
set cpr_suspend_succeeded, %l0
mov 1, %l1
st %l1, [%l0]
!
! special shortened version of longjmp
! Don't need to flushw
!
mov %l7, %i7 ! i7 = saved pc
mov %l6, %fp ! i6 = saved sp
ret ! return 1
restore %g0, 1, %o0 ! takes underflow, switches stack
SET_SIZE(i_cpr_resume_setup)
!
! while running on the new/tmp prom, the prom's trap table
! must be used to handle translations within prom space
! since the kernel's mappings may not match this prom.
!
! always set %tba to the prom's trap table before calling
! any prom service; after returning, read %tba again;
! if the %tba wasn't changed by the prom service,
! restore the original %tba.
!
! a call stack looks like this:
!
! current prom cookie
! [i_cpr_cif_wrapper]
! client_handler
! p1275_sparc_cif_handler
! prom_xxx
!
ENTRY(i_cpr_cif_wrapper)
save %sp, -SA64(MINFRAME64 + 8), %sp
rdpr %tba, %o5 ! read original %tba
stx %o5, [%fp + V9BIAS64 - 8]
set prom_tba, %l4
ldx [%l4], %o4 ! read prom_tba
wrpr %o4, %tba ! switch to prom trap table
set i_cpr_tmp_cif, %g3 ! cookie for new/tmp prom
ldn [%g3], %g4
jmpl %g4, %o7 ! call prom service
mov %i0, %o0
ldx [%l4], %o4 ! read prom_tba
rdpr %tba, %o3 ! read current %tba
cmp %o3, %o4 ! did prom change %tba ?
bne,pn %xcc, 1f ! yes, dont reset %tba
nop
ldx [%fp + V9BIAS64 - 8], %o5
wrpr %o5, %tba ! no change, restore orignal
1:
ret
restore %g0, %o0, %o0
SET_SIZE(i_cpr_cif_wrapper)
!
! write dtlb entry at index
!
ENTRY(dtlb_wr_entry)
sllx %o0, 3, %o0 ! index << 3
ldx [%o1], %o5 ! o5 = tte.ll
ldx [%o2], %o4 ! o4 = va_tag
srlx %o4, MMU_PAGESHIFT, %o4 ! clear any page offset
sllx %o4, MMU_PAGESHIFT, %o4 ! o4 = va_tag & PAGEMASK
set MMU_TAG_ACCESS, %o3
stxa %o4, [%o3]ASI_DMMU
stxa %o5, [%o0]ASI_DTLB_ACCESS
membar #Sync
retl
nop
SET_SIZE(dtlb_wr_entry)
!
! write itlb entry at index
!
ENTRY(itlb_wr_entry)
sllx %o0, 3, %o0 ! index << 3
ldx [%o1], %o5 ! o5 = tte.ll
ldx [%o2], %o4 ! o4 = va_tag
srlx %o4, MMU_PAGESHIFT, %o4 ! clear any page offset
sllx %o4, MMU_PAGESHIFT, %o4 ! o4 = va_tag & PAGEMASK
set MMU_TAG_ACCESS, %o3
stxa %o4, [%o3]ASI_IMMU
stxa %o5, [%o0]ASI_ITLB_ACCESS
membar #Sync
retl
nop
SET_SIZE(itlb_wr_entry)
#endif /* !lint */