/*
        IDEA in i386 assembler (for gcc)
        Author: Olaf Titz <olaf@bigred.inka.de>

        Follows the API defined in Richard De Moliner's reference
        implementation.

        Provides function Idea_Crypt.
        $Id: idea-i386.S,v 1.3 1997/03/31 22:07:01 olaf Exp $
*/

#define Idea_nofRound 8

#ifdef ASM_Idea_Crypt

#ifndef __ASSEMBLY__
#define __ASSEMBLY__
#endif
#include <linux/linkage.h>

/*
   IDEA is completely 16-bit operations. In a 32-bit segment, this
   means the code gets bulky from the many size prefixes. Perhaps
   this should be optimized a bit.
*/

/*
   Primitive operations: add/multiply in the next key element.
   I'm taking advantage of the fact that the multiply operation is only
   used for key material, and key material is used sequentially.
   Key is in (%esi).
*/

/* add key into x */
#define AddK(x)			\
	lodsw;			\
	addw	%ax, x

/* multiply key with x, result in %ax */
#define MulK0(x)		\
	lodsw;			\
	mulw	x;		\
	subw	%dx, %ax;	\
	jz	1f;		\
	adcw	$0, %ax;	\
	jmp	2f;		\
1:	movw	$1, %ax;	\
	subw	x, %ax;		\
	subw	-2(%esi), %ax;	\
2:

/* multiply key into x */
#define MulK(x)			\
	MulK0(x);		\
        movw	%ax, x

/*
    load/store data operations in correct byte order. i386 is little-endian.
    For the key, the byte order is set by Idea_ExpandUserKey().
*/

/* load data element into x */
#define LodX(x)			\
	lodsw;			\
	xchgb	%al, %ah;	\
	movw	%ax, x

/* store %ax into data element */
#define StoX			\
	xchgb	%al, %ah;	\
	stosw

/*
   void Idea_Crypt (Idea_Data dataIn, Idea_Data dataOut, Idea_Key key);
*/

ENTRY(Idea_Crypt)
	pushl	%ebx
	pushl	%ebp
	pushl	%esi
	pushl	%edi
#define SAVE	16 /* no. of bytes the saved registers occupy */

/* arguments relative to %esp */
#define dataIn	SAVE+4
#define dataOut	SAVE+8
#define key	SAVE+12
/* local variables */
#define X0	(%edi)
#define	X1	%bx
#define X2	%cx
#define X3	%bp
#define	RC	dataIn(%esp) /* abuse this */

        cld
	movl	dataIn(%esp), %esi
	movl	dataOut(%esp), %edi
	LodX(X0)
	LodX(X1)
	LodX(X2)
	LodX(X3)
	movl	key(%esp), %esi
	movw	$Idea_nofRound, RC
	.align 2,0x90

	/* Rounds 0-7 */
7:
	MulK(X0)
	AddK(X1)
	AddK(X2)
	MulK(X3)
	pushw	X1	/* T0 */
	pushw	X2	/* T1 */
	xorw	X0, X2
	xorw	X3, X1
	MulK(X2)
	addw	X2, X1
	MulK(X1)
	addw	X1, X2
	xorw	X1, X0
	xorw	X2, X3
	popw	%ax	/* T1 */
	xorw	%ax, X1
	popw	%ax	/* T0 */
	xorw	%ax, X2
	decw	RC
	jnz	7b

	/* Round 8 */
	MulK0(X0)
	StoX
	lodsw
	addw	X2, %ax
	StoX
	lodsw
	addw	X1, %ax
	StoX
	MulK0(X3)
	StoX

	popl	%edi
	popl	%esi
	popl	%ebp
	popl	%ebx
	ret
#undef	dataIn
#undef	dataOut
#undef	key

#endif ASM_Idea_Crypt
