/*
 * setup.S
 *
 * Copyright 2002, Minoru Murashima. All rights reserved.
 * Distributed under the terms of the BSD License.
 *
 * アセンブラメインセットアププログラム
 *
 * このプログラムはbootload.sによりconfig.hで定義されるSTART_ADDRESSにロードされるので、
 * Makefileの-Ttext引数にもSTART_ADDRESS値を設定しなければならない。
 *
 * bootload.sにより
 * 	ebp=MPFloatingPointerStructureアドレス
 * が代入さる。
 *
 * 8cpuに対応させる
 */


#define ASM_FILE


#include"config.h"
#include"segment.h"
#include"apm.h"


#define SYS_EXEC 1				/* execシステムコールの値 */
#define BOOT_KERNEL_STACK START_ADDRESS		/* BOOT時のカーネルスタックポインタ */
/*
 * BOOT時のカーネルスタックサイズ
 * BIOS DATA AREA を壊さない大きさにする
 */
#define BOOT_KERNEL_STACK_SIZE 0x100


.text

.code16
.globl _start
_start:

/* Application cpuならBIOS初期化コードにjump */
.globl mpstart
mpstart:
	movl	$cpu_num,%eax
	shrl	$4,%eax
	andw	$0xf000,%ax
	movw	%ax,%ds
	movw	cpu_num,%ax
	orw		%ax,%ax
	jz		apm
	jmp		jumpToBios

/* リブート用。 */
.globl switchRealMode
switchRealMode:
	movl	%cr0,%eax
	andl	$0xfffffffe,%eax
	movl	%eax,%cr0
	wbinvd

jumpToBios:
	ljmp	$0xffff,$0

/* APMの設定。 */
apm:
	movb	$APM_FUNC,%ah
	movb	$APM_FUNC_CHCK,%al
	movw	$APM_DEV_APMBIOS,%bx
	int		$APM_BIOS				/* Check APM. */
	movw	%ax,apmVersion
	jc		1f
	movw	%cx,apmFlag
	testw	$APM_FLG_32MODE,%cx		/* Support 32bit connection? */
	jz		1f

	movb	$APM_FUNC,%ah
	movb	$APM_FUNC_32MODE,%al
	movw	$APM_DEV_APMBIOS,%bx
	int		$APM_BIOS				/* 32bit interface connect. */
	movw	%ax,apmCodeSegBase		/* Code segment base address. */
	jc		1f
	movw	%cx,apmCode16SegBase	/* 16bit code segment base address. */
	movw	%dx,apmDataSegBase		/* Data segment base address. */
	movl	%ebx,apmOffset			/* Offset of the entry point. */
	movw	%si,apmCodeSegLen		/* Code segment length. */
	shrl	$16,%esi
	movw	%si,apmCode16SegLen		/* 16bit code segment length. */
	movw	%di,apmDataSegLen		/* Data segment length. */
1:

/* プロテクトモード移行16ビットコード */
.globl switch_protect_mode
switch_protect_mode:
	movl	$gdtr,%eax
	shrl	$4,%eax
	andw	$0xf000,%ax
	movw	%ax,%ds
	cli
	lgdt	gdtr
	movl	%cr0,%eax
	orw		$1,%ax
	movl	%eax,%cr0
	wbinvd					/* シリアル化+キャッシュメモリーバック命令 */
	ljmp	$KERNEL_CODE_DES,$start_protect_mode

/* プロテクトモード開始 */
.code32
start_protect_mode:
	movl	$0x10,%eax
	movl	%eax,%ds
	movl	%eax,%ss
	movl	%eax,%es		/* movs命令に対応するためesをセット */
	cld
1:	lock					/* スピンロックに入る */
	btsl	$1,stack_lock
	jc		1b

	movl	kernel_stack,%esp
	subl	$BOOT_KERNEL_STACK_SIZE,kernel_stack

	movl	$0,stack_lock	/* スピンロックから出る */

	xorl	%eax,%eax
	movl	%eax,%fs
	movl	%eax,%gs

/*  IDTをロードするを */
	lidt	idtr

/* Application cpuなら初期化用コードにジャンプ */
	cmpl	$0,cpu_num
	jz		1f
	jmp		init_application_cpu
1:
/************************************************************************************************************/
	/* テスト用、有効にするとマルチプロセッサでもシングルプロセッサモードになる */
//	xorl	%ebp,%ebp
/************************************************************************************************************/
	movl	%ebp,MFPS_addres	/* MP Floating Pointer Structureアドレスを代入 */

	call	main				/* main setup in C language */

	movl	$KERNEL_ESP_BEG,%esp
	call	init				/* Start init */


/* int startExec(const char*,void*,void*) */
.globl startExec
startExec:
	pushl	$0				/* user ss */
	pushl	$0				/* user eps */
	movl	20(%esp),%eax
	pushl	%eax
	movl	20(%esp),%eax
	pushl	%eax
	movl	20(%esp),%eax
	pushl	%eax
	pushl	$0				/* ユーザーシステムコール呼び出し元 eip */
	movl	$SYS_EXEC,%eax
	lcall	$KERNEL_CODE_DES,$syscall3
	addl	$8,%esp
	ret


.align 4

.globl apmVersion,apmFlag
apmVersion:
	.word	0		/* Apm version. */
apmFlag:
	.word	0		/* Apm flags. */

.globl apmCodeSegBase,apmCode16SegBase,apmDataSegBase,apmOffset,apmCodeSegLen,apmCode16SegLen,apmDataSegLen
apmCodeSegBase:
	.long	0		/* 32-bit code segment (real mode segment base address). */
apmCode16SegBase:
	.long	0		/* 16-bit code segment (real mode segment base address). */
apmDataSegBase:
	.long	0		/* APM data segment (real mode segment base address). */
apmOffset:
	.long	0		/* Offset of the entry point into the APM BIOS. */
apmCodeSegLen:
	.long	0		/* APM BIOS 32-bit code segment length. */
apmCode16SegLen:
	.long	0		/* APM BIOS 16-bit code segment length. */
apmDataSegLen:
	.long	0		/* APM BIOS data segment length. */

kernel_stack:
	.long	BOOT_KERNEL_STACK

stack_lock:
	.long	0

cpu_num:
	.long	0

.globl active_cpu
active_cpu:					/* Number of active cpus */
	.long	cpu_num

gdtr:
	.word	GDT_ENTRY*8-1
	.long	gdt	
