/* See COPYRIGHT for copyright information. */

#include <inc/asm.h>
#include <inc/mmu.h>
#include <inc/trap.h>
#include <kern/picirq.h>

###################################################################
# The kernel(this code) is linked at address ~(KERNBASE + 1 Meg), 
# but the bootloader load it at address	~1 Meg.
#	
# RELOC(x) maps a symbol x from its link address to its actual
# location in physical memory(its load address).	 
###################################################################
	
#define	RELOC(x) ((x) - KERNBASE)
	
###################################################################	
# See mmu.h for a complete description of these two.
###################################################################
.data
	.globl	_vpt
	.set	_vpt, VPT
	.globl	_vpd
	.set	_vpd, (VPT + SRL(VPT, 10))

###################################################################
# boot stack
###################################################################
	.p2align	PGSHIFT		# force page alignment
	.globl		_bootstack
_bootstack:
	.space		KSTKSIZE
	.globl		_bootstacktop   
_bootstacktop:

###################################################################
# setup the GDT	
###################################################################
.set CODE_SEL,0x8				# index of code seg within mygdt
.set DATA_SEL,0x10				# index of data seg within mygdt
.p2align	2				# force 4 byte alignment
mygdt:
	SEG_NULL				# null seg
	SEG(STA_X|STA_R, -KERNBASE, 0xffffffff)	# code seg
	SEG(STA_W, -KERNBASE, 0xffffffff)	# data seg
mygdtdesc:
	.word	0x17			# sizeof(mygdt) - 1
	.long	RELOC(mygdt)		# address mygdt
	
###################################################################
# entry point
###################################################################

.text
.globl		start
start:
	movw	$0x1234,0x472			# warm boot
	lgdt	RELOC(mygdtdesc)		# load descriptor
	movl	$DATA_SEL, %eax			# reload seg regs
	movw	%ax,%es				#
	movw	%ax,%ds				#
	movw	%ax,%ss				#
	ljmp	$CODE_SEL,$relocated		# reload CS
relocated:
	movl	$0x0,%ebp			# And nuke frame pointer

        # Leave a few words on the stack for the user trap frame UTF
	# XXX use sizeof(.)
	movl	$(_bootstacktop-0x40),%esp	# set the stack pointer 

	/* Zero the BSS */
	xorl	%eax,%eax			# quickest way to get zero
	cld					# d=0 string op is ascending
	movl	$_edata,%edi			# destination of string op
	movl	$(3 + _end),%ecx		# repeat count for "rep"
	subl	$_edata,%ecx			#  = ceil((_end-_edata)/4)
	shr	$2, %ecx
	rep
	 stosl					# store it!
	
	# now to C code
	call	_i386_init
	
	
###################################################################
# exceptions/interrupts
###################################################################

/* For certain traps the CPU automatically pushes an error code, for 
 * all other traps the IDTFUNC_NOEC() pushes a 0 in place of the error code,
 * so the trap frame has the same format.
 */
#define IDTFNC(name,num)      ENTRY(name)           pushl $(num); jmp _alltraps
#define IDTFNC_NOEC(name,num) ENTRY(name) pushl $0; pushl $(num); jmp _alltraps 

IDTFNC_NOEC(handler0, T_DIVIDE)
IDTFNC_NOEC(handler1, T_DEBUG)
IDTFNC_NOEC(handler2, T_NMI)
IDTFNC_NOEC(handler3, T_BRKPT)
IDTFNC_NOEC(handler4, T_OFLOW)
IDTFNC_NOEC(handler5, T_BOUND)
IDTFNC_NOEC(handler6, T_ILLOP)
IDTFNC_NOEC(handler7, T_DEVICE)
IDTFNC(handler8, T_DBLFLT)
IDTFNC_NOEC(handler9, 9)
IDTFNC(handler10, T_TSS)
IDTFNC(handler11, T_SEGNP)
IDTFNC(handler12, T_STACK)
IDTFNC(handler13, T_GPFLT)
IDTFNC(handler14, T_PGFLT)
IDTFNC_NOEC(handler15, 15)
IDTFNC_NOEC(handler16, T_FPERR)
IDTFNC(handler17, T_ALIGN)
IDTFNC_NOEC(handler18, T_MCHK)
IDTFNC_NOEC(handler19, 19)
IDTFNC_NOEC(handler20, 20)
IDTFNC_NOEC(handler21, 21)
IDTFNC_NOEC(handler22, 22)
IDTFNC_NOEC(handler23, 23)
IDTFNC_NOEC(handler24, 24)
IDTFNC_NOEC(handler25, 25)
IDTFNC_NOEC(handler26, 26)
IDTFNC_NOEC(handler27, 27)
IDTFNC_NOEC(handler28, 28)
IDTFNC_NOEC(handler29, 29)
IDTFNC_NOEC(handler30, 30)
IDTFNC_NOEC(handler31, 31)

# These are for the IRQ devices
IDTFNC_NOEC(handler32, 32)
IDTFNC_NOEC(handler33, 33)
IDTFNC_NOEC(handler36, 36)

IDTFNC_NOEC(handler48, T_SYSCALL)
_alltraps:
	pushl %ds
	pushl %es
	pushal
	movl $GD_KD,%eax	
	movw %ax,%ds
	movw %ax,%es
	pushl %esp
	call _trap
	popl %esp
	popal
	pop %es
	pop %ds
	add $8, %esp
	iret
