📄 vectors.s
字号:
pusha # save registers
hal_fpu_push_int # save FPU state
#if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT) || \
defined(CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT) || \
defined(CYGPKG_PROFILE_GPROF)
# Save the context just to be able to set a breakpoint
# when we have a CTRL-C
.extern hal_saved_interrupt_state
movl %esp,hal_saved_interrupt_state
#endif
#if defined(CYGFUN_HAL_COMMON_KERNEL_SUPPORT) && \
!defined(CYGPKG_HAL_SMP_SUPPORT)
# Increment scheduler lock
.extern cyg_scheduler_sched_lock
incl cyg_scheduler_sched_lock
#endif
movl %esp,%ebp # EBP = copy of ESP
# adjust ESP by 16 for the state stored before the pusha
add $16,i386reg_esp(%esp)
hal_to_intstack
hal_fpu_push_int_annex # save extra FPU state
#ifdef CYGSEM_HAL_COMMON_INTERRUPTS_ALLOW_NESTING
# If we are allowing nested interrupts, restore the flags pushed
# by the hardware when this interrupt was taken.
movl i386reg_eflags(%ebp), %eax
btrl $8,%eax # Clear TF bit
pushl %eax
popfl
#endif
#if defined(CYGPKG_KERNEL_INSTRUMENT) && defined(CYGDBG_KERNEL_INSTRUMENT_INTR)
# Call cyg_instrument to record that this interrupt is being raised.
movl i386reg_vector(%ebp), %ecx # vector number from saved state
movl %ecx,%edi # EDI = copy of vector
subl $0x20,%edi # EDI = interrupt table offset
pushl %edi # arg3 = interrupt number
pushl %ecx # arg2 = vector number
pushl $0x0301 # arg1 = type = INTR.RAISE
call cyg_instrument # call instrument function
add $12,%esp # skip arguments
#endif
# Call hal_interrupt_handlers[vector](vector, cyg_hal_interrupt_data[vector])
movl i386reg_vector(%ebp), %ecx # vector number from saved state
movl %ecx,%edi # EDI = copy of vector
subl $0x20,%edi # EDI = interrupt table offset
movl $hal_interrupt_handlers, %ebx
movl (%ebx, %edi, 4), %edx # EDX = interrupt routine
movl $hal_interrupt_data, %ebx
movl (%ebx, %edi, 4), %eax # EAX = interrupt data
pushl %eax # arg2 = data
pushl %ecx # arg1 = vector
call *%edx # EAX = return value, needed for interrupt_end()
addl $8,%esp # pop args
# At this point:
# EAX = ISR return code (returned by call)
# EDI = ISR table offset (saved across call)
# EBP = State pointer (saved across call)
hal_fpu_pop_int_annex # Pop any saved interrupt state
# If we are returning from the last nested interrupt, move back
# to the thread stack. interrupt_end() must be called on the
# thread stack since it potentially causes a context switch.
hal_from_intstack
#ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT
# Call interrupt_end(r, cyg_hal_interrupt_objects[vector], regs)
# - r is the return value from the ISR
# - regs points to saved CPU context
movl $hal_interrupt_objects, %ebx
movl (%ebx, %edi, 4), %edx # EDX = interrupt object ptr
pushl %ebp # arg3 = ptr to saved registers
pushl %edx # arg2 = object
pushl %eax # arg1 = ISR return code
call interrupt_end # Call it
addl $12, %esp # pop args
#endif
# Now pull saved state from stack and return to
# what thread was originally doing.
hal_fpu_pop_int # restore FPU state
popa # restore all our registers.
addl $4, %esp # skip the vector number.
iret # and return to the thread.
#==============================================================================
## Execute pending DSRs on the interrupt stack with interrupts enabled.
## Note: this can only be called from code running on a thread stack so we
## can always just jump to the interrupt stack without looking.
#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
.extern cyg_interrupt_call_pending_DSRs
.global hal_interrupt_stack_call_pending_DSRs
hal_interrupt_stack_call_pending_DSRs:
pushl %ebp # save EBP
pushfl # save flags
movl %esp,%ebp # EBP = saved SP
hal_load_istack %edx # load new SP into EDX
movl %edx,%esp # move it to ESP
sti # Enable interrupts
# Call back to kernel to run DSRs
call cyg_interrupt_call_pending_DSRs
# On return EBP will still contain the old ESP since
# it is a callee saved register.
movl %ebp,%esp # restore saved SP
# Now merge the original IF bit into the current
# EFLAGS.
popl %eax # EAX = saved flags
pushfl # 0(%esp) = current flags
btrl $9,0(%esp) # clear IF bit in current flags
andl $0x00000200,%eax # isolate saved IF bit
orl %eax,0(%esp) # OR it in to the saved flags
popfl # restore flags
popl %ebp # restore EBP
ret # and return
#endif
#==============================================================================
# FPU lazy state switch VSR
# This is invoked via hardware exception 7 (FPU unavailable) as a result of
# setting the TS bit in CR0 whenever we context switch. If we discover here
# that a different context from the current owner of the FPU has attempted
# a floating point operation, we save the old context and load the new before
# allowing it to proceed.
#ifdef CYGHWR_HAL_I386_FPU_SWITCH_LAZY
#ifndef CYGPKG_HAL_SMP_CPU_MAX
#define CYGPKG_HAL_SMP_CPU_MAX 1
#endif
.data
.global cyg_hal_fpustate_owner
cyg_hal_fpustate_owner:
.rept CYGPKG_HAL_SMP_CPU_MAX
.long 0 # pointer to FPU owning context
.endr
.global cyg_hal_fpustate_current
cyg_hal_fpustate_current:
.rept CYGPKG_HAL_SMP_CPU_MAX
.long 0 # pointer to current threads FPU context
.endr
.text
__fpu_switch_vsr:
## We enter here with the CPU state still in the registers and:
## 0(%esp) vector number pushed by trampoline
## 4(%esp) PC pushed by hardware
## 8(%esp) CS pushed by hardware
## 12(%esp) EFLAGS pushed by hardware
clts # clear CR0:TS bit
pusha # save all regs
hal_smp_cpu %ecx # ECX = CPU id
movl $cyg_hal_fpustate_owner,%eax # EAX = FPU context owner table
leal 0(%eax,%ecx,4),%esi # ESI = address of owner pointer
movl $cyg_hal_fpustate_current,%ebx # EBX = current threads context table
leal 0(%ebx,%ecx,4),%edi # EDI = address of context pointer
movl 0(%esi),%eax # EAX = Current FPU context owner
movl 0(%edi),%ebx # EBX = Current threads FPU context
cmpl %ebx,%eax # current == owner ?
je 9f # yes, nothing else to do
cmpl $0,%eax # is FPU even in use?
je 1f # if not, skip save
fnsave i386reg_fpucontext_state(%eax) # save FPU state
#ifdef CYGHWR_HAL_I386_PENTIUM_SSE
# Save SIMD state.
# FIXME. This is awfully inefficient. Need to use FXSAVE to
# save FPU and SIMD at same time. FXSAVE requires a 16 byte
# alignment and does not have an implicit finit as does FSAVE.
stmxcsr i386reg_simd_mxcsr(%eax)
movups %xmm0,i386reg_simd_xmm0(%eax)
movups %xmm1,i386reg_simd_xmm1(%eax)
movups %xmm2,i386reg_simd_xmm2(%eax)
movups %xmm3,i386reg_simd_xmm3(%eax)
movups %xmm4,i386reg_simd_xmm4(%eax)
movups %xmm5,i386reg_simd_xmm5(%eax)
movups %xmm6,i386reg_simd_xmm6(%eax)
movups %xmm7,i386reg_simd_xmm7(%eax)
#endif
movl $1,i386reg_fpucontext_valid(%eax) # mark valid
1:
movl %ebx,0(%esi) # Set new owner
btl $0,i386reg_fpucontext_valid(%ebx) # Valid state?
jc 2f # If yes, go to restore it
finit # Otherwise init FPU
#ifdef CYGHWR_HAL_I386_PENTIUM_SSE
# FIXME. Anything needed here?
#endif
jmp 9f # skip restore
2:
frstor i386reg_fpucontext_state(%ebx) # restore FPU state
#ifdef CYGHWR_HAL_I386_PENTIUM_SSE
# Restore SIMD state.
# FIXME. This is awfully inefficient. Need to use FXRSTOR to
# restore FPU and SIMD at same time. FXRSTOR requires a 16 byte
# alignment.
movups i386reg_simd_xmm0(%ebx),%xmm0
movups i386reg_simd_xmm1(%ebx),%xmm1
movups i386reg_simd_xmm2(%ebx),%xmm2
movups i386reg_simd_xmm3(%ebx),%xmm3
movups i386reg_simd_xmm4(%ebx),%xmm4
movups i386reg_simd_xmm5(%ebx),%xmm5
movups i386reg_simd_xmm6(%ebx),%xmm6
movups i386reg_simd_xmm7(%ebx),%xmm7
ldmxcsr i386reg_simd_mxcsr(%ebx)
#endif
9:
popa # restore all our registers.
addl $4, %esp # skip the vector number.
iret # and return to the thread.
#endif
#if 0
#==============================================================================
# Assembler swap routines
# x = CPU_swap_u16(x)
.align 4
.global CPU_swap_u16
CPU_swap_u16:
xorl %eax, %eax
movb 4(%esp), %ah
movb 5(%esp), %al
ret
# x = CPU_swap_u32(x)
.align 4
.global CPU_swap_u32
CPU_swap_u32:
xorl %eax, %eax
movb 4(%esp), %ah
movb 5(%esp), %al
sall $16, %eax
movb 6(%esp), %ah
movb 7(%esp), %al
ret
#endif
#==============================================================================
# Exception trampolines
# IDT exception gates point to short code sequences that push the vector
# number on to the stack and then indirect via the VSR table to a handler.
#
# Just for yuks we keep a count of the number of times each
# vector is called.
.bss
.globl hal_vsr_stats
hal_vsr_stats:
.rept 64 // Default VSR table is 64 entries long
.long 0
.endr
# When an exception which supplies an error code is generated,
# we move the code here.
hal_trap_error_code:
.long 0
.text
# macro to create exception handler (no error code)
.macro hal_pc_exception_noerr idx
hal_pc_exception_\idx:
movl $0,hal_trap_error_code
pushl $\idx
incl (hal_vsr_stats+\idx*4)
jmp *(hal_vsr_table+\idx*4)
.endm
# macro to create exception handler (with error code)
.macro hal_pc_exception_err idx
hal_pc_exception_\idx:
popl hal_trap_error_code
pushl $\idx
incl (hal_vsr_stats+\idx*4)
jmp *(hal_vsr_table+\idx*4)
.endm
# Now generate all the default exception VSR trampolines.
hal_pc_exception_noerr 0
hal_pc_exception_noerr 1
hal_pc_exception_noerr 2
hal_pc_exception_noerr 3
hal_pc_exception_noerr 4
hal_pc_exception_noerr 5
hal_pc_exception_noerr 6
hal_pc_exception_noerr 7
hal_pc_exception_err 8
hal_pc_exception_noerr 9
hal_pc_exception_err 10
hal_pc_exception_err 11
hal_pc_exception_err 12
hal_pc_exception_err 13
hal_pc_exception_err 14
hal_pc_exception_noerr 15
hal_pc_exception_noerr 16
hal_pc_exception_err 17
hal_pc_exception_noerr 18
hal_pc_exception_noerr 19
hal_pc_exception_noerr 20
hal_pc_exception_noerr 21
hal_pc_exception_noerr 22
hal_pc_exception_noerr 23
hal_pc_exception_noerr 24
hal_pc_exception_noerr 25
hal_pc_exception_noerr 26
hal_pc_exception_noerr 27
hal_pc_exception_noerr 28
hal_pc_exception_noerr 29
hal_pc_exception_noerr 30
hal_pc_exception_noerr 31
#==============================================================================
# IRQ handler trampolines
# macro to create exception handler (no error code)
.macro hal_pc_irq_handler idx
hal_pc_irq_\idx:
pushl $\idx
incl (hal_vsr_stats+\idx*4)
jmp *(hal_vsr_table+\idx*4)
.endm
hal_pc_irq_handler 32
hal_pc_irq_handler 33
hal_pc_irq_handler 34
hal_pc_irq_handler 35
hal_pc_irq_handler 36
hal_pc_irq_handler 37
hal_pc_irq_handler 38
hal_pc_irq_handler 39
hal_pc_irq_handler 40
hal_pc_irq_handler 41
hal_pc_irq_handler 42
hal_pc_irq_handler 43
hal_pc_irq_handler 44
hal_pc_irq_handler 45
hal_pc_irq_handler 46
hal_pc_irq_handler 47
#ifdef CYGPKG_HAL_SMP_SUPPORT
# Extra interrupt vectors for IOAPIc routed PCI and
# other interrupt sources
hal_pc_irq_handler 48
hal_pc_irq_handler 49
hal_pc_irq_handler 50
hal_pc_irq_handler 51
hal_pc_irq_handler 52
hal_pc_irq_handler 53
hal_pc_irq_handler 54
hal_pc_irq_handler 55
hal_pc_irq_handler 56
hal_pc_irq_handler 57
hal_pc_irq_handler 58
hal_pc_irq_handler 59
hal_pc_irq_handler 60
hal_pc_irq_handler 61
hal_pc_irq_handler 62
hal_pc_irq_handler 63
# Inter-CPU interrupts start at 64
hal_pc_irq_handler 64
hal_pc_irq_handler 65
hal_pc_irq_handler 66
hal_pc_irq_handler 67
#endif
# default vsr entries: pop the vector code from the stack and return.
default_vsr_iret:
add $4,%esp
iret
# GNUPro apps use "int $0x80" for syscalls.
# There is no vsr table entry for this.
.global __syscall_tramp
__syscall_tramp:
pushl $0x80
jmp __default_exception_vsr
#==============================================================================
# Initial and interrupt stack
#ifndef CYG_HAL_I386_INTERRUPT_STACK_DEFINED
.bss
#ifndef CYGPKG_HAL_SMP_SUPPORT
.balign 16
.global cyg_interrupt_stack_base
cyg_interrupt_stack_base:
__interrupt_stack_base:
.rept CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE
.byte 0
.endr
.balign 16
.global cyg_interrupt_stack
cyg_interrupt_stack:
__interrupt_stack:
.long 0,0,0,0,0,0,0,0
#else // CYGPKG_HAL_SMP_SUPPORT
__interrupt_stack_vector:
.rept CYGPKG_HAL_SMP_CPU_MAX
.long 0
.endr
.balign 16
.global cyg_interrupt_stack_base
cyg_interrupt_stack_base:
__interrupt_stack_base:
__interrupt_stack_first:
.rept CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE
.byte 0
.endr
.global cyg_interrupt_stack
cyg_interrupt_stack:
__interrupt_stack:
.rept CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE*(CYGPKG_HAL_SMP_CPU_MAX-1)
.byte 0
.endr
#endif // CYGPKG_HAL_SMP_SUPPORT
#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
.global __stub_stack_base
__stub_stack_base:
.rept CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE
.byte 0
.endr
.balign 16
.global __stub_stack
__stub_stack:
.long 0,0,0,0,0,0,0,0
#endif // CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
#endif // CYG_HAL_I386_INTERRUPT_STACK_DEFINED
#------------------------------------------------------------------------------
# end of vectors.S
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -