/*
 * bootload.S
 *
 * Copyright 2002, Minoru Murashima. All rights reserved.
 * Distributed under the terms of the BSD License.
 *
 * 最初にBIOSによってfloppyからロードされるコードなので、サイズは512バイト以下にしなければならない。
 * これは、setupコードをSTART_ADDRESSにロードして、制御を渡すことが目的である。
 *
 * ロードする前にマルチプロセッサシステム用にMPFloatingPointerStructureを検索する。
 * <注意>ebpはMPFloatingPointerStructureアドレス格納に使用する。
 *
 */


#define ASM_FILE


#include "config.h"


/* ロードするsetupのバイナリサイズ、値はmake時に自動で挿入する */
SETUP_SIZE=36848

BOOT_SEGMENT=0x07C0				/* BIOSによりロードされるセグメント */
SS_SEGMENT=0x9000				/* Stackは安全を考えて使用可能メモリーの一番端に設定 */
SP_INIT=0x10000-0x200			/* 初期スタックポインタ値 */
CHANGE_SEGMENT=0x60				/* 本体の移動先セグメント */
SETUP_SEGMENT=START_ADDRESS>>4	/* setupモジュールのロードセグメント */

MP_SIGN=0x5f504d5f				/* MP Floating Pointer Structure検索用サイン */

SECTER_SIZE=512					/* フロッピーの１セクターサイズ */
SECTER_NUM=18					/* フロッピーの１トラック内のセクター数 */


.text
.code16
.globl _start
_start:
	movw	$SS_SEGMENT,%ax
	movw	%ax,%ss
	movw	$SP_INIT,%sp
	movw	$BOOT_SEGMENT,%ax
	movw	%ax,%ds

	/*
	 * メモリーがsetupコードで上書きされる前にMPFloatingPointerStructureを検索する
	 *
	 * 探す場所は次の３箇所
	 *	1 EDBC内(セグメントは0x40eに記述)最初の1kバイト
	 *	2 BIOS内(0xf0000から)64kバイト
	 *	3 ベースメモリー(640k)最後の1kバイト
	 */
	xorl	%ebp,%ebp
	pushw	%ds
	xorw	%ax,%ax
	movw	%ax,%ds
	movw	0x40e,%ax
	popw	%ds
	pushw	$0x400
	pushw	%ax
	call	search_sign
	orl		%ebp,%ebp
	jnz		end
	pushw	$0
	pushw	$0xf000
	call	search_sign
	orl		%ebp,%ebp
	jnz		end
	pushw	$0x400
	pushw	$(0xa000-0x40)
	call	search_sign
end:

	/*
	 * 本体コードをsetupロードアドレスよりも前のアドレスに移動する
	 */
	cld
	movw	$CHANGE_SEGMENT,%ax
	movw	%ax,%es
	xorw	%si,%si
	xorw	%di,%di
	movw	$512/2,%cx
	rep
	movsw
	ljmp	$CHANGE_SEGMENT,$change_end
change_end:
	movw	$CHANGE_SEGMENT,%ax
	movw	%ax,%ds

	/*
	 * BIOS割り込みを使ってsetupバイナリをSETUP_SEGMENTにロードする
	 */
	pushw	$80*24
	pushw	$load_message
	call	print_ascii		/* ロードメッセージを表示する */

	/* 初期設定 */
	movw	$SETUP_SEGMENT,%ax
	andw	$0xf000,%ax
	movw	%ax,%es				/* 読み込み先セグメント */
	movw	$SETUP_SEGMENT,%bx
	andw	$0xfff,%bx
	shlw	$4,%bx				/* 読み込み先アドレス */
	movb	$2,%cl				/* 読み込み開始セクター番号 */
	movb	$0,%ch				/* 開始トラック番号 */
	movw	$0,%dx				/* ディスクの種類 dl=0(フロッピー) ヘッド番号 dh=0 */
	movw	$(SETUP_SIZE+SECTER_SIZE-1)/SECTER_SIZE,%si	/* 総読み込みセクター数 */

	/* 読み込み開始 */
loop:
	movw	$SECTER_NUM+1,%ax
	subb	%cl,%al			/* 1トラックの読み込みセクター数 */
	movw	%ax,%di
	shlw	$9,%di			/* *512バイト */
	addw	%bx,%di			/* 1回のRead操作が64Kbyte境界を越えてるかをチェック */
	jnc		1f				/* 超えていないならジャンプ */
	xorw	%di,%di
	subw	%bx,%di
	shrw	$9,%di			/* /512バイト */
	movw	%di,%ax			/* ax=64Kbyte境界を越えない読み込みセクター数 */
1:	cmpw	%si,%ax			/* 読み込みセクター数が総読み込みSecter数より大きいかチェック */
	jbe		read
	movw	%si,%ax
read:
	movb	$2,%ah
	int		$0x13
	jc		read_error
	incw	mark_position
	pushw	mark_position
	pushw	$load_mark
	call	print_ascii		/* ロードマークの表示 */
	subw	%ax,%si			/* al=読み込んだセクター数 */
	jz		end_loop		/* 残りセクター数が0なら終了 */

	addb	%al,%cl
	cmpb	$SECTER_NUM,%cl
	jbe		1f				/* １トラック内のセクター数を超えていなければジャンプ */
	movb	$1,%cl
	xorb	$1,%dh			/* ヘッド番号の設定 */
	incb	%ch
	subb	%dh,%ch			/* トラック番号の設定 Trackの進み方 head 0,track 0→head 1,track0→head 0,track 1→... */
1:	shlw	$9,%ax			/* *512byte */
	addw	%ax,%bx			/* 読み込み先アドレスの設定 */
	jnz		loop
	movw	%es,%ax			/* アドレスが0に戻ったらセグメントを0x1000進める */
	addw	$0x1000,%ax
	movw	%ax,%es
	jmp		loop
end_loop:

	/* FloppyMotorを止める */
	movb	$0,%al
	movw	$0x3f2,%dx
	outb	%dx

	/*
	 * ロードしたセットアップコードにジャンプする
	 */
	ljmp	$SETUP_SEGMENT,$0


/*
 * MPFloatingPointerStructureサインを検索する
 * 引数 : アドレスセグメント、検索対象バイト数
 */
search_sign:
	pushw	%bp
	movw	%sp,%bp
	movw	4(%bp),%ax
	movw	6(%bp),%cx
	popw	%bp
	pushw	%ds
	movw	%ax,%ds
	xorl	%ebx,%ebx

1:	movl	(%bx),%eax
	cmpl	$MP_SIGN,%eax
	je		2f
	addw	$4,%bx
	cmpw	%cx,%bx
	je		3f
	jmp		1b

2:	movw	%ds,%dx
	movw	%dx,%bp
	shll	$4,%ebp
	addl	%ebx,%ebp
3:	popw	%ds
	ret		$4


/*
 * フロッピー読み込みエラー時の処理
 * エラーコードを表示してストップする
 */
read_error:
	shrw	$8,%ax
	pushw	$80*24+30
	pushw	%ax
	call	print_binary
	pushw	$80*24
	pushw	$read_error_message
	call	print_ascii
	cli
	hlt


/*
 * 空文字付きアスキー文字列を表示する
 * 引数 : 文字列アドレス、表示開始位置
 */
print_ascii:
	pushw	%dx
	pushw	%si
	pushw	%di
	pushw	%bp
	pushw	%es

	movw	$VIDEO_ADDRESS>>4,%dx
	movw	%dx,%es
	movw	%sp,%bp
	movw	12(%bp),%si
	movw	14(%bp),%di
	shlw	$1,%di
1:	movb	(%si),%dl
	cmpb	$0,%dl
	je		2f
	movb	%dl,%es:(%di)
	incw	%si
	addw	$2,%di
	jmp		1b

2:	popw	%es
	popw	%bp
	popw	%di
	popw	%si
	popw	%dx
	ret		$4


/*
 * 2バイトバイナリ値を表示する
 * 引数 : バイナリ値、表示開始位置
 */
print_binary:
	pushw	%ax
	pushw	%bx
	pushw	%dx
	pushw	%bp
	pushw	%ds

	movw	$VIDEO_ADDRESS>>4,%ax
	movw	%ax,%ds
	movw	%sp,%bp
	movw	12(%bp),%ax
	movw	14(%bp),%bx
	shlw	$1,%bx
	shlw	$1,14(%bp)
	addw	$6,%bx
1:	movw	%ax,%dx
	andw	$0xf,%dx
	cmpw	$9,%dx
	jbe		2f
	addw	$7,%dx
2:	addw	$0x30,%dx
	movb	%dl,(%bx)
	shrw	$4,%ax
	subw	$2,%bx
	cmpw	14(%bp),%bx
	jge		1b

	popw	%ds
	popw	%bp
	popw	%dx
	popw	%bx
	popw	%ax
	ret		$4


load_message:
	.string	"Start loading."

load_mark:
	.string	"."

mark_position:
	.word	24*80+13

read_error_message:
	.string	"Floppy read errer. Boot stop!"
