d0ce9a7e07
back into the calling MD code. The MD code must ensure no races between checking the astpening flag and returning to usermode. Submitted by: peter (ia64 bits) Tested on: alpha (peter, jeff), i386, ia64 (peter), sparc64
1546 lines
35 KiB
ArmAsm
1546 lines
35 KiB
ArmAsm
/*-
|
|
* Copyright (c) 2000 Doug Rabson
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions 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.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
* $FreeBSD$
|
|
*/
|
|
|
|
#include <machine/asm.h>
|
|
#include <machine/pte.h>
|
|
#include <assym.s>
|
|
|
|
/*
|
|
* ar.k7 = curthread
|
|
* ar.k6 = ksp
|
|
* ar.k5 = kbsp
|
|
* ar.k4 = pcpup
|
|
*/
|
|
|
|
/*
|
|
* Call exception_save_regs to preserve the interrupted state in a
|
|
* trapframe. Note that we don't use a call instruction because we
|
|
* must be careful not to lose track of the RSE state. We then call
|
|
* trap() with the value of _n_ as an argument to handle the
|
|
* exception. We arrange for trap() to return to exception_restore
|
|
* which will restore the interrupted state before executing an rfi to
|
|
* resume it.
|
|
*/
|
|
#define TRAP(_n_) \
|
|
mov r16=b0; \
|
|
1: mov r17=ip;; \
|
|
add r17=2f-1b,r17;; \
|
|
mov b0=r17; \
|
|
br.sptk.few exception_save; \
|
|
2: (p3) ssm psr.i; \
|
|
alloc r15=ar.pfs,0,0,3,0; \
|
|
mov out0=_n_; \
|
|
mov out1=r14; \
|
|
mov out2=sp;; \
|
|
add sp=-16,sp;; \
|
|
.prologue; \
|
|
.save rp,r0; \
|
|
.body; \
|
|
br.call.sptk.few rp=trap; \
|
|
3: br.sptk.many exception_restore
|
|
|
|
/*
|
|
* The IA64 Interrupt Vector Table (IVT) contains 20 slots with 64
|
|
* bundles per vector and 48 slots with 16 bundles per vector.
|
|
*/
|
|
|
|
.section .text.ivt,"ax"
|
|
|
|
.align 32768
|
|
.global ia64_vector_table
|
|
ia64_vector_table:
|
|
|
|
.org ia64_vector_table + 0x0000 // VHPT Translation vector
|
|
interruption_VHPT_Translation:
|
|
TRAP(0)
|
|
|
|
.org ia64_vector_table + 0x0400 // Instruction TLB vector
|
|
interruption_Instruction_TLB:
|
|
mov r16=cr.ifa
|
|
mov r17=pr
|
|
;;
|
|
thash r18=r16
|
|
ttag r19=r16
|
|
;;
|
|
add r21=16,r18 // tag
|
|
add r20=24,r18 // collision chain
|
|
;;
|
|
ld8 r21=[r21] // check VHPT tag
|
|
;;
|
|
cmp.ne p1,p0=r21,r19
|
|
(p1) br.dpnt.few 1f
|
|
;;
|
|
ld8 r21=[r18] // read pte
|
|
;;
|
|
itc.i r21 // insert pte
|
|
rfi // done
|
|
;;
|
|
1: ld8 r20=[r20] // first entry
|
|
;;
|
|
rsm psr.dt // turn off data translations
|
|
;;
|
|
srlz.d // serialize
|
|
;;
|
|
2: cmp.eq p1,p0=r0,r20 // done?
|
|
(p1) br.cond.spnt.few 9f // bail if done
|
|
;;
|
|
add r21=16,r20 // tag location
|
|
;;
|
|
ld8 r21=[r21] // read tag
|
|
;;
|
|
cmp.ne p1,p0=r21,r19 // compare tags
|
|
(p1) br.cond.sptk.few 3f // if not, read next in chain
|
|
;;
|
|
ld8 r21=[r20],8 // read pte
|
|
;;
|
|
ld8 r22=[r20] // read rest of pte
|
|
;;
|
|
dep r18=0,r18,61,3 // convert vhpt ptr to physical
|
|
;;
|
|
add r20=16,r18 // address of tag
|
|
;;
|
|
ld8.acq r23=[r20] // read old tag
|
|
;;
|
|
dep r23=-1,r23,63,1 // set ti bit
|
|
;;
|
|
st8.rel [r20]=r23 // store old tag + ti
|
|
;;
|
|
mf // make sure everyone sees
|
|
;;
|
|
st8 [r18]=r21,8 // store pte
|
|
;;
|
|
st8 [r18]=r22,8
|
|
;;
|
|
st8.rel [r18]=r19 // store new tag
|
|
;;
|
|
mov pr=r17,0x1ffff // restore predicates
|
|
;;
|
|
itc.i r21 // and place in TLB
|
|
rfi
|
|
|
|
3: add r20=24,r20 // next in chain
|
|
;;
|
|
ld8 r20=[r20] // read chain
|
|
br.cond.sptk.few 2b // loop
|
|
|
|
9: mov pr=r17,0x1ffff // restore predicates
|
|
ssm psr.dt
|
|
;;
|
|
srlz.d
|
|
;;
|
|
TRAP(20) // Page Not Present trap
|
|
|
|
.org ia64_vector_table + 0x0800 // Data TLB vector
|
|
interruption_Data_TLB:
|
|
mov r16=cr.ifa
|
|
mov r17=pr
|
|
;;
|
|
thash r18=r16
|
|
ttag r19=r16
|
|
;;
|
|
add r21=16,r18 // tag
|
|
add r20=24,r18 // collision chain
|
|
;;
|
|
ld8 r21=[r21] // check VHPT tag
|
|
;;
|
|
cmp.ne p1,p0=r21,r19
|
|
(p1) br.dpnt.few 1f
|
|
;;
|
|
ld8 r21=[r18] // read pte
|
|
;;
|
|
itc.d r21 // insert pte
|
|
rfi // done
|
|
;;
|
|
1: ld8 r20=[r20] // first entry
|
|
;;
|
|
rsm psr.dt // turn off data translations
|
|
;;
|
|
srlz.d // serialize
|
|
;;
|
|
2: cmp.eq p1,p0=r0,r20 // done?
|
|
(p1) br.cond.spnt.few 9f // bail if done
|
|
;;
|
|
add r21=16,r20 // tag location
|
|
;;
|
|
ld8 r21=[r21] // read tag
|
|
;;
|
|
cmp.ne p1,p0=r21,r19 // compare tags
|
|
(p1) br.cond.sptk.few 3f // if not, read next in chain
|
|
;;
|
|
ld8 r21=[r20],8 // read pte
|
|
;;
|
|
ld8 r22=[r20] // read rest of pte
|
|
;;
|
|
dep r18=0,r18,61,3 // convert vhpt ptr to physical
|
|
;;
|
|
add r20=16,r18 // address of tag
|
|
;;
|
|
ld8.acq r23=[r20] // read old tag
|
|
;;
|
|
dep r23=-1,r23,63,1 // set ti bit
|
|
;;
|
|
st8.rel [r20]=r23 // store old tag + ti
|
|
;;
|
|
mf // make sure everyone sees
|
|
;;
|
|
st8 [r18]=r21,8 // store pte
|
|
;;
|
|
st8 [r18]=r22,8
|
|
;;
|
|
st8.rel [r18]=r19 // store new tag
|
|
;;
|
|
mov pr=r17,0x1ffff // restore predicates
|
|
;;
|
|
itc.d r21 // and place in TLB
|
|
rfi
|
|
|
|
3: add r20=24,r20 // next in chain
|
|
;;
|
|
ld8 r20=[r20] // read chain
|
|
br.cond.sptk.few 2b // loop
|
|
|
|
9: mov pr=r17,0x1ffff // restore predicates
|
|
ssm psr.dt
|
|
;;
|
|
srlz.d
|
|
;;
|
|
TRAP(20) // Page Not Present trap
|
|
|
|
.org ia64_vector_table + 0x0c00 // Alternate ITLB vector
|
|
interruption_Alternate_Instruction_TLB:
|
|
mov r16=cr.ifa // where did it happen
|
|
mov r18=pr // save predicates
|
|
;;
|
|
extr.u r17=r16,61,3 // get region number
|
|
;;
|
|
cmp.ge p3,p0=5,r17 // RR0-RR5?
|
|
cmp.eq p1,p2=7,r17 // RR7->p1, RR6->p2
|
|
(p3) br.spnt 9f
|
|
;;
|
|
(p1) movl r17=PTE_P+PTE_MA_WB+PTE_A+PTE_D+PTE_PL_KERN+PTE_AR_RX
|
|
(p2) movl r17=PTE_P+PTE_MA_UC+PTE_A+PTE_D+PTE_PL_KERN+PTE_AR_RX
|
|
;;
|
|
dep r16=0,r16,50,14 // clear bits above PPN
|
|
;;
|
|
dep r16=r17,r16,0,12 // put pte bits in 0..11
|
|
;;
|
|
itc.i r16
|
|
mov pr=r18,0x1ffff // restore predicates
|
|
;;
|
|
rfi
|
|
9: mov pr=r18,0x1ffff // restore predicates
|
|
TRAP(3)
|
|
|
|
.org ia64_vector_table + 0x1000 // Alternate DTLB vector
|
|
interruption_Alternate_Data_TLB:
|
|
mov r16=cr.ifa // where did it happen
|
|
mov r18=pr // save predicates
|
|
;;
|
|
extr.u r17=r16,61,3 // get region number
|
|
;;
|
|
cmp.ge p3,p0=5,r17 // RR0-RR5?
|
|
cmp.eq p1,p2=7,r17 // RR7->p1, RR6->p2
|
|
(p3) br.spnt 9f
|
|
;;
|
|
(p1) movl r17=PTE_P+PTE_MA_WB+PTE_A+PTE_D+PTE_PL_KERN+PTE_AR_RW
|
|
(p2) movl r17=PTE_P+PTE_MA_UC+PTE_A+PTE_D+PTE_PL_KERN+PTE_AR_RW
|
|
;;
|
|
dep r16=0,r16,50,14 // clear bits above PPN
|
|
;;
|
|
dep r16=r17,r16,0,12 // put pte bits in 0..11
|
|
;;
|
|
itc.d r16
|
|
mov pr=r18,0x1ffff // restore predicates
|
|
;;
|
|
rfi
|
|
9: mov pr=r18,0x1ffff // restore predicates
|
|
TRAP(4)
|
|
|
|
.org ia64_vector_table + 0x1400 // Data Nested TLB vector
|
|
interruption_Data_Nested_TLB:
|
|
TRAP(5)
|
|
|
|
.org ia64_vector_table + 0x1800 // Instr. Key Miss vector
|
|
interruption_Instruction_Key_Miss:
|
|
TRAP(6)
|
|
|
|
.org ia64_vector_table + 0x1c00 // Data Key Miss vector
|
|
interruption_Data_Key_Miss:
|
|
TRAP(7)
|
|
|
|
.org ia64_vector_table + 0x2000 // Dirty-Bit vector
|
|
interruption_Dirty_Bit:
|
|
mov r16=cr.ifa
|
|
mov r17=pr
|
|
mov r20=PAGE_SHIFT<<2 // XXX get page size from VHPT
|
|
;;
|
|
ptc.l r16,r20 // purge TLB
|
|
thash r18=r16
|
|
ttag r19=r16
|
|
;;
|
|
srlz.d
|
|
add r20=24,r18 // collision chain
|
|
;;
|
|
ld8 r20=[r20] // first entry
|
|
;;
|
|
rsm psr.dt // turn off data translations
|
|
;;
|
|
srlz.d // serialize
|
|
;;
|
|
1: cmp.eq p1,p0=r0,r20 // done?
|
|
(p1) br.cond.spnt.few 9f // bail if done
|
|
;;
|
|
add r21=16,r20 // tag location
|
|
;;
|
|
ld8 r21=[r21] // read tag
|
|
;;
|
|
cmp.ne p1,p0=r21,r19 // compare tags
|
|
(p1) br.cond.sptk.few 2f // if not, read next in chain
|
|
;;
|
|
ld8 r21=[r20] // read pte
|
|
mov r22=PTE_D
|
|
;;
|
|
or r21=r22,r21 // set dirty bit
|
|
;;
|
|
st8 [r20]=r21 // store back
|
|
;;
|
|
ld8 r22=[r20] // read rest of pte
|
|
;;
|
|
dep r18=0,r18,61,3 // convert vhpt ptr to physical
|
|
;;
|
|
add r20=16,r18 // address of tag
|
|
;;
|
|
ld8.acq r23=[r20] // read old tag
|
|
;;
|
|
dep r23=-1,r23,63,1 // set ti bit
|
|
;;
|
|
st8.rel [r20]=r23 // store old tag + ti
|
|
;;
|
|
mf // make sure everyone sees
|
|
;;
|
|
st8 [r18]=r21,8 // store pte
|
|
;;
|
|
st8 [r18]=r22,8
|
|
;;
|
|
st8.rel [r18]=r19 // store new tag
|
|
;;
|
|
mov pr=r17,0x1ffff // restore predicates
|
|
;;
|
|
itc.d r21 // and place in TLB
|
|
rfi
|
|
|
|
2: add r20=24,r20 // next in chain
|
|
;;
|
|
ld8 r20=[r20] // read chain
|
|
br.cond.sptk.few 1b // loop
|
|
|
|
9: mov pr=r17,0x1ffff // restore predicates
|
|
TRAP(8) // die horribly
|
|
|
|
.org ia64_vector_table + 0x2400 // Instr. Access-Bit vector
|
|
interruption_Instruction_Access_Bit:
|
|
mov r16=cr.ifa
|
|
mov r17=pr
|
|
mov r20=PAGE_SHIFT<<2 // XXX get page size from VHPT
|
|
;;
|
|
ptc.l r16,r20 // purge TLB
|
|
thash r18=r16
|
|
ttag r19=r16
|
|
;;
|
|
srlz.d
|
|
add r20=24,r18 // collision chain
|
|
;;
|
|
ld8 r20=[r20] // first entry
|
|
;;
|
|
rsm psr.dt // turn off data translations
|
|
;;
|
|
srlz.d // serialize
|
|
;;
|
|
1: cmp.eq p1,p0=r0,r20 // done?
|
|
(p1) br.cond.spnt.few 9f // bail if done
|
|
;;
|
|
add r21=16,r20 // tag location
|
|
;;
|
|
ld8 r21=[r21] // read tag
|
|
;;
|
|
cmp.ne p1,p0=r21,r19 // compare tags
|
|
(p1) br.cond.sptk.few 2f // if not, read next in chain
|
|
;;
|
|
ld8 r21=[r20] // read pte
|
|
mov r22=PTE_A
|
|
;;
|
|
or r21=r22,r21 // set accessed bit
|
|
;;
|
|
st8 [r20]=r21 // store back
|
|
;;
|
|
ld8 r22=[r20] // read rest of pte
|
|
;;
|
|
dep r18=0,r18,61,3 // convert vhpt ptr to physical
|
|
;;
|
|
add r20=16,r18 // address of tag
|
|
;;
|
|
ld8.acq r23=[r20] // read old tag
|
|
;;
|
|
dep r23=-1,r23,63,1 // set ti bit
|
|
;;
|
|
st8.rel [r20]=r23 // store old tag + ti
|
|
;;
|
|
mf // make sure everyone sees
|
|
;;
|
|
st8 [r18]=r21,8 // store pte
|
|
;;
|
|
st8 [r18]=r22,8
|
|
;;
|
|
st8.rel [r18]=r19 // store new tag
|
|
;;
|
|
mov pr=r17,0x1ffff // restore predicates
|
|
;;
|
|
itc.i r21 // and place in TLB
|
|
rfi // walker will retry the access
|
|
|
|
2: add r20=24,r20 // next in chain
|
|
;;
|
|
ld8 r20=[r20] // read chain
|
|
br.cond.sptk.few 1b // loop
|
|
|
|
9: mov pr=r17,0x1ffff // restore predicates
|
|
TRAP(9)
|
|
|
|
.org ia64_vector_table + 0x2800 // Data Access-Bit vector
|
|
interruption_Data_Access_Bit:
|
|
mov r16=cr.ifa
|
|
mov r17=pr
|
|
mov r20=PAGE_SHIFT<<2 // XXX get page size from VHPT
|
|
;;
|
|
ptc.l r16,r20 // purge TLB
|
|
thash r18=r16
|
|
ttag r19=r16
|
|
;;
|
|
srlz.d
|
|
add r20=24,r18 // collision chain
|
|
;;
|
|
ld8 r20=[r20] // first entry
|
|
;;
|
|
rsm psr.dt // turn off data translations
|
|
;;
|
|
srlz.d // serialize
|
|
;;
|
|
1: cmp.eq p1,p0=r0,r20 // done?
|
|
(p1) br.cond.spnt.few 9f // bail if done
|
|
;;
|
|
add r21=16,r20 // tag location
|
|
;;
|
|
ld8 r21=[r21] // read tag
|
|
;;
|
|
cmp.ne p1,p0=r21,r19 // compare tags
|
|
(p1) br.cond.sptk.few 2f // if not, read next in chain
|
|
;;
|
|
ld8 r21=[r20] // read pte
|
|
mov r22=PTE_A
|
|
;;
|
|
or r21=r22,r21 // set accessed bit
|
|
;;
|
|
st8 [r20]=r21 // store back
|
|
;;
|
|
ld8 r22=[r20] // read rest of pte
|
|
;;
|
|
dep r18=0,r18,61,3 // convert vhpt ptr to physical
|
|
;;
|
|
add r20=16,r18 // address of tag
|
|
;;
|
|
ld8.acq r23=[r20] // read old tag
|
|
;;
|
|
dep r23=-1,r23,63,1 // set ti bit
|
|
;;
|
|
st8.rel [r20]=r23 // store old tag + ti
|
|
;;
|
|
mf // make sure everyone sees
|
|
;;
|
|
st8 [r18]=r21,8 // store pte
|
|
;;
|
|
st8 [r18]=r22,8
|
|
;;
|
|
st8.rel [r18]=r19 // store new tag
|
|
;;
|
|
mov pr=r17,0x1ffff // restore predicates
|
|
;;
|
|
itc.d r21 // and place in TLB
|
|
rfi // walker will retry the access
|
|
|
|
2: add r20=24,r20 // next in chain
|
|
;;
|
|
ld8 r20=[r20] // read chain
|
|
br.cond.sptk.few 1b // loop
|
|
|
|
9: mov pr=r17,0x1ffff // restore predicates
|
|
TRAP(10)
|
|
|
|
.org ia64_vector_table + 0x2c00 // Break Instruction vector
|
|
interruption_Break:
|
|
mov r16=pr // save pr for a moment
|
|
mov r17=cr.iim;; // read break value
|
|
mov r18=0x100000;; // syscall number
|
|
cmp.ne p6,p0=r18,r17;; // check for syscall
|
|
(p6) br.dpnt.few 9f
|
|
|
|
mov r17=cr.ipsr;; // check for user mode
|
|
extr.u r17=r17,32,2;;
|
|
cmp.eq p6,p0=r0,r17
|
|
(p6) br.dpnt.few 9f // trap if kernel mode
|
|
|
|
// Note: p6 and p7 are temporaries so we don't need to restore
|
|
// the value of pr here since the user-mode program assumes
|
|
// that syscalls only preserve the function-preserved state.
|
|
|
|
br.sptk.many do_syscall
|
|
;;
|
|
9: mov pr=r16,0x1ffff // restore pr
|
|
TRAP(11)
|
|
|
|
.org ia64_vector_table + 0x3000 // External Interrupt vector
|
|
interruption_External_Interrupt:
|
|
mov r16=b0 // save user's b0
|
|
1: mov r17=ip;; // construct return address
|
|
add r17=2f-1b,r17;; // for exception_save
|
|
mov b0=r17
|
|
br.sptk.few exception_save // 'call' exception_save
|
|
|
|
2: alloc r14=ar.pfs,0,0,2,0 // make a frame for calling with
|
|
|
|
mov out1=sp;;
|
|
add sp=-16,sp;;
|
|
|
|
3: mov out0=cr.ivr // find interrupt vector
|
|
;;
|
|
cmp.eq p6,p0=15,out0 // check for spurious vector number
|
|
(p6) br.dpnt.few exception_restore // if spurious, we are done
|
|
;;
|
|
ssm psr.i // re-enable interrupts
|
|
;; // now that we are in-progress
|
|
srlz.d
|
|
;;
|
|
br.call.sptk.many rp=interrupt // call high-level handler
|
|
|
|
rsm psr.i // disable interrupts
|
|
;;
|
|
srlz.d
|
|
;;
|
|
mov cr.eoi=r0 // and ack the interrupt
|
|
;;
|
|
srlz.d
|
|
br.sptk.few 3b // loop for more
|
|
|
|
.org ia64_vector_table + 0x3400 // Reserved
|
|
interruption_3400:
|
|
TRAP(13)
|
|
|
|
.org ia64_vector_table + 0x3800 // Reserved
|
|
interruption_3800:
|
|
TRAP(14)
|
|
|
|
.org ia64_vector_table + 0x3c00 // Reserved
|
|
interruption_3c00:
|
|
TRAP(15)
|
|
|
|
.org ia64_vector_table + 0x4000 // Reserved
|
|
interruption_4000:
|
|
TRAP(16)
|
|
|
|
.org ia64_vector_table + 0x4400 // Reserved
|
|
interruption_4400:
|
|
TRAP(17)
|
|
|
|
.org ia64_vector_table + 0x4800 // Reserved
|
|
interruption_4800:
|
|
TRAP(18)
|
|
|
|
.org ia64_vector_table + 0x4c00 // Reserved
|
|
interruption_4c00:
|
|
TRAP(19)
|
|
|
|
.org ia64_vector_table + 0x5000 // Page Not Present vector
|
|
interruption_Page_Not_Present:
|
|
TRAP(20)
|
|
|
|
.org ia64_vector_table + 0x5100 // Key Permission vector
|
|
interruption_Key_Permission:
|
|
TRAP(21)
|
|
|
|
.org ia64_vector_table + 0x5200 // Instr. Access Rights vector
|
|
interruption_Instruction_Access_Rights:
|
|
TRAP(22)
|
|
|
|
.org ia64_vector_table + 0x5300 // Data Access Rights vector
|
|
interruption_Data_Access_Rights:
|
|
TRAP(23)
|
|
|
|
.org ia64_vector_table + 0x5400 // General Exception vector
|
|
interruption_General_Exception:
|
|
TRAP(24)
|
|
|
|
.org ia64_vector_table + 0x5500 // Disabled FP-Register vector
|
|
interruption_Disabled_FP_Register:
|
|
TRAP(25)
|
|
|
|
.org ia64_vector_table + 0x5600 // NaT Consumption vector
|
|
interruption_NaT_Consumption:
|
|
TRAP(26)
|
|
|
|
.org ia64_vector_table + 0x5700 // Speculation vector
|
|
interruption_Speculation:
|
|
TRAP(27)
|
|
|
|
.org ia64_vector_table + 0x5800 // Reserved
|
|
interruption_5800:
|
|
TRAP(28)
|
|
|
|
.org ia64_vector_table + 0x5900 // Debug vector
|
|
interruption_Debug:
|
|
TRAP(29)
|
|
|
|
.org ia64_vector_table + 0x5a00 // Unaligned Reference vector
|
|
interruption_Unaligned_Reference:
|
|
TRAP(30)
|
|
|
|
.org ia64_vector_table + 0x5b00 // Unsupported Data Ref. vec.
|
|
interruption_Unsupported_Data_Reference:
|
|
TRAP(31)
|
|
|
|
.org ia64_vector_table + 0x5c00 // Floating-point Fault vector
|
|
interruption_Floating_Point_Fault:
|
|
TRAP(32)
|
|
|
|
.org ia64_vector_table + 0x5d00 // Floating-point Trap vector
|
|
interruption_Floating_Point_Trap:
|
|
TRAP(33)
|
|
|
|
.org ia64_vector_table + 0x5e00 // Lower-Priv. Transfer Trap
|
|
interruption_Lower_Privilege_Transfer_Trap:
|
|
TRAP(34)
|
|
|
|
.org ia64_vector_table + 0x5f00 // Taken Branch Trap vector
|
|
interruption_Taken_Branch_Trap:
|
|
TRAP(35)
|
|
|
|
.org ia64_vector_table + 0x6000 // Single Step Trap vector
|
|
interruption_Single_Step_Trap:
|
|
TRAP(36)
|
|
|
|
.org ia64_vector_table + 0x6100 // Reserved
|
|
interruption_6100:
|
|
TRAP(37)
|
|
|
|
.org ia64_vector_table + 0x6200 // Reserved
|
|
interruption_6200:
|
|
TRAP(38)
|
|
|
|
.org ia64_vector_table + 0x6300 // Reserved
|
|
interruption_6300:
|
|
TRAP(39)
|
|
|
|
.org ia64_vector_table + 0x6400 // Reserved
|
|
interruption_6400:
|
|
TRAP(40)
|
|
|
|
.org ia64_vector_table + 0x6500 // Reserved
|
|
interruption_6500:
|
|
TRAP(41)
|
|
|
|
.org ia64_vector_table + 0x6600 // Reserved
|
|
interruption_6600:
|
|
TRAP(42)
|
|
|
|
.org ia64_vector_table + 0x6700 // Reserved
|
|
interruption_6700:
|
|
TRAP(43)
|
|
|
|
.org ia64_vector_table + 0x6800 // Reserved
|
|
interruption_6800:
|
|
TRAP(44)
|
|
|
|
.org ia64_vector_table + 0x6900 // IA-32 Exception vector
|
|
interruption_IA_32_Exception:
|
|
TRAP(45)
|
|
|
|
.org ia64_vector_table + 0x6a00 // IA-32 Intercept vector
|
|
interruption_IA_32_Intercept:
|
|
TRAP(46)
|
|
|
|
.org ia64_vector_table + 0x6b00 // IA-32 Interrupt vector
|
|
interruption_IA_32_Interrupt:
|
|
TRAP(47)
|
|
|
|
.org ia64_vector_table + 0x6c00 // Reserved
|
|
interruption_6c00:
|
|
TRAP(48)
|
|
|
|
.org ia64_vector_table + 0x6d00 // Reserved
|
|
interruption_6d00:
|
|
TRAP(49)
|
|
|
|
.org ia64_vector_table + 0x6e00 // Reserved
|
|
interruption_6e00:
|
|
TRAP(50)
|
|
|
|
.org ia64_vector_table + 0x6f00 // Reserved
|
|
interruption_6f00:
|
|
TRAP(51)
|
|
|
|
.org ia64_vector_table + 0x7000 // Reserved
|
|
interruption_7000:
|
|
TRAP(52)
|
|
|
|
.org ia64_vector_table + 0x7100 // Reserved
|
|
interruption_7100:
|
|
TRAP(53)
|
|
|
|
.org ia64_vector_table + 0x7200 // Reserved
|
|
interruption_7200:
|
|
TRAP(54)
|
|
|
|
.org ia64_vector_table + 0x7300 // Reserved
|
|
interruption_7300:
|
|
TRAP(55)
|
|
|
|
.org ia64_vector_table + 0x7400 // Reserved
|
|
interruption_7400:
|
|
TRAP(56)
|
|
|
|
.org ia64_vector_table + 0x7500 // Reserved
|
|
interruption_7500:
|
|
TRAP(57)
|
|
|
|
.org ia64_vector_table + 0x7600 // Reserved
|
|
interruption_7600:
|
|
TRAP(58)
|
|
|
|
.org ia64_vector_table + 0x7700 // Reserved
|
|
interruption_7700:
|
|
TRAP(59)
|
|
|
|
.org ia64_vector_table + 0x7800 // Reserved
|
|
interruption_7800:
|
|
TRAP(60)
|
|
|
|
.org ia64_vector_table + 0x7900 // Reserved
|
|
interruption_7900:
|
|
TRAP(61)
|
|
|
|
.org ia64_vector_table + 0x7a00 // Reserved
|
|
interruption_7a00:
|
|
TRAP(62)
|
|
|
|
.org ia64_vector_table + 0x7b00 // Reserved
|
|
interruption_7b00:
|
|
TRAP(63)
|
|
|
|
.org ia64_vector_table + 0x7c00 // Reserved
|
|
interruption_7c00:
|
|
TRAP(64)
|
|
|
|
.org ia64_vector_table + 0x7d00 // Reserved
|
|
interruption_7d00:
|
|
TRAP(65)
|
|
|
|
.org ia64_vector_table + 0x7e00 // Reserved
|
|
interruption_7e00:
|
|
TRAP(66)
|
|
|
|
.org ia64_vector_table + 0x7f00 // Reserved
|
|
interruption_7f00:
|
|
TRAP(67)
|
|
|
|
// Make the IVT 32KB in size
|
|
.org ia64_vector_table + 0x8000
|
|
|
|
.section .data.vhpt,"aw"
|
|
|
|
.global ia64_vhpt
|
|
|
|
.align 32768
|
|
ia64_vhpt: .quad 0
|
|
.align 32768
|
|
|
|
.text
|
|
|
|
#define rIIP r31
|
|
#define rIPSR r30
|
|
#define rISR r29
|
|
#define rIFA r28
|
|
#define rPR r27
|
|
#define rSP r26
|
|
#define rIFS r25
|
|
#define rR1 r24
|
|
#define rR2 r23
|
|
#define rBSPSTORE r22
|
|
#define rRNAT r21
|
|
#define rNDIRTY r27 /* overlay rPR */
|
|
#define rRSC r20
|
|
#define rPFS r19
|
|
#define rB0 r31 /* overlay rIIP */
|
|
|
|
/*
|
|
* exception_restore: restore interrupted state
|
|
*
|
|
* Arguments:
|
|
* sp+16 trapframe pointer
|
|
* r4 ar.pfs before the alloc in TRAP()
|
|
*
|
|
*/
|
|
ENTRY(exception_restore, 0)
|
|
|
|
alloc r14=ar.pfs,0,0,1,0 // in case we call ast()
|
|
add r3=TF_CR_IPSR+16,sp
|
|
;;
|
|
ld8 rIPSR=[r3]
|
|
;;
|
|
extr.u r16=rIPSR,32,2 // extract ipsr.cpl
|
|
;;
|
|
cmp.eq p1,p2=r0,r16 // test for return to kernel mode
|
|
(p1) br.cond.dpnt 2f // skip ast checking for returns to kernel
|
|
3:
|
|
add r3=PC_CURTHREAD,r13 // &curthread
|
|
;;
|
|
ld8 r3=[r3] // curthread
|
|
add r2=(KEF_ASTPENDING|KEF_NEEDRESCHED),r0
|
|
;;
|
|
add r3=TD_KSE,r3 // &curthread->td_kse
|
|
mov r15=psr // save interrupt enable status
|
|
;;
|
|
ld8 r3=[r3] // curkse
|
|
;;
|
|
add r3=KE_FLAGS,r3 // &curkse->ke_flags
|
|
rsm psr.i // disable interrupts
|
|
;;
|
|
ld4 r14=[r3] // fetch curkse->ke_flags
|
|
;;
|
|
and r14=r2,r14 // flags & (KEF_ASTPENDING|KEF_NEEDRESCHED)
|
|
;;
|
|
cmp4.eq p6,p7=r0,r14 // == 0 ?
|
|
(p6) br.cond.dptk 2f
|
|
;;
|
|
mov psr.l=r15 // restore interrups
|
|
;;
|
|
srlz.d
|
|
;;
|
|
add out0=16,sp // trapframe argument to ast()
|
|
br.call.sptk.many rp=ast // note: p1, p2 preserved
|
|
;;
|
|
br 3b
|
|
;;
|
|
2:
|
|
rsm psr.ic|psr.dt|psr.i // disable interrupt collection and vm
|
|
add r3=16,sp;
|
|
;;
|
|
srlz.i
|
|
dep r3=0,r3,61,3 // physical address
|
|
;;
|
|
(p2) add r16=SIZEOF_TRAPFRAME+16,sp // restore ar.k6 (kernel sp)
|
|
;;
|
|
(p2) mov ar.k6=r16
|
|
add r1=SIZEOF_TRAPFRAME-16,r3 // r1=&tf_f[FRAME_F15]
|
|
add r2=SIZEOF_TRAPFRAME-32,r3 // r2=&tf_f[FRAME_F14]
|
|
;;
|
|
ldf.fill f15=[r1],-32 // r1=&tf_f[FRAME_F13]
|
|
ldf.fill f14=[r2],-32 // r2=&tf_f[FRAME_F12]
|
|
;;
|
|
ldf.fill f13=[r1],-32 // r1=&tf_f[FRAME_F11]
|
|
ldf.fill f12=[r2],-32 // r2=&tf_f[FRAME_F10]
|
|
;;
|
|
ldf.fill f11=[r1],-32 // r1=&tf_f[FRAME_F9]
|
|
ldf.fill f10=[r2],-32 // r2=&tf_f[FRAME_F8]
|
|
;;
|
|
ldf.fill f9=[r1],-32 // r1=&tf_f[FRAME_F7]
|
|
ldf.fill f8=[r2],-32 // r2=&tf_f[FRAME_F6]
|
|
;;
|
|
ldf.fill f7=[r1],-24 // r1=&tf_r[FRAME_R31]
|
|
ldf.fill f6=[r2],-16 // r2=&tf_r[FRAME_R30]
|
|
;;
|
|
ld8.fill r31=[r1],-16 // r1=&tf_r[FRAME_R29]
|
|
ld8.fill r30=[r2],-16 // r2=&tf_r[FRAME_R28]
|
|
;;
|
|
ld8.fill r29=[r1],-16 // r1=&tf_r[FRAME_R27]
|
|
ld8.fill r28=[r2],-16 // r2=&tf_r[FRAME_R26]
|
|
;;
|
|
ld8.fill r27=[r1],-16 // r1=&tf_r[FRAME_R25]
|
|
ld8.fill r26=[r2],-16 // r2=&tf_r[FRAME_R24]
|
|
;;
|
|
ld8.fill r25=[r1],-16 // r1=&tf_r[FRAME_R23]
|
|
ld8.fill r24=[r2],-16 // r2=&tf_r[FRAME_R22]
|
|
;;
|
|
ld8.fill r23=[r1],-16 // r1=&tf_r[FRAME_R21]
|
|
ld8.fill r22=[r2],-16 // r2=&tf_r[FRAME_R20]
|
|
;;
|
|
ld8.fill r21=[r1],-16 // r1=&tf_r[FRAME_R19]
|
|
ld8.fill r20=[r2],-16 // r2=&tf_r[FRAME_R18]
|
|
;;
|
|
ld8.fill r19=[r1],-16 // r1=&tf_r[FRAME_R17]
|
|
ld8.fill r18=[r2],-16 // r2=&tf_r[FRAME_R16]
|
|
;;
|
|
ld8.fill r17=[r1],-16 // r1=&tf_r[FRAME_R15]
|
|
ld8.fill r16=[r2],-16 // r2=&tf_r[FRAME_R14]
|
|
;;
|
|
bsw.0 // switch to bank 0
|
|
;;
|
|
ld8.fill r15=[r1],-16 // r1=&tf_r[FRAME_R13]
|
|
ld8.fill r14=[r2],-16 // r2=&tf_r[FRAME_R12]
|
|
;;
|
|
// Don't restore r13 if returning to kernel
|
|
.pred.rel.mutex p1,p2
|
|
(p2) ld8.fill r13=[r1],-16 // r1=&tf_r[FRAME_R11]
|
|
(p1) add r1=-16,r1 // r1=&tf_r[FRAME_R11]
|
|
ld8.fill r12=[r2],-16 // r2=&tf_r[FRAME_R10]
|
|
;;
|
|
ld8.fill r11=[r1],-16 // r1=&tf_r[FRAME_R9]
|
|
ld8.fill r10=[r2],-16 // r2=&tf_r[FRAME_R8]
|
|
;;
|
|
ld8.fill r9=[r1],-16 // r1=&tf_r[FRAME_R7]
|
|
ld8.fill r8=[r2],-16 // r2=&tf_r[FRAME_R6]
|
|
;;
|
|
ld8.fill r7=[r1],-16 // r1=&tf_r[FRAME_R5]
|
|
ld8.fill r6=[r2],-16 // r2=&tf_r[FRAME_R4]
|
|
;;
|
|
ld8.fill r5=[r1],-16 // r1=&tf_r[FRAME_R3]
|
|
ld8.fill r4=[r2],-16 // r2=&tf_r[FRAME_R2]
|
|
;;
|
|
ld8.fill r3=[r1],-16 // r1=&tf_r[FRAME_R1]
|
|
ld8.fill rR2=[r2],-16 // r2=&tf_b[7]
|
|
;;
|
|
ld8.fill rR1=[r1],-16 // r1=&tf_b[6]
|
|
ld8 r16=[r2],-16 // r2=&tf_b[5]
|
|
;;
|
|
mov b7=r16
|
|
ld8 r18=[r1],-16 // r1=&tf_b[4]
|
|
ld8 r19=[r2],-16 // r2=&tf_b[3]
|
|
;;
|
|
mov b6=r18
|
|
mov b5=r19
|
|
ld8 r16=[r1],-16 // r1=&tf_b[2]
|
|
ld8 r17=[r2],-16 // r2=&tf_b[1]
|
|
;;
|
|
mov b4=r16
|
|
mov b3=r17
|
|
ld8 r18=[r1],-16 // r1=&tf_b[0]
|
|
ld8 r19=[r2],-16 // r2=&tf_ar_fpsr
|
|
;;
|
|
mov b2=r18
|
|
mov b1=r19
|
|
ld8 r16=[r1],-16 // r1=&tf_ar_ccv
|
|
ld8 r17=[r2],-16 // r2=&tf_ar_unat
|
|
;;
|
|
mov b0=r16
|
|
mov ar.fpsr=r17
|
|
ld8 r18=[r1],-16 // r1=&tf_ndirty
|
|
ld8 r19=[r2],-16 // r2=&tf_ar_rnat
|
|
;;
|
|
mov ar.ccv=r18
|
|
mov ar.unat=r19
|
|
ld8 rNDIRTY=[r1],-16 // r1=&tf_ar_bspstore
|
|
ld8 rRNAT=[r2],-16 // r2=&tf_cr_ifs
|
|
;;
|
|
ld8 rBSPSTORE=[r1],-16 // r1=&tf_cr_pfs
|
|
ld8 rIFS=[r2],-16 // r2=&tf_ar_rsc
|
|
;;
|
|
(p1) br.cond.dpnt.few 1f // don't switch bs if kernel
|
|
;;
|
|
alloc r16=ar.pfs,0,0,0,0 // discard current frame
|
|
;;
|
|
shl r16=rNDIRTY,16 // value for ar.rsc
|
|
;;
|
|
mov ar.rsc=r16 // setup for loadrs
|
|
;;
|
|
loadrs // load user regs from kernel bs
|
|
;;
|
|
mov ar.bspstore=rBSPSTORE
|
|
;;
|
|
mov ar.rnat=rRNAT
|
|
;;
|
|
1: ld8 rPFS=[r1],-16 // r1=&tf_pr
|
|
ld8 rRSC=[r2],-16 // r2=&tf_cr_ifa
|
|
;;
|
|
ld8 rPR=[r1],-16 // r1=&tf_cr_isr
|
|
ld8 rIFA=[r2],-16 // r2=&tf_cr_ipsr
|
|
;;
|
|
ld8 rISR=[r1],-16 // r1=&tf_cr_iip
|
|
ld8 rIPSR=[r2]
|
|
;;
|
|
ld8 rIIP=[r1]
|
|
;;
|
|
mov r1=rR1
|
|
mov r2=rR2
|
|
mov ar.pfs=rPFS
|
|
mov cr.ifs=rIFS
|
|
mov ar.rsc=rRSC
|
|
mov pr=rPR,0x1ffff
|
|
mov cr.ifa=rIFA
|
|
mov cr.iip=rIIP
|
|
mov cr.ipsr=rIPSR
|
|
;;
|
|
rfi
|
|
|
|
END(exception_restore)
|
|
|
|
|
|
/*
|
|
* exception_save: save interrupted state
|
|
*
|
|
* Arguments:
|
|
* b0 return address
|
|
* r16 saved b0
|
|
*
|
|
* Return:
|
|
* r14 cr.iim value for break traps
|
|
* sp kernel stack pointer
|
|
* p1 true if user mode
|
|
* p2 true if kernel mode
|
|
* p3 true if interrupts were enabled
|
|
*/
|
|
ENTRY(exception_save, 0)
|
|
rsm psr.dt // turn off data translations
|
|
;;
|
|
srlz.d // serialize
|
|
;;
|
|
mov rIIP=cr.iip
|
|
mov rIPSR=cr.ipsr
|
|
mov rISR=cr.isr
|
|
mov rIFA=cr.ifa
|
|
mov rPR=pr
|
|
;;
|
|
tbit.nz p3,p0=rIPSR,14 // check for interrupt enable state
|
|
extr.u r17=rIPSR,32,2 // extract ipsr.cpl
|
|
;;
|
|
cmp.eq p1,p2=r0,r17 // test for kernel mode
|
|
;;
|
|
mov rSP=sp // save sp
|
|
;;
|
|
(p2) mov sp=ar.k6 // and switch to kernel stack
|
|
;;
|
|
add sp=-SIZEOF_TRAPFRAME,sp // reserve trapframe
|
|
mov rR1=r1
|
|
mov rR2=r2
|
|
;;
|
|
dep r1=0,sp,61,3 // r1=&tf_flags
|
|
;;
|
|
add r2=16,r1 // r2=&tf_cr_ipsr
|
|
st8 [r1]=r0,8 // zero flags, r1=&tf_cr_iip
|
|
;;
|
|
st8 [r1]=rIIP,16 // r1=&tf_cr_isr
|
|
st8 [r2]=rIPSR,16 // r2=&tf_cr_ifa
|
|
;;
|
|
st8 [r1]=rISR,16 // r1=&tf_pr
|
|
st8 [r2]=rIFA,16 // r2=&tf_ar_rsc
|
|
;;
|
|
st8 [r1]=rPR,16 // r1=&tf_cr_pfs
|
|
|
|
mov rB0=r16
|
|
mov rRSC=ar.rsc
|
|
mov rPFS=ar.pfs
|
|
cover
|
|
mov rIFS=cr.ifs
|
|
;;
|
|
mov ar.rsc=0
|
|
;;
|
|
mov rBSPSTORE=ar.bspstore
|
|
;;
|
|
(p2) mov r16=ar.k5 // kernel backing store
|
|
mov rRNAT=ar.rnat
|
|
;;
|
|
(p1) mov r16=rBSPSTORE // so we can figure out ndirty
|
|
(p2) mov ar.bspstore=r16 // switch bspstore
|
|
st8 [r2]=rRSC,16 // r2=&tf_cr_ifs
|
|
;;
|
|
st8 [r1]=rPFS,16 // r1=&tf_ar_bspstore
|
|
st8 [r2]=rIFS,16 // r2=&tf_ar_rnat
|
|
mov r17=ar.bsp
|
|
;;
|
|
sub r17=r17,r16 // ndirty (in bytes)
|
|
;;
|
|
st8 [r1]=rBSPSTORE,16 // r1=&tf_ndirty
|
|
st8 [r2]=rRNAT,16 // r2=&tf_ar_unat
|
|
;;
|
|
st8 [r1]=r17,16 // r1=&tf_ar_ccv
|
|
mov ar.rsc=3 // switch RSE back on
|
|
mov r16=ar.unat
|
|
;;
|
|
mov r17=ar.ccv
|
|
st8 [r2]=r16,16 // r2=&tf_ar_fpsr
|
|
mov r18=ar.fpsr
|
|
;;
|
|
st8 [r1]=r17,16 // r1=&tf_b[0]
|
|
st8 [r2]=r18,16 // r2=&tf_b[1]
|
|
mov r17=b1
|
|
;;
|
|
st8 [r1]=rB0,16 // r1=&tf_b[2]
|
|
mov r18=b2
|
|
st8 [r2]=r17,16 // r2=&tf_b[3]
|
|
;;
|
|
mov r17=b3
|
|
st8 [r1]=r18,16 // r1=&tf_b[4]
|
|
;;
|
|
mov r18=b4
|
|
st8 [r2]=r17,16 // r2=&tf_b[5]
|
|
;;
|
|
mov r17=b5
|
|
st8 [r1]=r18,16 // r1=&tf_b[6]
|
|
;;
|
|
mov r18=b6
|
|
st8 [r2]=r17,16 // r2=&tf_b[7]
|
|
;;
|
|
mov r17=b7
|
|
st8 [r1]=r18,16 // r1=&tf_r[FRAME_R1]
|
|
;;
|
|
st8 [r2]=r17,16 // r2=&tf_r[FRAME_R2]
|
|
;;
|
|
.mem.offset 0,0
|
|
st8.spill [r1]=rR1,16 // r1=&tf_r[FRAME_R3]
|
|
.mem.offset 8,0
|
|
st8.spill [r2]=rR2,16 // r2=&tf_r[FRAME_R4]
|
|
;;
|
|
.mem.offset 0,0
|
|
st8.spill [r1]=r3,16 // r1=&tf_r[FRAME_R5]
|
|
.mem.offset 8,0
|
|
st8.spill [r2]=r4,16 // r2=&tf_r[FRAME_R6]
|
|
;;
|
|
.mem.offset 0,0
|
|
st8.spill [r1]=r5,16 // r1=&tf_r[FRAME_R7]
|
|
.mem.offset 8,0
|
|
st8.spill [r2]=r6,16 // r2=&tf_r[FRAME_R8]
|
|
;;
|
|
.mem.offset 0,0
|
|
st8.spill [r1]=r7,16 // r1=&tf_r[FRAME_R9]
|
|
.mem.offset 8,0
|
|
st8.spill [r2]=r8,16 // r2=&tf_r[FRAME_R10]
|
|
;;
|
|
.mem.offset 0,0
|
|
st8.spill [r1]=r9,16 // r1=&tf_r[FRAME_R11]
|
|
.mem.offset 8,0
|
|
st8.spill [r2]=r10,16 // r2=&tf_r[FRAME_SP]
|
|
;;
|
|
.mem.offset 0,0
|
|
st8.spill [r1]=r11,16 // r1=&tf_r[FRAME_R13]
|
|
.mem.offset 8,0
|
|
st8.spill [r2]=rSP,16 // r2=&tf_r[FRAME_R14]
|
|
;;
|
|
.mem.offset 0,0
|
|
st8.spill [r1]=r13,16 // r1=&tf_r[FRAME_R15]
|
|
.mem.offset 8,0
|
|
st8.spill [r2]=r14,16 // r2=&tf_r[FRAME_R16]
|
|
;;
|
|
.mem.offset 0,0
|
|
st8.spill [r1]=r15,16 // r1=&tf_r[FRAME_R17]
|
|
;;
|
|
bsw.1 // switch to bank 1
|
|
;;
|
|
.mem.offset 8,0
|
|
st8.spill [r2]=r16,16 // r2=&tf_r[FRAME_R18]
|
|
.mem.offset 0,0
|
|
st8.spill [r1]=r17,16 // r1=&tf_r[FRAME_R19]
|
|
;;
|
|
.mem.offset 8,0
|
|
st8.spill [r2]=r18,16 // r2=&tf_r[FRAME_R20]
|
|
.mem.offset 0,0
|
|
st8.spill [r1]=r19,16 // r1=&tf_r[FRAME_R21]
|
|
;;
|
|
.mem.offset 8,0
|
|
st8.spill [r2]=r20,16 // r2=&tf_r[FRAME_R22]
|
|
.mem.offset 0,0
|
|
st8.spill [r1]=r21,16 // r1=&tf_r[FRAME_R23]
|
|
;;
|
|
.mem.offset 8,0
|
|
st8.spill [r2]=r22,16 // r2=&tf_r[FRAME_R24]
|
|
.mem.offset 0,0
|
|
st8.spill [r1]=r23,16 // r1=&tf_r[FRAME_R25]
|
|
;;
|
|
.mem.offset 8,0
|
|
st8.spill [r2]=r24,16 // r2=&tf_r[FRAME_R26]
|
|
.mem.offset 0,0
|
|
st8.spill [r1]=r25,16 // r1=&tf_r[FRAME_R27]
|
|
;;
|
|
.mem.offset 8,0
|
|
st8.spill [r2]=r26,16 // r2=&tf_r[FRAME_R28]
|
|
.mem.offset 0,0
|
|
st8.spill [r1]=r27,16 // r1=&tf_r[FRAME_R29]
|
|
;;
|
|
.mem.offset 8,0
|
|
st8.spill [r2]=r28,16 // r2=&tf_r[FRAME_R30]
|
|
.mem.offset 0,0
|
|
st8.spill [r1]=r29,16 // r1=&tf_r[FRAME_R31]
|
|
;;
|
|
.mem.offset 8,0
|
|
st8.spill [r2]=r30,16 // r2=&tf_f[FRAME_F6]
|
|
.mem.offset 0,0
|
|
st8.spill [r1]=r31,24 // r1=&tf_f[FRAME_F7]
|
|
;;
|
|
stf.spill [r2]=f6,32 // r2=&tf_f[FRAME_F8]
|
|
stf.spill [r1]=f7,32 // r1=&tf_f[FRAME_F9]
|
|
;;
|
|
stf.spill [r2]=f8,32 // r2=&tf_f[FRAME_F10]
|
|
stf.spill [r1]=f9,32 // r1=&tf_f[FRAME_F11]
|
|
;;
|
|
stf.spill [r2]=f10,32 // r2=&tf_f[FRAME_F12]
|
|
stf.spill [r1]=f11,32 // r1=&tf_f[FRAME_F13]
|
|
;;
|
|
stf.spill [r2]=f12,32 // r2=&tf_f[FRAME_F14]
|
|
stf.spill [r1]=f13,32 // r1=&tf_f[FRAME_F15]
|
|
;;
|
|
stf.spill [r2]=f14 //
|
|
stf.spill [r1]=f15 //
|
|
;;
|
|
movl r1=__gp // kernel globals
|
|
mov r13=ar.k4 // processor globals
|
|
mov r14=cr.iim // break immediate
|
|
ssm psr.ic|psr.dt // enable interrupts & translation
|
|
;;
|
|
srlz.i // serialize
|
|
;;
|
|
br.sptk.few b0 // not br.ret - we were not br.call'ed
|
|
|
|
END(exception_save)
|
|
|
|
/*
|
|
* System call entry point (via Break Instruction vector).
|
|
*
|
|
* Arguments:
|
|
* r15 System call number
|
|
* out0-out7 System call arguments
|
|
*/
|
|
ENTRY(do_syscall, 0)
|
|
.prologue
|
|
.save rp,r0
|
|
.body
|
|
// Save minimal state for syscall.
|
|
// We need to save enough state so that sendsig doesn't
|
|
// trash things if we take a signal during the system call.
|
|
// Essentially we need to save all the function-preserved
|
|
// state. Note that if we don't take a signal, we don't need
|
|
// to restore much of that state on the way out. Note also
|
|
// that when we save r4-r7 we spill their NaT bits into
|
|
// ar.unat. This register is preserved by the call to
|
|
// syscall() and if a full restore is needed,
|
|
// exception_restore will recover the NaT bits from ar.unat.
|
|
// The function-preserved state (including syscall number) is:
|
|
//
|
|
// r1,r4-r7,sp,r15
|
|
// f16-f31
|
|
// p1-p5,p16-p63
|
|
// b0-b5
|
|
// various ar's
|
|
//
|
|
{ .mmi // start reading high latency regs
|
|
mov r16=cr.ipsr // (13)
|
|
mov.m r17=ar.rsc // (13)
|
|
mov r18=sp // save user sp
|
|
;;
|
|
} { .mmi
|
|
mov sp=ar.k6 // (13) kernel sp
|
|
mov r19=cr.isr // (13)
|
|
nop.i 0
|
|
} { .mmi
|
|
mov.m ar.rsc=0
|
|
;;
|
|
mov.m r20=ar.bspstore // (13)
|
|
nop.i 0
|
|
} { .mmi
|
|
mov.m r21=ar.k5 // (13)
|
|
mov.m r22=ar.rnat // (6)
|
|
nop.i 0
|
|
} { .mmi
|
|
mov.m r23=ar.unat // (6)
|
|
rsm psr.dt // (5) physical addressing
|
|
} { .mii
|
|
mov r24=cr.iip // (2)
|
|
mov.i r25=ar.pfs // (2)
|
|
add sp=-SIZEOF_TRAPFRAME,sp // reserve trapframe
|
|
;;
|
|
} { .mii
|
|
addl r27=FRAME_SYSCALL,r0 // (1)
|
|
mov r26=pr // (2)
|
|
dep r30=0,sp,61,3 // physical address
|
|
} { .mmi
|
|
srlz.d // serialize psr.dt
|
|
;;
|
|
add r31=8,r30 // secondary pointer
|
|
;;
|
|
} { .mmi
|
|
st8 [r30]=r27,16 // tf_flags
|
|
st8 [r31]=r24,16 // save cr.iip
|
|
mov r28=b0
|
|
;;
|
|
} { .mmi
|
|
st8 [r30]=r16,24 // save cr.ipsr, skip to pr
|
|
st8 [r31]=r19,24 // save cr.isr, skip to ar.rsc
|
|
mov r24=b1
|
|
;;
|
|
} { .mmi
|
|
st8 [r30]=r26,16 // save pr, skip to ar.pfs
|
|
st8 [r31]=r17,24 // save ar.rsc, skip to ar.bspstore
|
|
mov r27=b2
|
|
;;
|
|
} { .mii
|
|
st8 [r30]=r25,24 // save ar.pfs, skip to ar.rnat
|
|
mov r16=b3
|
|
mov r17=b4
|
|
;;
|
|
} { .mmi
|
|
st8 [r31]=r20,24 // save ar.bspstore, skip to ar.unat
|
|
mov.m ar.bspstore=r21 // switch to kernel backing store
|
|
mov r29=b5
|
|
;;
|
|
} { .mmi
|
|
mov.m r20=ar.ccv
|
|
mov.m r21=ar.fpsr
|
|
nop.i 0
|
|
;;
|
|
} { .mmi
|
|
st8 [r30]=r22,24 // save ar.rnat, skip to ar.ccv
|
|
st8 [r31]=r23,16 // save ar.unat, skip to ar.fpsr
|
|
nop.i 0
|
|
;;
|
|
} { .mmi
|
|
st8 [r30]=r20,16 // save ar.ccv, skip to b0
|
|
st8 [r31]=r21,16 // save ar.fpsr, skip to b1
|
|
nop.i 0
|
|
;;
|
|
} { .mmi
|
|
st8 [r30]=r28,16 // save b0, skip to b2
|
|
st8 [r31]=r24,16 // save b1, skip to b3
|
|
nop.i 0
|
|
;;
|
|
} { .mmi
|
|
st8 [r30]=r27,16 // save b2, skip to b4
|
|
st8 [r31]=r16,16 // save b3, skip to b5
|
|
nop.i 0
|
|
;;
|
|
} { .mmi
|
|
st8 [r30]=r17,TF_R_R1-(TF_B+4*8) // save b4, skip to r1
|
|
st8 [r31]=r29,TF_R_R4-(TF_B+5*8) // save b5, skip to r4
|
|
nop.i 0
|
|
;;
|
|
} { .mmi
|
|
st8 [r30]=r1,TF_R_R5-TF_R_R1 // save r1, skip to r5
|
|
.mem.offset 8,0
|
|
st8.spill [r31]=r4,16 // save r4, skip to r6
|
|
nop.i 0
|
|
;;
|
|
} { .mmi
|
|
.mem.offset 0,0
|
|
st8.spill [r30]=r5,16 // save r5, skip to r7
|
|
.mem.offset 8,0
|
|
st8.spill [r31]=r6,TF_R_SP-TF_R_R6 // save r6, skip to sp
|
|
nop.i 0
|
|
;;
|
|
} { .mmi
|
|
.mem.offset 0,0
|
|
st8.spill [r30]=r7,TF_R_R15-TF_R_R7 // save r7, skip to r15
|
|
st8 [r31]=r18 // save sp
|
|
nop.i 0
|
|
;;
|
|
} { .mmb
|
|
st8 [r30]=r15 // save r15 (syscall number)
|
|
add sp=-(8*8),sp // reserve stack for arguments
|
|
br.call.sptk.few b0=Lsaveargs // dump args
|
|
} { .mmb
|
|
mov.m r13=ar.k4 // processor globals
|
|
nop.m 0
|
|
bsw.1 // switch back to bank 1
|
|
;;
|
|
} { .mmb
|
|
mov r16=sp // point at args
|
|
mov.m r17=ar.k5 // for calculating ndirty
|
|
cover // preserve user register frame
|
|
;;
|
|
} { .mmi
|
|
mov r18=cr.ifs // record user's CFM
|
|
mov.m r19=ar.bsp // ndirty = ar.bsp - kbsp
|
|
add sp=-16,sp // reserve scratch space
|
|
;;
|
|
} { .mmi
|
|
add r20=TF_CR_IFS+(8*8),r16 // point at cr.ifs
|
|
ssm psr.ic|psr.dt // reenable traps and translation
|
|
sub r19=r19,r17 // calculate ndirty
|
|
;;
|
|
} { .mmi
|
|
srlz.i // serialize psr.ic and psr.dt
|
|
;;
|
|
ssm psr.i // safe to take interrupts again
|
|
add r21=TF_NDIRTY+(8*8),r16 // point at ndirty
|
|
;;
|
|
} { .mmi
|
|
st8 [r20]=r18 // save cr.ifs
|
|
st8 [r21]=r19 // save ndirty
|
|
;;
|
|
} { .mmi
|
|
alloc r14=ar.pfs,0,1,3,0
|
|
srlz.d // serialize psr.i
|
|
add loc0=(8*8),r16 // remember where trapframe is
|
|
;;
|
|
} { .mlx
|
|
mov out0=r15 // syscall number (from user)
|
|
movl gp=__gp // kernel globals
|
|
} { .mmb
|
|
mov out1=r16 // arguments
|
|
add out2=(8*8),r16 // trapframe pointer
|
|
br.call.sptk.many rp=syscall // do the work
|
|
} { .mii
|
|
ld8 r14=[loc0] // check tf_flags
|
|
dep r15=0,loc0,61,3 // physical address of trapframe
|
|
;;
|
|
tbit.z p6,p0=r14,0 // check FRAME_SYSCALL bit
|
|
;;
|
|
} { .mib
|
|
(p6) add sp=-16,loc0 // do a full restore if clear
|
|
add r16=SIZEOF_TRAPFRAME,loc0 // new kernel sp
|
|
(p6) br.dpnt.many exception_restore
|
|
} { .mmi
|
|
rsm psr.dt|psr.ic|psr.i // get ready to restore
|
|
;;
|
|
srlz.i // serialise psr.dt and psr.ic
|
|
add r30=TF_R_R15,r15 // point at r15
|
|
;;
|
|
} { .mmi
|
|
alloc r14=ar.pfs,0,0,0,0 // discard register frame
|
|
mov ar.k6=r16 // restore kernel sp
|
|
add r31=TF_R_SP,r15 // point at sp
|
|
;;
|
|
} { .mmi
|
|
ld8 r15=[r30],TF_R_R10-TF_R_R15 // restore r15, skip to r10
|
|
ld8 sp=[r31],TF_R_R9-TF_R_SP // restore user sp, skip to r9
|
|
nop.i 0
|
|
;;
|
|
} { .mmi
|
|
ld8 r10=[r30],-16 // restore r10, skip to r8
|
|
ld8 r9=[r31],TF_R_R1-TF_R_R9 // restore r9, skip to r1
|
|
nop.i 0
|
|
;;
|
|
} { .mmi
|
|
ld8 r8=[r30],TF_B-TF_R_R8 // restore r8, skip to b0
|
|
ld8 r1=[r31],TF_AR_FPSR-TF_R_R1 // restore r1, skip to ar.fpsr
|
|
nop.i 0
|
|
;;
|
|
} { .mmi
|
|
ld8 r16=[r30],-16 // restore b0, skip to ar.ccv
|
|
ld8 r17=[r31],-16 // restore ar.fpsr, skip to ar.unat
|
|
nop.i 0
|
|
;;
|
|
} { .mmi
|
|
ld8 r18=[r30],-16 // restore ar.ccv, skip to ndirty
|
|
ld8 r19=[r31],-16 // restore ar.unat, skip to ar.rnat
|
|
mov b0=r16
|
|
;;
|
|
} { .mmi
|
|
ld8 r20=[r30],-16 // restore ndirty, skip to ar.bspstore
|
|
ld8 r21=[r31],-16 // restore ar.rnat, skip to cr.ifs
|
|
nop.i 0
|
|
;;
|
|
} { .mmi
|
|
ld8 r16=[r30],-16 // restore ar.bspstore, skip to ar.pfs
|
|
mov ar.fpsr=r17
|
|
shl r20=r20,16 // value for ar.rsc
|
|
;;
|
|
} { .mmi
|
|
ld8 r22=[r31],-16 // restore cr.ifs, skip to ar.rsc
|
|
mov.m ar.ccv=r18
|
|
nop.i 0
|
|
;;
|
|
} { .mmi
|
|
ld8 r17=[r30],-16 // restore ar.pfs, skip to pr
|
|
mov.m ar.unat=r19
|
|
nop.i 0
|
|
;;
|
|
} { .mmi
|
|
ld8 r18=[r31],-32 // restore ar.rsc, skip to cr.ipsr
|
|
mov.m ar.rsc=r20 // setup for loadrs
|
|
nop.i 0
|
|
;;
|
|
} { .mmi
|
|
loadrs // restore user stacked registers
|
|
;;
|
|
mov.m ar.bspstore=r16 // back to user backing store
|
|
mov.i ar.pfs=r17
|
|
;;
|
|
} { .mmi
|
|
mov.m ar.rnat=r21
|
|
mov.m ar.rsc=r18
|
|
nop.i 0
|
|
;;
|
|
} { .mmi
|
|
ld8 r16=[r30],-32 // restore pr, skip to cr.iip
|
|
ld8 r17=[r31] // restore cr.ipsr
|
|
nop.i 0
|
|
;;
|
|
} { .mmi
|
|
ld8 r18=[r30] // restore cr.iip
|
|
mov cr.ifs=r22
|
|
nop.i 0
|
|
;;
|
|
} { .mmi
|
|
mov cr.iip=r18
|
|
mov cr.ipsr=r17
|
|
mov pr=r16,0x1ffff
|
|
;;
|
|
} { .bbb
|
|
rfi
|
|
}
|
|
|
|
// This is done as a function call to make sure that we only
|
|
// have output registers in the register frame. It also gives
|
|
// us a chance to use alloc to round up to 8 arguments for
|
|
// simplicity.
|
|
//
|
|
// We are still running in physical mode with psr.ic==0 because
|
|
// we haven't yet covered the user's register frame to get a
|
|
// value for cr.ifs
|
|
Lsaveargs:
|
|
{ .mii
|
|
alloc r14=ar.pfs,0,0,8,0 // round up to 8 outputs
|
|
extr.u r31=sp,0,61 // physical address
|
|
;;
|
|
add r30=8,r31
|
|
;;
|
|
} { .mmi
|
|
st8 [r31]=r32,16
|
|
st8 [r30]=r33,16
|
|
;;
|
|
} { .mmi
|
|
st8 [r31]=r34,16
|
|
st8 [r30]=r35,16
|
|
;;
|
|
} { .mmi
|
|
st8 [r31]=r36,16
|
|
st8 [r30]=r37,16
|
|
;;
|
|
} { .mmb
|
|
st8 [r31]=r38
|
|
st8 [r30]=r39
|
|
br.ret.sptk.many b0
|
|
}
|
|
.global do_syscall_end
|
|
do_syscall_end:
|
|
|
|
END(do_syscall)
|