/*
 * lib.S
 *
 * Copyright 2002, Minoru Murashima. All rights reserved.
 * Distributed under the terms of the BSD License.
 *
 * アセンブラルーチンライブラリー
 */


#define ASM_FILE


#include"segment.h"


.text


/*
 * void idle();
 * アイドルルーチン
 */
.globl idle
idle:
	hlt
	jmp		idle


/*
 * long long rdtsc()
 * 返り値 : クロックカウント値
 */
.globl rdtsc
rdtsc:
	rdtsc
	ret


/*
 * void *memcpy(void *dest,const void *src, size_t n);
 * オーバーラップしないコピー
 * P6プロセッサの場合、アドレスが8バイト境界で256バイト以上のコピーなら高速でコピーする
 */
.globl memcpy
memcpy:
	pushl	%esi
	pushl	%edi
	movl	12(%esp),%edi
	movl	16(%esp),%esi
	cmpl	%esi,%edi
	je		1f

	/* Adjust alignment by 4bytes */
	xorl	%ecx,%ecx
	subl	%esi,%ecx
	andl	$0x3,%ecx
	cmpl	20(%esp),%ecx
	ja		2f
	movl	%ecx,%eax
	rep
	movsb

	/* Move by 4bytes */
	movl	20(%esp),%ecx
	subl	%eax,%ecx
	movl	%ecx,20(%esp)
	shrl	$2,%ecx
	rep
	movsl

	/* Move rest by bytes */
2:	movl	20(%esp),%ecx
	andl	$0x3,%ecx
	rep
	movsb

1:	movl	12(%esp),%eax
	popl	%edi
	popl	%esi
	ret


/*
 * void *memset(void *dest,int c,size_t n);
 * P6プロセッサの場合、アドレスが8バイト境界で256バイト以上のコピーなら高速でコピーする
 */
.globl memset
memset:
	pushl	%edi
	movl	8(%esp),%edi
	movl	12(%esp),%eax
	movl	16(%esp),%ecx
	orl		%ecx,%ecx
	je		1f

	/* Adjust alignment by 8bytes */
	xorl	%ecx,%ecx
	subl	%edi,%ecx
	andl	$0x7,%ecx
	cmpl	16(%esp),%ecx
	ja		2f
	movl	%ecx,%edx
	rep
	stosb

	/* Store by 4bytes */
	movb	%al,%ah
	movl	%eax,%ecx
	shll	$16,%eax
	orl		%ecx,%eax
	movl	16(%esp),%ecx
	subl	%edx,%ecx
	movl	%ecx,16(%esp)
	shrl	$2,%ecx
	rep
	stosl

	/* Store rest by bytes */
2:	movl	16(%esp),%ecx
	andl	$0x3,%ecx
	rep
	stosb

1:	movl	12(%esp),%eax
	popl	%edi
	ret


/*
 * void *memcpy_to_user(void *dest,const void *src, size_t n);
 * memcpy to user
 */
.globl memcpy_to_user
memcpy_to_user:
	pushl	%es
	movl	$USER_DATA_DES,%eax
	movl	%eax,%es

	movl	8(%esp),%eax
	movl	12(%esp),%ecx
	movl	16(%esp),%edx
	pushl	%edx
	pushl	%ecx
	pushl	%eax
	call	memcpy
	addl	$12,%esp

	popl	%es
	ret


/*
 * void *memcpy_from_user(void *dest,const void *src, size_t n);
 * memcpy from user
 */
.globl memcpy_from_user
memcpy_from_user:
	pushl	%ds
	movl	$USER_DATA_DES,%eax
	movl	%eax,%ds

	movl	8(%esp),%eax
	movl	12(%esp),%ecx
	movl	16(%esp),%edx
	pushl	%edx
	pushl	%ecx
	pushl	%eax
	call	memcpy
	addl	$12,%esp

	popl	%ds
	ret
