Commit 0b537257 authored by Max Filippov's avatar Max Filippov

xtensa: implement call0 ABI support in assembly

Replace hardcoded register and opcode names with ABI-agnostic macros.
Add register save/restore code where necessary. Conditionalize windowed
only or call0 only code. Add stack initialization matching _switch_to
epilogue to copy_thread.
Signed-off-by: default avatarMax Filippov <jcmvbkbc@gmail.com>
parent 5cce39b6
......@@ -3,6 +3,7 @@
#include <asm/regs.h>
#include <asm/asmmacro.h>
#include <asm/cacheasm.h>
#include <asm/processor.h>
/*
* RB-Data: RedBoot data/bss
* P: Boot-Parameters
......@@ -36,7 +37,7 @@
.globl __start
/* this must be the first byte of the loader! */
__start:
entry sp, 32 # we do not intend to return
abi_entry(32) # we do not intend to return
_call0 _start
__start_a0:
.align 4
......@@ -62,10 +63,12 @@ _start:
wsr a4, windowstart
rsync
movi a4, 0x00040000
movi a4, KERNEL_PS_WOE_MASK
wsr a4, ps
rsync
KABI_C0 mov abi_saved0, abi_arg0
/* copy the loader to its address
* Note: The loader itself is a very small piece, so we assume we
* don't partially overlap. We also assume (even more important)
......@@ -168,52 +171,52 @@ _reloc:
movi a3, __image_load
sub a4, a3, a4
add a8, a0, a4
add abi_arg2, a0, a4
# a1 Stack
# a8(a4) Load address of the image
movi a6, _image_start
movi a10, _image_end
movi a7, 0x1000000
sub a11, a10, a6
movi a9, complen
s32i a11, a9, 0
movi abi_arg0, _image_start
movi abi_arg4, _image_end
movi abi_arg1, 0x1000000
sub abi_tmp0, abi_arg4, abi_arg0
movi abi_arg3, complen
s32i abi_tmp0, abi_arg3, 0
movi a0, 0
# a6 destination
# a7 maximum size of destination
# a8 source
# a9 ptr to length
# abi_arg0 destination
# abi_arg1 maximum size of destination
# abi_arg2 source
# abi_arg3 ptr to length
.extern gunzip
movi a4, gunzip
beqz a4, 1f
movi abi_tmp0, gunzip
beqz abi_tmp0, 1f
callx4 a4
abi_callx abi_tmp0
j 2f
# a6 destination start
# a7 maximum size of destination
# a8 source start
# a9 ptr to length
# a10 destination end
# abi_arg0 destination start
# abi_arg1 maximum size of destination
# abi_arg2 source start
# abi_arg3 ptr to length
# abi_arg4 destination end
1:
l32i a9, a8, 0
l32i a11, a8, 4
s32i a9, a6, 0
s32i a11, a6, 4
l32i a9, a8, 8
l32i a11, a8, 12
s32i a9, a6, 8
s32i a11, a6, 12
addi a6, a6, 16
addi a8, a8, 16
blt a6, a10, 1b
l32i abi_tmp0, abi_arg2, 0
l32i abi_tmp1, abi_arg2, 4
s32i abi_tmp0, abi_arg0, 0
s32i abi_tmp1, abi_arg0, 4
l32i abi_tmp0, abi_arg2, 8
l32i abi_tmp1, abi_arg2, 12
s32i abi_tmp0, abi_arg0, 8
s32i abi_tmp1, abi_arg0, 12
addi abi_arg0, abi_arg0, 16
addi abi_arg2, abi_arg2, 16
blt abi_arg0, abi_arg4, 1b
/* jump to the kernel */
......@@ -230,6 +233,7 @@ _reloc:
# a2 Boot parameter list
KABI_C0 mov abi_arg0, abi_saved0
movi a0, _image_start
jx a0
......
This diff is collapsed.
......@@ -15,6 +15,7 @@
* Kevin Chea
*/
#include <asm/asmmacro.h>
#include <asm/processor.h>
#include <asm/page.h>
#include <asm/cacheasm.h>
......@@ -193,9 +194,10 @@ ENTRY(_startup)
movi a1, start_info
l32i a1, a1, 0
movi a2, PS_WOE_MASK | LOCKLEVEL
# WOE=1, INTLEVEL=LOCKLEVEL, UM=0
wsr a2, ps # (enable reg-windows; progmode stack)
/* Disable interrupts. */
/* Enable window exceptions if kernel is built with windowed ABI. */
movi a2, KERNEL_PS_WOE_MASK | LOCKLEVEL
wsr a2, ps
rsync
#ifdef CONFIG_SMP
......@@ -267,13 +269,13 @@ ENTRY(_startup)
l32i a1, a1, 0
#endif
movi a6, 0
xsr a6, excsave1
movi abi_arg0, 0
xsr abi_arg0, excsave1
/* init_arch kick-starts the linux kernel */
call4 init_arch
call4 start_kernel
abi_call init_arch
abi_call start_kernel
should_never_return:
j should_never_return
......@@ -297,10 +299,10 @@ should_never_return:
s32i a3, a2, 0
memw
movi a6, 0
wsr a6, excsave1
movi abi_arg0, 0
wsr abi_arg0, excsave1
call4 secondary_start_kernel
abi_call secondary_start_kernel
j should_never_return
#endif /* CONFIG_SMP */
......
......@@ -17,11 +17,16 @@
/*
* Entry condition:
*
* a2: a0 of the caller
* a2: a0 of the caller in windowed ABI
* a10: a0 of the caller in call0 ABI
*
* In call0 ABI the function _mcount is called with the special ABI:
* its argument is in a10 and all the usual argument registers (a2 - a7)
* must be preserved in addition to callee-saved a12 - a15.
*/
ENTRY(_mcount)
#if defined(__XTENSA_WINDOWED_ABI__)
abi_entry_default
movi a4, ftrace_trace_function
......@@ -42,7 +47,36 @@ ENTRY(_mcount)
callx4 a4
abi_ret_default
#elif defined(__XTENSA_CALL0_ABI__)
abi_entry_default
movi a9, ftrace_trace_function
l32i a9, a9, 0
movi a11, ftrace_stub
bne a9, a11, 1f
abi_ret_default
1: abi_entry(28)
s32i a0, sp, 0
s32i a2, sp, 4
s32i a3, sp, 8
s32i a4, sp, 12
s32i a5, sp, 16
s32i a6, sp, 20
s32i a7, sp, 24
addi a2, a10, -MCOUNT_INSN_SIZE
callx0 a9
l32i a0, sp, 0
l32i a2, sp, 4
l32i a3, sp, 8
l32i a4, sp, 12
l32i a5, sp, 16
l32i a6, sp, 20
l32i a7, sp, 24
abi_ret(28)
#else
#error Unsupported Xtensa ABI
#endif
ENDPROC(_mcount)
ENTRY(ftrace_stub)
......
......@@ -211,11 +211,18 @@ int copy_thread(unsigned long clone_flags, unsigned long usp_thread_fn,
struct thread_info *ti;
#endif
#if defined(__XTENSA_WINDOWED_ABI__)
/* Create a call4 dummy-frame: a0 = 0, a1 = childregs. */
SPILL_SLOT(childregs, 1) = (unsigned long)childregs;
SPILL_SLOT(childregs, 0) = 0;
p->thread.sp = (unsigned long)childregs;
#elif defined(__XTENSA_CALL0_ABI__)
/* Reserve 16 bytes for the _switch_to stack frame. */
p->thread.sp = (unsigned long)childregs - 16;
#else
#error Unsupported Xtensa ABI
#endif
if (!(p->flags & (PF_KTHREAD | PF_IO_WORKER))) {
struct pt_regs *regs = current_pt_regs();
......@@ -272,11 +279,25 @@ int copy_thread(unsigned long clone_flags, unsigned long usp_thread_fn,
p->thread.ra = MAKE_RA_FOR_CALL(
(unsigned long)ret_from_kernel_thread, 1);
/* pass parameters to ret_from_kernel_thread:
* a2 = thread_fn, a3 = thread_fn arg
/* pass parameters to ret_from_kernel_thread: */
#if defined(__XTENSA_WINDOWED_ABI__)
/*
* a2 = thread_fn, a3 = thread_fn arg.
* Window underflow will load registers from the
* spill slots on the stack on return from _switch_to.
*/
SPILL_SLOT(childregs, 3) = thread_fn_arg;
SPILL_SLOT(childregs, 2) = usp_thread_fn;
SPILL_SLOT(childregs, 3) = thread_fn_arg;
#elif defined(__XTENSA_CALL0_ABI__)
/*
* a12 = thread_fn, a13 = thread_fn arg.
* _switch_to epilogue will load registers from the stack.
*/
((unsigned long *)p->thread.sp)[0] = usp_thread_fn;
((unsigned long *)p->thread.sp)[1] = thread_fn_arg;
#else
#error Unsupported Xtensa ABI
#endif
/* Childregs are only used when we're going to userspace
* in which case start_thread will set them up.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment