##=============================================================================
##
##      vectors.S
##
##      x86 exception vectors
##
##=============================================================================
#####COPYRIGHTBEGIN####
#
# -------------------------------------------
# The contents of this file are subject to the Cygnus eCos Public License
# Version 1.0 (the "License"); you may not use this file except in
# compliance with the License.  You may obtain a copy of the License at
# http://sourceware.cygnus.com/ecos
# 
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the
# License for the specific language governing rights and limitations under
# the License.
# 
# The Original Code is eCos - Embedded Cygnus Operating System, released
# September 30, 1998.
# 
# The Initial Developer of the Original Code is Cygnus.  Portions created
# by Cygnus are Copyright (C) 1998,1999 Cygnus Solutions.  All Rights Reserved.
# -------------------------------------------
#
#####COPYRIGHTEND####
##=============================================================================
#######DESCRIPTIONBEGIN####
##
## Author(s):   jskov
## Contributors:jskov
## Date:        1999-01-07
## Purpose:     x86 exception vectors
## Description: This file defines the code placed into the exception
##              vectors. It also contains the first level default VSRs
##              that save and restore state for both exceptions and
##              interrupts.
##
######DESCRIPTIONEND####
##
##=============================================================================


// pjo, 15 oct 1999
#include <pkgconf/system.h>
#include <pkgconf/hal.h>

#ifdef CYGPKG_KERNEL
#include <pkgconf/kernel.h>
#endif /* CYGPKG_KERNEL */

#include <cyg/hal/arch.inc>


#==============================================================================

    .file   "vectors.S"

# The Linux synthetic target defines its own startup.
#ifdef CYGPKG_HAL_I386_LINUX
    .extern _linux_entry
    .text
    .globl _start

_start:
    jmp   _linux_entry

#else  ## ifdef CYGPKG_HAL_I386_LINUX
#==============================================================================
# Real startup code. We jump here from the various reset vectors to set up the
# world.

    .text
    .globl _start

_start: 
	hal_cpu_init
	hal_diag_init
	hal_mmu_init
	hal_fpu_init
	hal_memc_init
	hal_intc_init
	hal_cache_init
	hal_timer_init

# loading the stack pointer seems appropriate now.
	movl $_start, %esp

	hal_mon_init

	.extern hal_zero_bss
	call hal_zero_bss

	.extern hal_variant_init
	call hal_variant_init

	.extern hal_platform_init
	call hal_platform_init

	.extern cyg_hal_invoke_constructors
	call cyg_hal_invoke_constructors

#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
	.extern initialize_stub
	call initialize_stub
#endif /* CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS */

	.extern cyg_start
	call cyg_start

# Hmm.  Not expecting to return from cyg_start.
1:	hlt
	jmp 1b


# Add a bit of debugger support.
	.align 4
	.globl _breakinst
_breakinst:
	int $3
	ret




	.extern __interrupt_stack

#
#	hal_pc_generic_interrupt
#
#- Pushes the interrupt vector onto the stack, then
#  jumps to hal_pc_irq.
#
	.align 4, 0xCC
	.globl hal_pc_generic_interrupt
	.globl hal_pc_generic_interrupt_start
	.globl hal_pc_generic_interrupt_vector
	.globl hal_pc_generic_interrupt_end
hal_pc_generic_interrupt_start:
hal_pc_generic_interrupt:
	pushl $0xbad4c0de
hal_pc_generic_interrupt_vector = . - 4
	jmp *hal_pc_irq_p
hal_pc_generic_interrupt_end:

	.align 4, 0xCC
hal_pc_irq_p:
	.long hal_pc_irq


#
#	hal_pc_irq
#
#- Actually saves the CPU state, executes ISRs, etc.
#- The stack has eflags, cs, eip, and vector; all 32 bits.
#
	.align 4, 0xCC
	.globl hal_pc_irq
hal_pc_irq:
	pusha

# Show how far nested we are.
	.extern hal_pc_in_interrupt
	incl hal_pc_in_interrupt


#ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT
	.extern cyg_scheduler_sched_lock
	incl cyg_scheduler_sched_lock
#endif /* CYGFUN_HAL_COMMON_KERNEL_SUPPORT */


# Call cyg_hal_interrupt_handlers[vector](vector, cyg_hal_interrupt_data[vector])
	movl 0x20(%esp), %ecx
	movl $cyg_hal_interrupt_handlers, %ebx
	movl (%ebx, %ecx, 4), %edx
	movl $cyg_hal_interrupt_data, %ebx
	movl (%ebx, %ecx, 4), %eax
	pushl %eax
	pushl %ecx
	call *%edx  # eax has the return value, needed for interrupt_end()
	popl %ebx
	popl %ebx

# Fix our nesting figure.
	decl hal_pc_in_interrupt

# Send an EOI, maybe.
	hal_intc_ack 0x20(%esp)

# Reenable interrupts, if necessary.
	movl 0x2C(%esp), %eax
#	Turn off the single step flag.  GDB uses that to single step through
#	the code; we'll use the tasks' version of this flag in the popf later.
	andl $~(0x100), %eax
	pushl %eax
	popfl

#ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT
# Call interrupt_end(r, cyg_hal_interrupt_objects[vector], regs)
# - r is the return value from cyg_hal_interrupt_handlers;
# - regs just points to the stack; we have already saved our context there;
	movl $cyg_hal_interrupt_objects, %ebx
	movl (%ebx, %ecx, 4), %edx
	# regs is left from the push of ebp above;
	pushl %edx
	pushl %eax
	call interrupt_end
	addl $8, %esp
#endif /* CYGFUN_HAL_COMMON_KERNEL_SUPPORT */

	popa  # restore all our registers.
	addl $4, %esp  # dump the vector number
	iret  # and return to the program.


# pc_outb(port, value)
	.align 4
	.globl pc_outb
pc_outb:
	movl 4(%esp), %edx
	movl 8(%esp), %eax
	outb %al, %dx
	ret


# x = pc_inb(port)
	.align 4
	.globl pc_inb
pc_inb:
	movl 4(%esp), %edx
	inb %dx, %al
	cbtw
	cwtl
	ret

# pc_outw(port, value)
	.align 4
	.globl pc_outw
pc_outw:
	movl 4(%esp), %edx
	movl 8(%esp), %eax
	outw %ax, %dx
	ret


# x = pc_inw(port)
	.align 4
	.globl pc_inw
pc_inw:
	movl 4(%esp), %edx
	inw %dx, %ax
	cwtl
	ret



#endif ## ifndef CYGPKG_HAL_I386_LINUX

#------------------------------------------------------------------------------
# end of vectors.S
