version 1.3, 2004/06/28 09:13:11 |
version 1.3.12.8, 2008/02/27 08:36:18 |
|
|
*/ |
*/ |
|
|
/* |
/* |
* Copyright (c) 1998 The NetBSD Foundation, Inc. |
* Copyright (c) 1998, 2007 The NetBSD Foundation, Inc. |
* All rights reserved. |
* All rights reserved. |
* |
* |
* This code is derived from software contributed to The NetBSD Foundation |
* This code is derived from software contributed to The NetBSD Foundation |
* by Charles M. Hannum. |
* by Charles M. Hannum and Andrew Doran. |
* |
* |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* modification, are permitted provided that the following conditions |
|
|
#define ALIGN_TEXT .align 16,0x90 |
#define ALIGN_TEXT .align 16,0x90 |
|
|
#include <machine/asm.h> |
#include <machine/asm.h> |
#include <machine/psl.h> |
|
#include <machine/trap.h> |
#include <machine/trap.h> |
#include <machine/segments.h> |
#include <machine/segments.h> |
#include <machine/frameasm.h> |
#include <machine/frameasm.h> |
|
|
#include "assym.h" |
#include "assym.h" |
|
|
.data |
|
.globl _C_LABEL(netisr) |
|
.text |
.text |
|
|
#if 0 |
#ifndef XEN |
#if defined(PROF) || defined(GPROF) |
|
/* |
/* |
* XXXX TODO |
* softintr() |
|
* |
|
* Switch to the LWP assigned to handle interrupts from the given |
|
* source. We borrow the VM context from the interrupted LWP. |
|
* |
|
* On entry: |
|
* |
|
* %rax intrsource |
|
* %r13 address to return to |
*/ |
*/ |
.globl _C_LABEL(splhigh), _C_LABEL(splx) |
IDTVEC(softintr) |
|
pushq $_C_LABEL(softintr_ret) /* set up struct switchframe */ |
|
pushq %rbx |
|
pushq %r12 |
|
pushq %r13 |
|
pushq %r14 |
|
pushq %r15 |
|
movl $IPL_HIGH,CPUVAR(ILEVEL) |
|
movq CPUVAR(CURLWP),%r15 |
|
movq IS_LWP(%rax),%rdi /* switch to handler LWP */ |
|
movq L_ADDR(%rdi),%rdx |
|
movq L_ADDR(%r15),%rcx |
|
movq %rdi,CPUVAR(CURLWP) |
|
movq %rsp,PCB_RSP(%rcx) |
|
movq %rbp,PCB_RBP(%rcx) |
|
movq PCB_RSP0(%rdx),%rsp /* onto new stack */ |
|
sti |
|
movq %r15,%rdi /* interrupted LWP */ |
|
movl IS_MAXLEVEL(%rax),%esi /* ipl to run at */ |
|
call _C_LABEL(softint_dispatch)/* run handlers */ |
|
movq L_ADDR(%r15),%rcx |
|
movq PCB_RSP(%rcx),%rsp |
|
xchgq %r15,CPUVAR(CURLWP) /* must be globally visible */ |
|
popq %r15 /* unwind switchframe */ |
|
addq $(5 * 8),%rsp |
|
cli |
|
jmp *%r13 /* back to splx/doreti */ |
|
|
ALIGN_TEXT |
/* |
_C_LABEL(splhigh): |
* softintr_ret() |
movl $IPL_HIGH,%eax |
* |
xchgl %eax,CPUVAR(ILEVEL) |
* Trampoline function that gets returned to by cpu_switchto() when |
|
* an interrupt handler blocks. On entry: |
|
* |
|
* %rax prevlwp from cpu_switchto() |
|
*/ |
|
NENTRY(softintr_ret) |
|
incl CPUVAR(MTX_COUNT) /* re-adjust after mi_switch */ |
|
movl $0, L_CTXSWTCH(%rax) /* %rax from cpu_switchto */ |
|
cli |
|
jmp *%r13 /* back to splx/doreti */ |
|
|
|
/* |
|
* void softint_trigger(uintptr_t machdep); |
|
* |
|
* Software interrupt registration. |
|
*/ |
|
NENTRY(softint_trigger) |
|
orl %edi,CPUVAR(IPENDING) /* atomic on local cpu */ |
ret |
ret |
|
|
ALIGN_TEXT |
/* |
_C_LABEL(splx): |
* int splraise(int s); |
movl 4(%esp),%eax |
*/ |
movl %eax,CPUVAR(ILEVEL) |
ENTRY(splraise) |
testl %eax,%eax |
movl CPUVAR(ILEVEL),%eax |
jnz _C_LABEL(Xspllower) |
cmpl %edi,%eax |
|
cmoval %eax,%edi |
|
movl %edi,CPUVAR(ILEVEL) |
ret |
ret |
#endif /* PROF || GPROF */ |
|
#endif |
/* |
|
* void spllower(int s); |
|
* |
|
* Must be the same size as i686_spllower(). This must use |
|
* pushf/cli/popf as it is used early in boot where interrupts |
|
* are disabled via eflags/IE. |
|
*/ |
|
ENTRY(spllower) |
|
cmpl CPUVAR(ILEVEL), %edi |
|
jae 1f |
|
movl CPUVAR(IUNMASK)(,%rdi,4), %edx |
|
pushf |
|
cli |
|
testl CPUVAR(IPENDING), %edx |
|
jnz 2f |
|
movl %edi, CPUVAR(ILEVEL) |
|
popf |
|
1: |
|
ret |
|
ret |
|
2: |
|
popf |
|
jmp _C_LABEL(Xspllower) |
|
nop |
|
nop |
|
.align 16 |
|
LABEL(spllower_end) |
|
|
|
#endif /* !XEN */ |
|
|
|
/* |
|
* void cx8_spllower(int s); |
|
* |
|
* For cmpxchg8b, edx/ecx are the high words and eax/ebx the low. |
|
* |
|
* edx : eax = old level / old ipending |
|
* ecx : ebx = new level / old ipending |
|
*/ |
|
ENTRY(cx8_spllower) |
|
movl CPUVAR(ILEVEL),%edx |
|
movq %rbx,%r8 |
|
cmpl %edx,%edi /* new level is lower? */ |
|
jae,pn 1f |
|
0: |
|
movl CPUVAR(IPENDING),%eax |
|
movl %edi,%ecx |
|
testl %eax,CPUVAR(IUNMASK)(,%rcx,4)/* deferred interrupts? */ |
|
movl %eax,%ebx |
|
/* |
|
* On the P4 this jump is cheaper than patching in junk |
|
* using cmov. Is cmpxchg expensive if it fails? |
|
*/ |
|
jnz,pn 2f |
|
cmpxchg8b CPUVAR(ISTATE) /* swap in new ilevel */ |
|
jnz,pn 0b |
|
1: |
|
movq %r8,%rbx |
|
ret |
|
2: |
|
movq %r8,%rbx |
|
LABEL(cx8_spllower_patch) |
|
jmp _C_LABEL(Xspllower) |
|
|
|
.align 16 |
|
LABEL(cx8_spllower_end) |
|
|
/* |
/* |
|
* void Xspllower(int s); |
|
* |
* Process pending interrupts. |
* Process pending interrupts. |
* |
* |
* Important registers: |
* Important registers: |
|
|
* the sending CPU will never see the that CPU accept the IPI |
* the sending CPU will never see the that CPU accept the IPI |
* (see pmap_tlb_shootnow). |
* (see pmap_tlb_shootnow). |
*/ |
*/ |
|
nop |
|
.align 4 /* Avoid confusion with cx8_spllower_end */ |
|
|
IDTVEC(spllower) |
IDTVEC(spllower) |
pushq %rbx |
pushq %rbx |
pushq %r13 |
pushq %r13 |
Line 133 IDTVEC(spllower) |
|
Line 251 IDTVEC(spllower) |
|
leaq 1f(%rip),%r13 # address to resume loop at |
leaq 1f(%rip),%r13 # address to resume loop at |
1: movl %ebx,%eax # get cpl |
1: movl %ebx,%eax # get cpl |
movl CPUVAR(IUNMASK)(,%rax,4),%eax |
movl CPUVAR(IUNMASK)(,%rax,4),%eax |
cli |
CLI(si) |
andl CPUVAR(IPENDING),%eax # any non-masked bits left? |
andl CPUVAR(IPENDING),%eax # any non-masked bits left? |
jz 2f |
jz 2f |
bsrl %eax,%eax |
bsrl %eax,%eax |
Line 142 IDTVEC(spllower) |
|
Line 260 IDTVEC(spllower) |
|
jmp *IS_RECURSE(%rax) |
jmp *IS_RECURSE(%rax) |
2: |
2: |
movl %ebx,CPUVAR(ILEVEL) |
movl %ebx,CPUVAR(ILEVEL) |
sti |
STI(si) |
popq %r12 |
popq %r12 |
popq %r13 |
popq %r13 |
popq %rbx |
popq %rbx |
|
|
leaq 1f(%rip),%r13 |
leaq 1f(%rip),%r13 |
1: movl %ebx,%eax |
1: movl %ebx,%eax |
movl CPUVAR(IUNMASK)(,%rax,4),%eax |
movl CPUVAR(IUNMASK)(,%rax,4),%eax |
cli |
CLI(si) |
andl CPUVAR(IPENDING),%eax |
andl CPUVAR(IPENDING),%eax |
jz 2f |
jz 2f |
bsrl %eax,%eax # slow, but not worth optimizing |
bsrl %eax,%eax # slow, but not worth optimizing |
|
|
jmp *IS_RESUME(%rax) |
jmp *IS_RESUME(%rax) |
2: /* Check for ASTs on exit to user mode. */ |
2: /* Check for ASTs on exit to user mode. */ |
movl %ebx,CPUVAR(ILEVEL) |
movl %ebx,CPUVAR(ILEVEL) |
5: CHECK_ASTPENDING(%r11) |
5: |
je 3f |
|
testb $SEL_RPL,TF_CS(%rsp) |
testb $SEL_RPL,TF_CS(%rsp) |
jz 3f |
jz 6f |
4: CLEAR_ASTPENDING(%r11) |
.globl doreti_checkast |
sti |
doreti_checkast: |
|
movq CPUVAR(CURLWP),%r14 |
|
CHECK_ASTPENDING(%r14) |
|
je 3f |
|
CLEAR_ASTPENDING(%r14) |
|
STI(si) |
movl $T_ASTFLT,TF_TRAPNO(%rsp) /* XXX undo later.. */ |
movl $T_ASTFLT,TF_TRAPNO(%rsp) /* XXX undo later.. */ |
/* Pushed T_ASTFLT into tf_trapno on entry. */ |
/* Pushed T_ASTFLT into tf_trapno on entry. */ |
movq %rsp,%rdi |
movq %rsp,%rdi |
call _C_LABEL(trap) |
call _C_LABEL(trap) |
cli |
CLI(si) |
jmp 5b |
jmp doreti_checkast |
3: INTRFASTEXIT |
3: |
|
CHECK_DEFERRED_SWITCH |
|
jnz 9f |
|
6: |
|
INTRFASTEXIT |
|
9: |
|
STI(si) |
|
call _C_LABEL(do_pmap_load) |
|
CLI(si) |
|
jmp doreti_checkast /* recheck ASTs */ |
|
|
|
#ifdef XEN |
|
NENTRY(call_evtchn_do_event) |
|
incl CPUVAR(IDEPTH) |
|
call _C_LABEL(evtchn_do_event) |
|
decl CPUVAR(IDEPTH) |
|
ret |
|
#endif |