162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *	O32 interface for the 64 (or N32) ABI.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *	Copyright (C) 2002, 2014  Maciej W. Rozycki
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <asm/asm.h>
962306a36Sopenharmony_ci#include <asm/regdef.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/* O32 register size.  */
1262306a36Sopenharmony_ci#define O32_SZREG	4
1362306a36Sopenharmony_ci/* Maximum number of arguments supported.  Must be even!  */
1462306a36Sopenharmony_ci#define O32_ARGC	32
1562306a36Sopenharmony_ci/* Number of static registers we save.  */
1662306a36Sopenharmony_ci#define O32_STATC	11
1762306a36Sopenharmony_ci/* Argument area frame size.  */
1862306a36Sopenharmony_ci#define O32_ARGSZ	(O32_SZREG * O32_ARGC)
1962306a36Sopenharmony_ci/* Static register save area frame size.  */
2062306a36Sopenharmony_ci#define O32_STATSZ	(SZREG * O32_STATC)
2162306a36Sopenharmony_ci/* Stack pointer register save area frame size.  */
2262306a36Sopenharmony_ci#define O32_SPSZ	SZREG
2362306a36Sopenharmony_ci/* Combined area frame size.  */
2462306a36Sopenharmony_ci#define O32_FRAMESZ	(O32_ARGSZ + O32_SPSZ + O32_STATSZ)
2562306a36Sopenharmony_ci/* Switched stack frame size.  */
2662306a36Sopenharmony_ci#define O32_NFRAMESZ	(O32_ARGSZ + O32_SPSZ)
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci		.text
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/*
3162306a36Sopenharmony_ci * O32 function call dispatcher, for interfacing 32-bit ROM routines.
3262306a36Sopenharmony_ci *
3362306a36Sopenharmony_ci * The standard 64 (N32) calling sequence is supported, with a0 holding
3462306a36Sopenharmony_ci * a function pointer, a1 a pointer to the new stack to call the
3562306a36Sopenharmony_ci * function with or 0 if no stack switching is requested, a2-a7 -- the
3662306a36Sopenharmony_ci * function call's first six arguments, and the stack -- the remaining
3762306a36Sopenharmony_ci * arguments (up to O32_ARGC, including a2-a7).  Static registers, gp
3862306a36Sopenharmony_ci * and fp are preserved, v0 holds the result.  This code relies on the
3962306a36Sopenharmony_ci * called o32 function for sp and ra restoration and this dispatcher has
4062306a36Sopenharmony_ci * to be placed in a KSEGx (or KUSEG) address space.  Any pointers
4162306a36Sopenharmony_ci * passed have to point to addresses within one of these spaces as well.
4262306a36Sopenharmony_ci */
4362306a36Sopenharmony_ciNESTED(call_o32, O32_FRAMESZ, ra)
4462306a36Sopenharmony_ci		REG_SUBU	sp,O32_FRAMESZ
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci		REG_S		ra,O32_FRAMESZ-1*SZREG(sp)
4762306a36Sopenharmony_ci		REG_S		fp,O32_FRAMESZ-2*SZREG(sp)
4862306a36Sopenharmony_ci		REG_S		gp,O32_FRAMESZ-3*SZREG(sp)
4962306a36Sopenharmony_ci		REG_S		s7,O32_FRAMESZ-4*SZREG(sp)
5062306a36Sopenharmony_ci		REG_S		s6,O32_FRAMESZ-5*SZREG(sp)
5162306a36Sopenharmony_ci		REG_S		s5,O32_FRAMESZ-6*SZREG(sp)
5262306a36Sopenharmony_ci		REG_S		s4,O32_FRAMESZ-7*SZREG(sp)
5362306a36Sopenharmony_ci		REG_S		s3,O32_FRAMESZ-8*SZREG(sp)
5462306a36Sopenharmony_ci		REG_S		s2,O32_FRAMESZ-9*SZREG(sp)
5562306a36Sopenharmony_ci		REG_S		s1,O32_FRAMESZ-10*SZREG(sp)
5662306a36Sopenharmony_ci		REG_S		s0,O32_FRAMESZ-11*SZREG(sp)
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci		move		jp,a0
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci		move		fp,sp
6162306a36Sopenharmony_ci		beqz		a1,0f
6262306a36Sopenharmony_ci		REG_SUBU	fp,a1,O32_NFRAMESZ
6362306a36Sopenharmony_ci0:
6462306a36Sopenharmony_ci		REG_S		sp,O32_NFRAMESZ-1*SZREG(fp)
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci		sll		a0,a2,zero
6762306a36Sopenharmony_ci		sll		a1,a3,zero
6862306a36Sopenharmony_ci		sll		a2,a4,zero
6962306a36Sopenharmony_ci		sll		a3,a5,zero
7062306a36Sopenharmony_ci		sw		a6,4*O32_SZREG(fp)
7162306a36Sopenharmony_ci		sw		a7,5*O32_SZREG(fp)
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci		PTR_LA		t0,O32_FRAMESZ(sp)
7462306a36Sopenharmony_ci		PTR_LA		t1,6*O32_SZREG(fp)
7562306a36Sopenharmony_ci		li		t2,O32_ARGC-6
7662306a36Sopenharmony_ci1:
7762306a36Sopenharmony_ci		lw		t3,(t0)
7862306a36Sopenharmony_ci		REG_ADDU	t0,SZREG
7962306a36Sopenharmony_ci		sw		t3,(t1)
8062306a36Sopenharmony_ci		REG_SUBU	t2,1
8162306a36Sopenharmony_ci		REG_ADDU	t1,O32_SZREG
8262306a36Sopenharmony_ci		bnez		t2,1b
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci		move		sp,fp
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci		jalr		jp
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci		REG_L		sp,O32_NFRAMESZ-1*SZREG(sp)
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci		REG_L		s0,O32_FRAMESZ-11*SZREG(sp)
9162306a36Sopenharmony_ci		REG_L		s1,O32_FRAMESZ-10*SZREG(sp)
9262306a36Sopenharmony_ci		REG_L		s2,O32_FRAMESZ-9*SZREG(sp)
9362306a36Sopenharmony_ci		REG_L		s3,O32_FRAMESZ-8*SZREG(sp)
9462306a36Sopenharmony_ci		REG_L		s4,O32_FRAMESZ-7*SZREG(sp)
9562306a36Sopenharmony_ci		REG_L		s5,O32_FRAMESZ-6*SZREG(sp)
9662306a36Sopenharmony_ci		REG_L		s6,O32_FRAMESZ-5*SZREG(sp)
9762306a36Sopenharmony_ci		REG_L		s7,O32_FRAMESZ-4*SZREG(sp)
9862306a36Sopenharmony_ci		REG_L		gp,O32_FRAMESZ-3*SZREG(sp)
9962306a36Sopenharmony_ci		REG_L		fp,O32_FRAMESZ-2*SZREG(sp)
10062306a36Sopenharmony_ci		REG_L		ra,O32_FRAMESZ-1*SZREG(sp)
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci		REG_ADDU	sp,O32_FRAMESZ
10362306a36Sopenharmony_ci		jr		ra
10462306a36Sopenharmony_ciEND(call_o32)
105