/*
 * interrupt.S
 *
 * Copyright 2002, Minoru Murashima. All rights reserved.
 * Distributed under the terms of the BSD License.
 *
 * 割り込みアセンブラルーチン
 */


#define ASM_FILE


#include"interrupt.h"
#include"segment.h"


/*
 * コンテキストセーブ
 */
.macro SAVE
	pushal
	pushl	%es
	pushl	%ds
/*	pushl	%fs
	pushl	%gs*/
.endm

/*
 * コンテキストリストア
 */
.macro RESTORE
/*	popl	%gs
	popl	%fs*/
	popl	%ds
	popl	%es
	popal
	iret
.endm

/*
 * タスクスイッチ
 */
.macro SWITCH
	pushl	$0				/* 前の割り込み時のesp値を保存 */
	pushl	%esp			/* esp値、戻り値は次のタスクのesp値保存アドレス */
	call	switch_task
	popl	%edx			/* コンテキストがセーブされたスタックのトップesp値 */
	movl	(%edx),%esp
	movl	%eax,%cr3		/* 次のタスクのページディレクトリ */
	popl	%eax			/* 前の割り込み時のesp値 */
	movl	%eax,(%edx)
.endm

/*
 * 割り込み
 */
.macro TRAP irq,handler
	SAVE
	movl	$KERNEL_DATA_DES,%eax
	movl	%eax,%es
	movl	%eax,%ds
	cld
	call	*irq_entry+\handler*4

	pushl	$\irq
	cli
	call	*irq_eoi
	addl	$4,%esp
	RESTORE
.endm

/*
 * タスクスイッチ割り込み
 */
.macro TRAP_SWITCH irq,handler
	SAVE
	movl	$KERNEL_DATA_DES,%eax
	movl	%eax,%es
	movl	%eax,%ds
	cld
	call	*irq_entry+\handler*4

	orl		%eax,%eax
	jz		1f
	SWITCH

1:	pushl	$\irq
	cli
	call	*irq_eoi
	addl	$4,%esp
	RESTORE
.endm


.text

/*
 * 例外ハンドラー
 */
.globl except0
except0:
	pushl	$0
	pushl	$0
	call	tmp_except

.globl except1
except1:
	pushl	$0
	pushl	$1
	call	tmp_except

.globl except2
except2:
	pushl	$0
	pushl	$2
	call	tmp_except

.globl except3
except3:
	pushl	$0
	pushl	$3
	call	tmp_except

.globl except4
except4:
	pushl	$0
	pushl	$4
	call	tmp_except

.globl except5
except5:
	pushl	$0
	pushl	$5
	call	tmp_except

.globl except6
except6:
	pushl	$0
	pushl	$6
	call	tmp_except

.globl except7
except7:
	pushl	$0
	pushl	$7
	call	tmp_except

.globl except8
except8:
	pushl	$0
	pushl	$8
	call	tmp_except

.globl except9
except9:
	pushl	$0
	pushl	$9
	call	tmp_except

.globl except10
except10:
	pushl	$0
	pushl	$10
	call	tmp_except

.globl except11
except11:
	pushl	$11
	call	tmp_except

.globl except12
except12:
	pushl	$12
	call	tmp_except

.globl except13
except13:
	pushl	$13
	call	tmp_except

.globl except14
except14:
	pushl	$14
	call	tmp_except

.globl except15
except15:
	pushl	$0
	pushl	$15
	call	tmp_except

.globl except16
except16:
	pushl	$0
	pushl	$16
	call	tmp_except

.globl except17
except17:
	pushl	$17
	call	tmp_except

.globl except18
except18:
	pushl	$0
	pushl	$18
	call	tmp_except

.globl except19
except19:
	pushl	$0
	pushl	$19
	call	tmp_except


/*
 * 割り込みハンドラー
 */
.globl apictimer
apictimer:
	TRAP_SWITCH 0,APIC_TIMER

.globl irq0
irq0:
	TRAP_SWITCH 0,IRQ0

.globl irq1
irq1:
	TRAP 1,IRQ1

.globl irq3
irq3:
	TRAP_SWITCH 3,IRQ3

.globl irq4
irq4:
	TRAP_SWITCH 4,IRQ4

.globl irq5
irq5:
	TRAP 5,IRQ5

.globl irq6
irq6:
	TRAP_SWITCH 6,IRQ6

.globl irq7
irq7:
	TRAP 7,IRQ7

.globl irq8
irq8:
	TRAP_SWITCH 8,IRQ8

.globl irq9
irq9:
	TRAP 9,IRQ9

.globl irq10
irq10:
	TRAP 10,IRQ10

.globl irq11
irq11:
	TRAP 11,IRQ11

.globl irq12
irq12:
	TRAP 12,IRQ12

.globl irq13
irq13:
	TRAP 13,IRQ13

.globl irq14
irq14:
	TRAP_SWITCH 14,IRQ14

.globl irq15
irq15:
	TRAP_SWITCH 15,IRQ15

.globl flash_pagedir
flash_pagedir:
	TRAP 0,FLASH_PAGEDIR


/*
 * System call
 */
.globl syscall0
syscall0:
	pushl	%es
	pushl	%ds
	movl	$KERNEL_DATA_DES,%ecx
	movl	%ecx,%ds
	call	*syscall_table(,%eax,4)
	popl	%ds
	popl	%es
	lret

.globl syscall1
syscall1:
	pushl	%es
	pushl	%ds
	movl	$KERNEL_DATA_DES,%ecx
	movl	%ecx,%ds
	movl	16(%esp),%edx
	pushl	%edx
	call	*syscall_table(,%eax,4)
	addl	$4,%esp
	popl	%ds
	popl	%es
	lret	$4*1

.globl syscall2
syscall2:
	pushl	%es
	pushl	%ds
	movl	$KERNEL_DATA_DES,%ecx
	movl	%ecx,%ds
	movl	20(%esp),%edx
	pushl	%edx
	movl	20(%esp),%ecx
	pushl	%ecx
	call	*syscall_table(,%eax,4)
	addl	$4*2,%esp
	popl	%ds
	popl	%es
	lret	$4*2

.globl syscall3
syscall3:
	pushl	%es
	pushl	%ds
	movl	$KERNEL_DATA_DES,%ecx
	movl	%ecx,%ds
	movl	24(%esp),%edx
	pushl	%edx
	movl	24(%esp),%ecx
	pushl	%ecx
	movl	24(%esp),%edx
	pushl	%edx
	call	*syscall_table(,%eax,4)
	addl	$4*3,%esp
	popl	%ds
	popl	%es
	lret	$4*3


/*
 * int sleep_task(int)
 * int sys_sleep(int)
 * Sleep task in time(ms)
 * parameters : time(ms)
 */
.globl sleep_task
sleep_task:
	popl	%eax			/* 呼び出し返りeip */
	pushl	$KERNEL_CODE_DES
	pushl	%eax
	SAVE
	jmp		1f
.globl sys_sleep
sys_sleep:
	SAVE
	movl	$KERNEL_DATA_DES,%edx
	movl	%edx,%es
	movl	%edx,%ds
1:	pushfl
	popl	%edx
	movl	48(%esp),%eax	/* 引数 */
	movl	%edx,48(%esp)
	pushl	%eax
	call	set_timer
	addl	$4,%esp
	cmpl	$1,%eax
	jne		1f
	SWITCH
	xorl	%eax,%eax
1:	movl	%eax,4*9(%esp)
	RESTORE


/*
 * void wait_task()
 */
.globl wait_task
wait_task:
	popl	%eax			/* 呼び出し返りeip */
	pushfl
	pushl	$KERNEL_CODE_DES
	pushl	%eax
	SAVE
	SWITCH
	RESTORE
