/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* bos720 src/bos/kernel/sys/pseg.h 1.13.4.5                              */
/*                                                                        */
/* Licensed Materials - Property of IBM                                   */
/*                                                                        */
/* COPYRIGHT International Business Machines Corp. 1988,2014              */
/* All Rights Reserved                                                    */
/*                                                                        */
/* US Government Users Restricted Rights - Use, duplication or            */
/* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.      */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/* @(#)42	1.13.4.5  src/bos/kernel/sys/pseg.h, sysproc, bos720, 1445A_720 9/24/14 17:40:18 */
/*
 *   COMPONENT_NAME: SYSPROC
 *
 *   FUNCTIONS: 
 *
 *   ORIGINS: 27, 83
 *
 */
/*
 * LEVEL 1,  5 Years Bull Confidential Information
 */

#ifndef	_H_PSEG
#define	_H_PSEG

/*
 *	For AIX, most of the regions of a 32-bit process are packaged into
 *	a single virtual memory segment, called the process-private segment.
 *	This arrangement is convenient, and avoids wasting lots of address
 *	space giving each region a separate segment.  Other machines might
 *	not want to use this scheme.  Nothing fundamental depends on it.
 */

#include <sys/param.h>
#include <sys/user.h>
#include <sys/seg.h>

/*      The format of the process private segment (PRIVSEG) for
	a 32-bit process is as follows:

		 _______________________ _              ===
PRIVSEG	     -> | user r/w data and text| |                |
		|  u_dsize <= u_dmax	| |     	   |
		 -----------------------  |     	   |
		|	unused		| |     	   |
		 -----------------------  | U_STKDATA_SIZE |
		| stack for user mode	| |     	   |
		|  u_ssize <= u_smax	| |     	   |
USTACK_TOP   ->  -----------------------  |     	   |
ERRNO	     ->	| standard syscall errno| |     	   | U_REGION_SIZE
		 -----------------------  |     	   |
		| pointer to std errno  | |     	   |
		 ----------------------- _ <-USRSTACK      |
                | unused space for >4K  | |                |
		| page size alignment   | | U_PSIZE_PAD    |
		 ======================= -              ===
		| standard kernel stack |       --	   |
U_BLOCK	     ->  -----------------------  --      | one    |
		| standard uthread block|   |	  | pinned |
		 -----------------------    |	  | page   | K_REGION_SIZE
		| user structure	|   |	--	   |
		| swappable proc info	|   | ublock	   |
		 -----------------------    |	  	   |
		|   Future Stack        |   |              |
		 -----------------------    |	  	   |
		|      AMR Stack        |   |	  	   |
		 -----------------------    |	  	   |
		| 64-bit user (unused)  |   |              |
               	 -----------------------  -- <-KLDRHEAPORG |
		| loader heap           |   |              |
		| (loader entries)      |   | KLDRHEAPSIZE |
SEGSIZE	     ->  -----------------------  --    	===

  	The process private segment (PRIVSEG) for 64-bit processes
	contains nothing but kernel data.  The
        segment is not mapped into the user address space.  ERRNO64
	is in the user stack segment.
							      U_REGION_SIZE64=0
PRIVORG		 _______________________  -- <-SNODEORG64=KHEAPORG64
0	     ->	|     snode heap        |   | SNODESIZE64  \ KHEAPSIZE64
		 -----------------------  -- <-UNODEORG64  |  |
		|     unode heap        |   | UNODESIZE64  |  |
		 -----------------------  -- <-KHEAPEND64--   |   
		| standard kernel stack |	_	      |
U_BLOCK	     ->  -----------------------  --	  | one       |
		| standard uthread block|   |	  | pinned    |
		 -----------------------    |	  | page      | K_REGION_SIZE64
		| user structure	|   |	--	      | (entire segment)
		| swappable proc info	|   | ublock	      |
		 -----------------------    |  		      |
		|   Future stack        |   |  		      |
		 -----------------------    |  		      |
		|      AMR stack        |   |  		      |
		 -----------------------    |--		      |
		| 64-bit user struct    |   |  | pinned	      |
		 ----------------------- ---|--<- KLDRHEAPORG |
		| loader heap or unused |      | KLDRHEAPSIZE |
SEGSIZE	     ->  -----------------------     --		   ---

 *  The addresses of the u-block and of the standard and 64-bit errno
 *  are exported by ipl.exp  All code should use these values rather
 *  than other constants.  Everything defined here is derived from them.
 */

#ifdef _KERNSYS
#define ERRNO		(SEGOFFSET(&_errno))
#define ERRNO64		(SEGOFFSET(&_errno64))
#else
extern int errno64;
#define ERRNO		(SEGOFFSET(&errno))
#define ERRNO64		(SEGOFFSET(&errno64))
#endif /* _KERNSYS */

#define U_BLOCK		(SEGOFFSET(&__ublock))

/* To support multiple page sizes for a 32-bit process's private
 * segment, the boundary between the user and kernel accessible parts
 * of a process private segment must be aligned to the system's
 * largest supported pageable page size (MAXPGPSIZE).  Thus, in order to
 * support larger than 4K alignments, the size of the user accessible
 * part of a 32-bit process private segment must be increased.
 *
 * However, to maintain backward compatibility with previous AIX
 * versions, the location of a process's errno and errnop variables
 * can't be moved.  So, the stack and data limits stay the same for a
 * 32-bit process (U_STKDATA_SIZE).  But, in reality, the size of the
 * user accessible part of the process private segment
 * (U_REGION_SIZE) is padded to a 64K page alignment with
 * U_PSIZE_PAD.  Thus, there is a
 * small window of memory that a process could access with stray
 * references beyond errnop.
 *
 */
#define U_STKDATA_SIZE	(ERRNO + 2*sizeof(int))
#define U_REGION_SIZE   ((U_STKDATA_SIZE + MAXPGPSIZE - 1) & ~(MAXPGPSIZE-1))
#define U_PSIZE_PAD     (U_REGION_SIZE - U_STKDATA_SIZE)
#define K_REGION_SIZE	(SEGSIZE - U_REGION_SIZE)

#define U_REGION_SIZE64	(0)

#define K_REGION_SIZE64	(SEGSIZE - U_REGION_SIZE64)

/*  U_ARGS_SIZE64:
 *
 *  execargs max buffer size for 64-bit applications.
 *
 *  - ARG_MAX (<sys/limits.h>) and NCARGS (<sys/param.h>) dictate
 *    the statically compiled in max size which must be less then this.
 *
 *  - U_ARGS_ORG64 assumes that errno64 is placed near the end of the
 *    4Mb buffer, contained within it. 
 *    
 *    errno64 is defined in ipl64.imp for 64-bit kernel.
 *
 */

#define U_ARGS_SIZE64	NCARGS_MAX

#define U_ARGS_ORG64    ( (unsigned long long)&errno64 & \
		         ~((unsigned long long)(U_ARGS_SIZE64-1)) )

/*
 *  The following defines are calculated from the preceeding values.
 * 
 *  USRSTACK is for 32-bit applications.
 *
 *  KLDRHEAPORG32, KLDRHEAPORG64 and KLDRHEAPSIZE define the layout of the
 *  memory where the loader heap will be.  This memory is used for loader
 *  entries for the shlap and all 32-bit processes.  For 64-bit processes
 *  other than the shlap, this memory is reserved for use by the loader.
 * 
 *  KHEAPORG64, KHEAPSIZE64 and KHEAPEND64 refer to the additional kernel
 *  storage used to hold structures for a 64-bit process, consisting of address
 *  space structures (segnodes and uadnodes).
 */

#define USRSTACK	(PRIVORG_LO + U_STKDATA_SIZE)

#ifdef _POWER
/* Start of loader heap in process-private segment for 32-bit processes.
 */
#define KLDRHEAPORG32	((uintptr_t)&U64+PAGESIZE)

/* Start of loader heap in process-private segment for shlap.
 */
#define KLDRHEAPORG64	(((uintptr_t)(&__ublock+1) \
			  + (MAXPGPSIZE-1))&~(MAXPGPSIZE-1))
#define KLDRHEAPSIZE(s_addr) (SEGSIZE - SEGOFFSET((s_addr)))

#define KHEAPSIZE64     ((ulong)((ulong)U_REGION_SIZE -  \
				 (ulong)U_REGION_SIZE64) & 0x0FFFFFFFUL)
#define KHEAPORG64      (PRIVORG + U_REGION_SIZE64)
#define KHEAPEND64      (KHEAPORG64 + KHEAPSIZE64)

/*
 *  For 64-bit apps, PRIVSEG is not mapped into the user address space.
 *  U_REGION_SIZE64 is 0, and loader entries are
 *  allocated from segments managed by the loader.
 *
 */

#define	LDRHDRSIZE64	0

#endif /* _POWER */

#define SNODEORG64	(KHEAPORG64 + LDRHDRSIZE64)
/* Round SNODESIZE64 down to a multiple of the page size. */
#define SNODESIZE64     ((KHEAPSIZE64-LDRHDRSIZE64)/2 & ~((ulong)(MAXPGPSIZE-1)))
#define UNODEORG64      (SNODEORG64 + SNODESIZE64)
#define UNODESIZE64     (SNODESIZE64)

/*
 *  The following defines are offsets in a process private segment
 *  to the appropriate data area. They can be used in pointer assignment
 *  in addressing portions of the process private segment
 */
#define USTACK_TOP	ERRNO
#define USTACK_TOP64	ERRNO64

/*
 * Any change to the STACKTOUCH* #defines should also be reflected in
 * param.m4 as well.
 */
#define STACKTOUCH	(2 * 1024)		/* don't touch next segment */
#define STACKTOUCH_U    STACKTOUCH		/* touch above */
#define STACKTOUCH_M    -STACKTOUCH		/* touch middle */
#define STACKTOUCH_L    -(6 * 1024)		/* touch below */
#define STACKTOUCH_LL   -(8 * 1024)		/* touch far below */
#define KSTACKBLOCK	(96 * 1024)		/* size of uthr and kstack  */
						/* actual kstack bytes	    */
#define KSTACKSIZE	(KSTACKBLOCK - sizeof(struct uthread))

/*   
 * mininum initial stack frame is STKMIN. this is machine dependent.
 */
#ifdef __64BIT__
#define STKMIN          56*2
#define STKMINALIGN     112
#else
#define STKMIN          56
#define STKMINALIGN     64
#endif /* __64BIT__ */

#ifdef _KERNEL
#define STKMIN64 	112
#define STKMINALIGN64 	112
#endif /* _KERNEL */

#ifdef _KERNSYS

/*
 * The user stack address of the 64bit process.
 *
 *   STKTOP64 is the top of the stack + 1.
 *
 *   STKFLOOR64 is the lowest address to which the stack
 *   can grow architecturally. The implementation may limit
 *   it to a higher address than this. 
 *
 *   MAXSTACK64 is the default size for how big we allow the stack
 *   to grow. The rlimit may be unlimited, or bigger, but this is
 *   how far we will actually let em go, unless the process defines
 *   its own maxstack.
 *
 *   HARDMAXSTK64 is the hard limit on the total stack that we will
 *   allow a 64-bit process to consume. This is a kernel-specific
 *   size.
 */

#ifdef _POWER
#define STKTOP64	((unsigned long long)(VM_MAXADDR + 1) << 32)
#define STKFLOOR64      (0x0F00000000000000ull)
#define MAXSTACK64      (SEGSIZE * 16ll)
#endif /* _POWER */
#define HARDMAXSTK64    v.v_hardstack

/*
 * The following describes layout of pm_heap segments, for multi-threaded
 * programs.  pm_heap segments contain uthread structures and kernel/frr/AMR 
 * stacks. Each segment is partitioned into zones for allocation of the 
 * structures.  The defines for these zones follow


0	 -----------------------  --+
	|        FRR stack      |   |
	 -----------------------    |
	|        AMR stack      |   |
	 -----------------------    |
	|        kernel stack   |   | uthkstk[0] (one PM ZONE)
	|			|   |
	 -----------------------    |
	|        uthread        |   |
	 =======================  --+
	|        FRR stack      |
	 ----------------------- 
	|        AMR stack      |
	 -----------------------  --+
	|        kernel stack   |   |
	|			|   | KSTACKBLOCK
	 -----------------------    |
	|        uthread        |   |
	 =======================  --+
	|           .           |
	|           .           |
	|           .           |
	|           .           |
	|           .           |
	 =======================  --+
	|        FRR stack      |   |
	 -----------------------    |
	|        AMR stack      |   |
	 -----------------------    | uthkstk[THREADS_PER_SEG-1]
	|        kernel stack   |   |
	|			|   | 
	 -----------------------    |
	|        uthread        |   |
	 =======================  --+
	|                       |
	|    uthread pm_heap	|
	|                       |
	 -----------------------	
	|			|
	|        free space     |
	|    			|
SEGSIZE	 -----------------------	

*/

#define THREADS_PER_SEG 2048		/* must be a multiple of 128 */
#define TS_PAD1 \
	   (PAGESIZE-((THREADS_PER_SEG*(sizeof(struct mstext)))&(PAGESIZE-1)))

/*
 * The kernel stack layout.
 *
 * Note: The kernel stacks for kprocs.
 *       have a separate segment, so they do not get the gratuitous pinned 
 *       stack portion. Since their stacks are in different segment, the stack
 *       space in kthreadseg (below &uth) is unused.
 */
struct uthkstk {
        char frrstk[FRRSTACKSIZE];   /* FRR stack for the thread */
        char amrstack[AMRSTACKSIZE];
        char kstk[KSTACKSIZE]; 	/* portion of kstack is pinned too. */
       	struct uthread  uth;	/* uth pinned */
};

struct threadseg {

	struct uthkstk	utzone[THREADS_PER_SEG];
	struct pm_heap uthread_heap;

	/* There is more space available in a thread segment.
	 */
};

/*
 * Get the kstack and amrstack address for this thread...
 */
#define UT_KSTACK_ADDR(_ut) ((void *)(_ut)) 

/*
 * Get the recovery stack address for a specified uthread.
 * Note this macro only works for uthreads in threadseg segments.
 */
#define UT_FRRSTACK_ADDR(_ut) \
        ((char *)(((char *)(_ut)) - offsetof(struct uthkstk, uth) + \
         offsetof(struct uthkstk, frrstk) + FRRSTACKSIZE))  

/*
 * Get the AMR stack address
 */
#define UT_AMRSTACK_ADDR(_ut)	\
        ((char *)(((char *)(_ut)) - offsetof(struct uthkstk, uth) + \
         offsetof(struct uthkstk, amrstack) + AMRSTACKSIZE))  

/* 
 * Kproc's uthread blocks are maintained in KTHREADSEG as laid
 * out above in threadseg. Kprocs can have only one KTHREADSEG segment. 
 * Kprocs in have their stack segment same as that of the 64bit
 * user processes. This layout is defined in structure kp64_stackseg below. 
 * A region of KSTACKBLOCK size at the high-end of the stack segment size is 
 * reserved for future use. 
 * Initial stack segment layout for kproc threads. The initial 
 * thread gets major piece of the stack segment to allow the ability to set 
 * stack rlimit. The initial thread can even grow the stack beyond one segment.
 */
#define KP64_UTHR0_STKSZ_MAX (ulong)(SEGSIZE - ((THREADS_PER_SEG)*KSTACKBLOCK))

struct kp64_stackseg {
	char kp64_uthr0_kstack[KP64_UTHR0_STKSZ_MAX];	/* primary thread */
	char kstack_zone[THREADS_PER_SEG-1][KSTACKBLOCK];/* other threads */
	char reserved[KSTACKBLOCK];
};


/* 
 * Get the kstack address for the initial thread of a kproc
 */
#define KP64_STACK_ORG	   ((STKTOP64-1) & ~(SEGSIZE-1))
#define KP64_UTHR0_KSTACK  ((void *)					     \
				&((struct kp64_stackseg *)KP64_STACK_ORG)->  \
				kp64_uthr0_kstack[KP64_UTHR0_STKSZ_MAX])

/* 
 * Get the index of this uthread into utzone[] in threadseg 
 */
#define KPUT_INDEX(_ut)      ((SEGOFFSET(_ut) -                              \
                            SEGOFFSET(&((((struct threadseg *)0)->	     \
							utzone[0]).uth)))     \
                            			/sizeof(struct uthkstk))

/*
 * Get the kstack address for this kproc thread...
 */
#define KP64_KSTACK_ADDR(_ut)  ((void *)				      \
			          &((struct kp64_stackseg *)KP64_STACK_ORG)-> \
				kstack_zone[KPUT_INDEX(_ut)][KSTACKBLOCK]) 

#endif /* _KERNSYS */

#endif	/* _H_PSEG */