/* Copyright 2013-2014 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * 	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef __STACKFRAME_H
#define __STACKFRAME_H

#include <mem-map.h>

#define STACK_ENTRY_OPAL_API	0	/* OPAL call */
#define STACK_ENTRY_HMI		0x0e60	/* Hypervisor maintenance */
#define STACK_ENTRY_RESET	0x0100	/* System reset */
#define STACK_ENTRY_SOFTPATCH	0x1500	/* Soft patch (denorm emulation) */

/* Safety/ABI gap at top of stack */
#define STACK_TOP_GAP		0x100

/* Remaining stack space (gap included) */
#define NORMAL_STACK_SIZE	(STACK_SIZE/2)

/* Emergency (re-entry) stack size */
#define EMERGENCY_STACK_SIZE	(STACK_SIZE/2)

/* Offset to get to normal CPU stacks */
#define CPU_STACKS_OFFSET	(CPU_STACKS_BASE + \
				 NORMAL_STACK_SIZE - STACK_TOP_GAP)

/* Offset to get to emergency CPU stacks */
#define EMERGENCY_CPU_STACKS_OFFSET	(CPU_STACKS_BASE + NORMAL_STACK_SIZE + \
				 EMERGENCY_STACK_SIZE - STACK_TOP_GAP)

/* Gap below the stack. If our stack checker sees the stack below that
 * gap, it will flag a stack overflow
 */
#define STACK_SAFETY_GAP	512

/* Warning threshold, if stack goes below that on mcount, print a
 * warning.
 */
#define STACK_WARNING_GAP	2048

#define STACK_CHECK_GUARD_BASE	0xdeadf00dbaad300

#ifndef __ASSEMBLY__

#include <stdint.h>
#include <opal-api.h>

/* This is the struct used to save GPRs etc.. on OPAL entry
 * and from some exceptions. It is not always entirely populated
 * depending on the entry type
 */
struct stack_frame {
	/* Standard 112-byte stack frame header (the minimum size required,
	 * using an 8-doubleword param save area). The callee (in C) may use
	 * lrsave; we declare these here so we don't get our own save area
	 * overwritten */
	uint64_t	backchain;
	uint64_t	crsave;
	uint64_t	lrsave;
	uint64_t	compiler_dw;
	uint64_t	linker_dw;
	uint64_t	tocsave;
	uint64_t	paramsave[8];

	/* Space for stack-local vars used by asm. At present we only use
	 * one doubleword. */
	uint64_t	locals[1];

	/* Entry type */
	uint64_t	type;

	/* GPR save area
	 *
	 * We don't necessarily save everything in here
	 */
	uint64_t	gpr[32];

	/* Other SPR saved
	 *
	 * Only for some exceptions.
	 */
	uint32_t	cr;
	uint32_t	xer;
	uint32_t	dsisr;
	uint64_t	ctr;
	uint64_t	lr;
	uint64_t	pc;
	uint64_t	msr;
	uint64_t	cfar;
	uint64_t	srr0;
	uint64_t	srr1;
	uint64_t	hsrr0;
	uint64_t	hsrr1;
	uint64_t	dar;
} __attribute__((aligned(16)));

/* Backtrace */
struct bt_entry {
	unsigned long	sp;
	unsigned long	pc;
};

/* Boot stack top */
extern void *boot_stack_top;

/* Create a backtrace */
void ___backtrace(struct bt_entry *entries, unsigned int *count,
				unsigned long r1,
				unsigned long *token, unsigned long *r1_caller);
static inline void __backtrace(struct bt_entry *entries, unsigned int *count)
{
	unsigned long token, r1_caller;

	___backtrace(entries, count,
			(unsigned long)__builtin_frame_address(0),
			&token, &r1_caller);
}

/* Convert a backtrace to ASCII */
extern void ___print_backtrace(unsigned int pir, struct bt_entry *entries,
			      unsigned int count, unsigned long token,
			      unsigned long r1_caller, char *out_buf,
			      unsigned int *len, bool symbols);

static inline void __print_backtrace(unsigned int pir, struct bt_entry *entries,
			      unsigned int count, char *out_buf,
			      unsigned int *len, bool symbols)
{
	___print_backtrace(pir, entries, count, OPAL_LAST + 1, 0, out_buf, len, symbols);
}

/* For use by debug code, create and print backtrace, uses a static buffer */
extern void backtrace(void);

#ifdef STACK_CHECK_ENABLED
extern void check_stacks(void);
#else
static inline void check_stacks(void) { }
#endif

#endif /* __ASSEMBLY__ */
#endif /* __STACKFRAME_H */

