.globl	entry, __switch_context, __exit_context, halt, init_exceptions

	.text
	.align	4

/*
 * Entry point
 * We start execution from here.
 * It is assumed that CPU is in 32-bit protected mode and
 * all segments are 4GB and base zero (flat model).
 */
entry:
	/* Save boot context and switch to our main context.
	 * Main context is statically defined in C.
	 */
	pushl	%cs
	call	__switch_context

	/* We get here when the main context switches back to
	 * the boot context.
	 * Return to previous bootloader.
	 */
	ret

/*
 * Switch execution context
 * This saves registers, segments, and GDT in the stack, then
 * switches the stack, and restores everything from the new stack.
 * This function takes no argument. New stack pointer is
 * taken from global variable __context, and old stack pointer
 * is also saved to __context. This way we can just jump to
 * this routine to get back to the original context.
 *
 * Call this routine with lcall or pushl %cs; call.
 */
__switch_context:
	/* Save everything in current stack */
	pushfl		    /* 56 */
	pushl	%ds	    /* 52 */
	pushl	%es	    /* 48 */
	pushl	%fs	    /* 44 */
	pushl	%gs	    /* 40 */
	pushal		    /* 8 */
	subl	$8, %esp
	movw	%ss, (%esp) /* 0 */
	sgdt	2(%esp)	    /* 2 */

#if 0
	/* Swap %cs and %eip on the stack, so lret will work */
	movl	60(%esp), %eax
	xchgl	%eax, 64(%esp)
	movl	%eax, 60(%esp)
#endif

	/* At this point we don't know if we are on flat segment
	 * or relocated. So compute the address offset from %eip.
	 * Assuming CS.base==DS.base==SS.base.
	 */
	call	1f
1:	popl	%ebx
	subl	$1b, %ebx

	/* Interrupts are not allowed... */
	cli

	/* Current context pointer is our stack pointer */
	movl	%esp, %esi

	/* Normalize the ctx pointer */
	subl	%ebx, %esi

	/* Swap it with new value */
	xchgl	%esi, __context(%ebx)

	/* Adjust new ctx pointer for current address offset */
	addl	%ebx, %esi

	/* Load new %ss and %esp to temporary */
	movzwl	(%esi), %edx
	movl	20(%esi), %eax

	/* Load new GDT */
	lgdt	2(%esi)

	/* Load new stack segment with new GDT */
	movl	%edx, %ss

	/* Set new stack pointer, but we have to adjust it because
	 * pushal saves %esp value before pushal, and we want the value
	 * after pushal.
	 */
	leal	-32(%eax), %esp

	/* Load the rest from new stack */
	popal
	popl	%gs
	popl	%fs
	popl	%es
	popl	%ds
	popfl

	/* Finally, load new %cs and %eip */
	lret

__exit_context:
	/* Get back to the original context */
	pushl	%cs
	call	__switch_context

	/* We get here if the other context attempt to switch to this
	 * dead context. This should not happen. */

halt:
	cli
	hlt
	jmp	halt

/*
 * initialize exception handler. All exceptions end up in the same
 * C function.
 */

init_exceptions:
	pushl	%ebx
	pushl	%edi

        /* Initialize the Interrupt Descriptor table */
        leal    _idt, %edi
        leal    vec0, %ebx
        movl    $(0x08 << 16), %eax     /* cs selector */

1:      movw    %bx, %ax
        movl    %ebx, %edx
        movw    $0x8E00, %dx            /* Interrupt gate - dpl=0, present */
        movl    %eax, 0(%edi)
        movl    %edx, 4(%edi)
        addl    $6, %ebx
        addl    $8, %edi
        cmpl    $_idt_end, %edi
        jne     1b

        /* Load the Interrupt descriptor table */
        lidt    idtarg

	movl 	$0, %eax
	popl	%edi
	popl	%ebx
	ret

vec0:
        pushl   $0 /* error code */
        pushl   $0 /* vector */
        jmp int_hand
vec1:
        pushl   $0 /* error code */
        pushl   $1 /* vector */
        jmp int_hand

vec2:
        pushl   $0 /* error code */
        pushl   $2 /* vector */
        jmp int_hand

vec3:
        pushl   $0 /* error code */
        pushl   $3 /* vector */
        jmp     int_hand

vec4:
        pushl   $0 /* error code */
        pushl   $4 /* vector */
        jmp     int_hand

vec5:
        pushl   $0 /* error code */
        pushl   $5 /* vector */
        jmp     int_hand

vec6:
        pushl   $0 /* error code */
        pushl   $6 /* vector */
        jmp     int_hand
vec7:
        pushl   $0 /* error code */
        pushl   $7 /* vector */
        jmp     int_hand

vec8:
        /* error code */
        pushl   $8 /* vector */
        jmp     int_hand
        .word   0x9090

vec9:
        pushl   $0 /* error code */
        pushl   $9 /* vector */
        jmp int_hand

vec10:
        /* error code */
        pushl   $10 /* vector */
        jmp     int_hand
        .word   0x9090

vec11:
        /* error code */
        pushl   $11 /* vector */
        jmp     int_hand
        .word   0x9090

vec12:
        /* error code */
        pushl   $12 /* vector */
        jmp     int_hand
        .word   0x9090

vec13:
        /* error code */
        pushl   $13 /* vector */
        jmp     int_hand
        .word   0x9090

vec14:
        /* error code */
        pushl   $14 /* vector */
        jmp     int_hand
        .word   0x9090

vec15:
        pushl   $0 /* error code */
        pushl   $15 /* vector */
        jmp     int_hand

vec16:
        pushl   $0 /* error code */
        pushl   $16 /* vector */
        jmp     int_hand

vec17:
        /* error code */
        pushl   $17 /* vector */
        jmp     int_hand
        .word   0x9090

vec18:
        pushl   $0 /* error code */
        pushl   $18 /* vector */
        jmp     int_hand

vec19:
        pushl   $0 /* error code */
        pushl   $19 /* vector */
        jmp     int_hand

__divide_error:
        pushl   $0 /* error code */
        pushl   $20 /* vector */
        jmp     int_hand
        .global __divide_error

int_hand:
        /* At this point on the stack there is:
         *  0(%esp) vector
         *  4(%esp) error code
         *  8(%esp) eip
         * 12(%esp) cs
         * 16(%esp) eflags
         */
        pushl   %edi
        pushl   %esi
        pushl   %ebp
        /* Original stack pointer */
        leal    32(%esp), %ebp
        pushl   %ebp
        pushl   %ebx
        pushl   %edx
        pushl   %ecx
        pushl   %eax

        pushl   %esp    /* Pointer to structure on the stack */

        call    x86_exception
        pop     %eax    /* Drop the pointer */

        popl    %eax
        popl    %ecx
        popl    %edx
        popl    %ebx
        popl    %ebp /* Ignore saved %esp value */
        popl    %ebp
        popl    %esi
        popl    %edi

        addl    $8, %esp /* pop of the vector and error code */

        iret

idtarg:
        .word   _idt_end - _idt - 1     /* limit */
        .long   _idt
        .word   0
_idt:
        .fill   20, 8, 0        # idt is unitiailzed
_idt_end:

        .globl  arch_nvram_size, arch_nvram_get, arch_nvram_put
arch_nvram_size:
        xor     %eax, %eax
        ret

arch_nvram_get:
        ret

arch_nvram_put:
        ret