#ifndef __L4__KERNEL_IFACE_PAGE_H__
#define __L4__KERNEL_IFACE_PAGE_H__
#include <l4/types.h>
#include __L4_INC_ARCH(syscalls.h)
#if defined(L4_64BIT)
# define __PAD32	__pad32:32
# define __PLUS32	+ 32
#else
# define __PAD32	:0
# define __PLUS32
#endif
typedef union {
    L4_Word_t	raw;
    struct {
	L4_BITFIELD4( L4_Word_t,
	    __padding:16,
	    subid:8,
	    id:8,
	    __PAD32
	);
    } x;
} L4_KernelId_t;
typedef union {
    L4_Word_t	raw;
    struct {
	L4_BITFIELD4( L4_Word_t,
	    __padding:16,
	    subversion:8,
	    version:8,
	    __PAD32
	);
    } x;
} L4_ApiVersion_t;
typedef union {
    L4_Word_t	raw;
    struct {
	L4_BITFIELD3( L4_Word_t,
	    ee:2,
	    ww:2,
	    __padding:28 __PLUS32
	);
    } x;
} L4_ApiFlags_t;
typedef struct {
    L4_BITFIELD2( L4_Word_t,
	n:L4_BITS_PER_WORD / 2,
	MemDescPtr:L4_BITS_PER_WORD / 2
    );
} L4_MemoryInfo_t;
typedef struct {
    L4_Word_t		magic;
    L4_ApiVersion_t	ApiVersion;
    L4_ApiFlags_t	ApiFlags;
    L4_Word_t		KernelVerPtr;
    
    L4_Word_t		__padding10[17];
    L4_MemoryInfo_t	MemoryInfo;
    L4_Word_t		__padding58[2];
    
    struct {
	L4_Word_t	low;
	L4_Word_t	high;
    } MainMem;
    
    struct {
	L4_Word_t	low;
	L4_Word_t	high;
    } ReservedMem[2];
    
    struct {
	L4_Word_t	low;
	L4_Word_t	high;
    } DedicatedMem[5];
    
    L4_Word_t		__paddingA0[2];
    union {
	L4_Word_t	raw;
	struct {
	    L4_BITFIELD4( L4_Word_t,
		m:10,
		a:6,
		s:6,
		__padding:10 __PLUS32
	    );
	} X;
    } UtcbAreaInfo;
    union {
	L4_Word_t	raw;
	struct {
	    L4_BITFIELD2( L4_Word_t,
		s:6,
		__padding:26 __PLUS32
	    );
	} X;
    } KipAreaInfo;
    
    L4_Word_t		__paddingB0[2];
    L4_Word_t		BootInfo;
    L4_Word_t		ProcDescPtr;
    
    union {
	L4_Word_t	raw;
	struct {
	    L4_BITFIELD3( L4_Word_t,
		ReadPrecision:16,
		SchedulePrecision:16,
		__PAD32
	    );
	} X;
    } ClockInfo;
    union {
	L4_Word_t	raw;
	struct {
	    L4_BITFIELD4( L4_Word_t,
		t:8,
		SystemBase:12,
		UserBase:12,
		__PAD32
	    );
	} X;
    } ThreadInfo;
    union {
	L4_Word_t	raw;
	struct {
	    L4_BITFIELD3( L4_Word_t,
		rwx:3,
		__padding:7,
		page_size_mask:22 __PLUS32
	    );
	} X;
    } PageInfo;		
    union {
	L4_Word_t	raw;
	struct {
	    L4_BITFIELD3( L4_Word_t,
		processors:16,
		__pading:12 __PLUS32,
		s:4
	    );
	} X;
    } ProcessorInfo;
    
    L4_Word_t	SpaceControl;
    L4_Word_t	ThreadControl;
    L4_Word_t	ProcessorControl;
    L4_Word_t	MemoryControl;
    
    L4_Word_t	Ipc;
    L4_Word_t	Lipc;
    L4_Word_t	Unmap;
    L4_Word_t	ExchangeRegisters;
    
    L4_Word_t	SystemClock;
    L4_Word_t	ThreadSwitch;
    L4_Word_t	Schedule;
    L4_Word_t	__paddingF0;
    
    L4_Word_t	__padding100[4];
    
    L4_Word_t	ArchSyscall0;
    L4_Word_t	ArchSyscall1;
    L4_Word_t	ArchSyscall2;
    L4_Word_t	ArchSyscall3;
} L4_KernelInterfacePage_t;
typedef union {
    L4_Word_t	raw[4];
    struct {
	L4_Word_t	ExternalFreq;
	L4_Word_t	InternalFreq;
	L4_Word_t	__padding[2];
    } X;
} L4_ProcDesc_t;
typedef struct {
    L4_KernelId_t	KernelId;
    union {
	L4_Word_t	raw;
	struct {
	    L4_BITFIELD4( L4_Word_t,
		day:5,
		month:4,
		year:7,
		__padding:16 __PLUS32
	    );
	} X;
    } KernelGenDate;
    union {
	L4_Word_t	raw;
	struct {
	    L4_BITFIELD4( L4_Word_t,
		subsubver:16,
		subver:8,
		ver:8,
		__PAD32
	    );
	} X;
    } KernelVer;
    L4_Word_t	Supplier;
    char	VersionString[0];
} L4_KernelDesc_t;
#ifndef L4_MAGIC
#if defined(L4_BIG_ENDIAN)
# define L4_MAGIC	(('L' << 24) + ('4' << 16) + (230 << 8) + 'K')
#else
# define L4_MAGIC	(('K' << 24) + (230 << 16) + ('4' << 8) + 'L')
#endif
#endif 
#define L4_APIVERSION_2		(0x02)
#define L4_APIVERSION_4		(0x04)
#define L4_APIVERSION_X0	(0x83)
#define L4_APIVERSION_X1	(0x83)
#define L4_APIVERSION_X2	(0x84)
#define L4_APISUBVERSION_X0	(0x80)
#define L4_APISUBVERSION_X1	(0x81)
#define L4_APISUBVERSION_X2	(0x82)
#define L4_APIFLAG_LE		(0x00)
#define L4_APIFLAG_BE		(0x01)
#define L4_APIFLAG_32BIT	(0x00)
#define L4_APIFLAG_64BIT	(0x01)
#define L4_KID_L4_486		((0 << 16) + 1)
#define L4_KID_L4_PENTIUM	((0 << 16) + 2)
#define L4_KID_L4_X86		((0 << 16) + 3)
#define L4_KID_L4_MIPS		((1 << 16) + 1)
#define L4_KID_L4_ALPHA		((2 << 16) + 1)
#define L4_KID_FIASCO		((3 << 16) + 1)
#define L4_KID_L4KA_X86		((4 << 16) + 1)
#define L4_KID_L4KA_ARM		((4 << 16) + 2)
#if defined(L4_BIG_ENDIAN)
# define L4_SUPL_GMD	(('G' << 24) + ('M' << 16) + ('D' << 8) + ' ')
# define L4_SUPL_IBM	(('I' << 24) + ('B' << 16) + ('M' << 8) + ' ')
# define L4_SUPL_UNSW	(('U' << 24) + ('N' << 16) + ('S' << 8) + 'W')
# define L4_SUPL_UKA	(('U' << 24) + ('K' << 16) + ('a' << 8) + ' ')
#else
# define L4_SUPL_GMD	((' ' << 24) + ('D' << 16) + ('M' << 8) + 'G')
# define L4_SUPL_IBM	((' ' << 24) + ('M' << 16) + ('B' << 8) + 'I')
# define L4_SUPL_UNSW	(('W' << 24) + ('S' << 16) + ('N' << 8) + 'U')
# define L4_SUPL_UKA	((' ' << 24) + ('a' << 16) + ('K' << 8) + 'U')
#endif
L4_INLINE void * L4_GetKernelInterface (void)
{
    L4_ApiVersion_t version;
    L4_ApiFlags_t flags;
    L4_KernelId_t kernel_id;
    return L4_KernelInterface (&version.raw, &flags.raw, &kernel_id.raw);
}
#if defined(__cplusplus)
L4_INLINE void * L4_KernelInterface (void)
{
    return L4_GetKernelInterface ();
}
#endif
L4_INLINE L4_Word_t L4_ApiVersion (void)
{
    L4_ApiVersion_t version;
    L4_ApiFlags_t flags;
    L4_KernelId_t kernel_id;
    L4_KernelInterface (&version.raw, &flags.raw, &kernel_id.raw);
    return version.raw;
}
L4_INLINE L4_Word_t L4_ApiFlags (void)
{
    L4_ApiVersion_t version;
    L4_ApiFlags_t flags;
    L4_KernelId_t kernel_id;
    L4_KernelInterface (&version.raw, &flags.raw, &kernel_id.raw);
    return flags.raw;
}
L4_INLINE L4_Word_t L4_KernelId (void)
{
    L4_ApiVersion_t version;
    L4_ApiFlags_t flags;
    L4_KernelId_t kernel_id;
    L4_KernelInterface (&version.raw, &flags.raw, &kernel_id.raw);
    return kernel_id.raw;
}
L4_INLINE void L4_KernelGenDate (void * KernelInterface, L4_Word_t * year,
				 L4_Word_t * month, L4_Word_t * day)
{
    L4_KernelInterfacePage_t * kip;
    L4_Word_t gen;
    kip = (L4_KernelInterfacePage_t *) KernelInterface;
    gen = ((L4_Word_t*)((L4_Word_t) KernelInterface + kip->KernelVerPtr))[1];
    *year = ((gen >> 9) & 0x7f) + 2000;
    *month = ((gen >> 5) & 0x0f);
    *day = (gen & 0x1f);
}
L4_INLINE L4_Word_t L4_KernelVersion (void * KernelInterface)
{
    L4_KernelInterfacePage_t * kip;
    kip = (L4_KernelInterfacePage_t *) KernelInterface;
    return ((L4_Word_t*)((L4_Word_t) KernelInterface + kip->KernelVerPtr))[2];
}
L4_INLINE L4_Word_t L4_KernelSupplier (void * KernelInterface)
{
    L4_KernelInterfacePage_t * kip;
    kip = (L4_KernelInterfacePage_t *) KernelInterface;
    return ((L4_Word_t*)((L4_Word_t) KernelInterface + kip->KernelVerPtr))[3];
}
L4_INLINE L4_Word_t L4_NumProcessors (void * KernelInterface)
{
    L4_KernelInterfacePage_t * kip;
    kip = (L4_KernelInterfacePage_t *) KernelInterface;
    return kip->ProcessorInfo.X.processors + 1;
}
L4_INLINE L4_Word_t L4_NumMemoryDescriptors (void * KernelInterface)
{
    L4_KernelInterfacePage_t * kip;
    kip = (L4_KernelInterfacePage_t *) KernelInterface;
    return kip->MemoryInfo.n;
}
L4_INLINE L4_Word_t L4_PageSizeMask (void * KernelInterface)
{
    L4_KernelInterfacePage_t * kip;
    kip = (L4_KernelInterfacePage_t *) KernelInterface;
    return kip->PageInfo.X.page_size_mask << 10;
}
L4_INLINE L4_Word_t L4_PageRights (void * KernelInterface)
{
    L4_KernelInterfacePage_t * kip;
    kip = (L4_KernelInterfacePage_t *) KernelInterface;
    return kip->PageInfo.X.rwx;
}
L4_INLINE L4_Word_t L4_ThreadIdBits (void * KernelInterface)
{
    L4_KernelInterfacePage_t * kip;
    kip = (L4_KernelInterfacePage_t *) KernelInterface;
    return kip->ThreadInfo.X.t;
}
L4_INLINE L4_Word_t L4_ThreadIdSystemBase (void * KernelInterface)
{
    L4_KernelInterfacePage_t * kip;
    kip = (L4_KernelInterfacePage_t *) KernelInterface;
    return kip->ThreadInfo.X.SystemBase;
}
L4_INLINE L4_Word_t L4_ThreadIdUserBase (void * KernelInterface)
{
    L4_KernelInterfacePage_t * kip;
    kip = (L4_KernelInterfacePage_t *) KernelInterface;
    return kip->ThreadInfo.X.UserBase;
}
L4_INLINE L4_Word_t L4_ReadPrecision (void * KernelInterface)
{
    L4_KernelInterfacePage_t * kip;
    kip = (L4_KernelInterfacePage_t *) KernelInterface;
    return kip->ClockInfo.X.ReadPrecision;
}
L4_INLINE L4_Word_t L4_SchedulePrecision (void * KernelInterface)
{
    L4_KernelInterfacePage_t * kip;
    kip = (L4_KernelInterfacePage_t *) KernelInterface;
    return kip->ClockInfo.X.SchedulePrecision;
}
L4_INLINE L4_Word_t L4_UtcbAreaSizeLog2 (void * KernelInterface)
{
    L4_KernelInterfacePage_t * kip;
    kip = (L4_KernelInterfacePage_t *) KernelInterface;
    return kip->UtcbAreaInfo.X.s;
}
L4_INLINE L4_Word_t L4_UtcbAreaSize (void * KernelInterface)
{
    return 1UL << L4_UtcbAreaSizeLog2 (KernelInterface);
}
L4_INLINE L4_Word_t L4_UtcbAlignmentLog2 (void * KernelInterface)
{
    L4_KernelInterfacePage_t * kip;
    kip = (L4_KernelInterfacePage_t *) KernelInterface;
    return kip->UtcbAreaInfo.X.a;
}
L4_INLINE L4_Word_t L4_UtcbSize (void * KernelInterface)
{
    L4_KernelInterfacePage_t * kip;
    kip = (L4_KernelInterfacePage_t *) KernelInterface;
    return (1UL << kip->UtcbAreaInfo.X.a) * kip->UtcbAreaInfo.X.m;
}
L4_INLINE L4_Word_t L4_KipAreaSizeLog2 (void * KernelInterface)
{
    L4_KernelInterfacePage_t * kip;
    kip = (L4_KernelInterfacePage_t *) KernelInterface;
    return kip->KipAreaInfo.X.s;
}
L4_INLINE L4_Word_t L4_KipAreaSize (void * KernelInterface)
{
    return 1UL << L4_KipAreaSizeLog2 (KernelInterface);
}
L4_INLINE L4_Word_t L4_BootInfo (void * KernelInterface)
{
    L4_KernelInterfacePage_t * kip;
    kip = (L4_KernelInterfacePage_t *) KernelInterface;
    return kip->BootInfo;
}
L4_INLINE char * L4_KernelVersionString (void * KernelInterface)
{
    L4_KernelInterfacePage_t * kip;
    kip = (L4_KernelInterfacePage_t *) KernelInterface;
    return (char *) ((L4_Word_t) KernelInterface + kip->KernelVerPtr +
		     sizeof (L4_Word_t) * 4);
}
L4_INLINE char * L4_Feature (void * KernelInterface, L4_Word_t num)
{
    char * str = L4_KernelVersionString (KernelInterface);
    do {
	while (*str++ != 0) {}
	if (*str == 0)
	    return (char *) 0;
    } while (num--);
    return str;
}
typedef union {
    L4_Word_t	raw[2];
    struct {
	L4_BITFIELD5( L4_Word_t,
	    type	:4,
	    t		:4,
	    __padding1	:1,
	    v		:1,
	    low		:L4_BITS_PER_WORD - 10
	);
	L4_BITFIELD2( L4_Word_t,
	    __padding2	:10,
	    high	:L4_BITS_PER_WORD - 10
	);
    } x;
} L4_MemoryDesc_t;
#define L4_UndefinedMemoryType			(0x0)
#define L4_ConventionalMemoryType		(0x1)
#define L4_ReservedMemoryType			(0x2)
#define L4_DedicatedMemoryType			(0x3)
#define L4_SharedMemoryType			(0x4)
#define L4_BootLoaderSpecificMemoryType		(0xe)
#define L4_ArchitectureSpecificMemoryType	(0xf)
L4_INLINE L4_MemoryDesc_t * L4_MemoryDesc (void * KernelInterface,
					   L4_Word_t num)
{
    L4_KernelInterfacePage_t * kip;
    kip = (L4_KernelInterfacePage_t *) KernelInterface;
    if (num >= kip->MemoryInfo.n)
	return (L4_MemoryDesc_t *) 0;
    return (L4_MemoryDesc_t *)
	((L4_Word_t) kip + kip->MemoryInfo.MemDescPtr) + num;
}
L4_INLINE L4_Bool_t L4_IsMemoryDescVirtual (L4_MemoryDesc_t * m)
{
    return m->x.v;
}
L4_INLINE L4_Word_t L4_MemoryDescType (L4_MemoryDesc_t * m)
{
    return (m->x.type >= 0x0E) ? (m->x.type + (m->x.t << 4)) : (m->x.type);
}
L4_INLINE L4_Word_t L4_MemoryDescLow (L4_MemoryDesc_t * m)
{
    return m->x.low << 10;
}
L4_INLINE L4_Word_t L4_MemoryDescHigh (L4_MemoryDesc_t * m)
{
    return (m->x.high << 10) + 0x3ff;
}
#if defined(__cplusplus)
L4_INLINE L4_Bool_t L4_IsVirtual (L4_MemoryDesc_t * m)
{
    return L4_IsMemoryDescVirtual (m);
}
L4_INLINE L4_Word_t L4_Type (L4_MemoryDesc_t * m)
{
    return L4_MemoryDescType (m);
}
L4_INLINE L4_Word_t L4_Low (L4_MemoryDesc_t * m)
{
    return L4_MemoryDescLow (m);
}
L4_INLINE L4_Word_t L4_High (L4_MemoryDesc_t * m)
{
    return L4_MemoryDescHigh (m);
}
#endif 
L4_INLINE L4_ProcDesc_t * L4_ProcDesc (void * KernelInterface, L4_Word_t cpu)
{
    L4_KernelInterfacePage_t * kip;
    kip = (L4_KernelInterfacePage_t *) KernelInterface;
    if (cpu > kip->ProcessorInfo.X.processors)
	return (L4_ProcDesc_t *) 0;
    return (L4_ProcDesc_t *)
	((L4_Word_t)kip + kip->ProcDescPtr + 
	 ((1 << kip->ProcessorInfo.X.s) * cpu));
}
L4_INLINE L4_Word_t L4_ProcDescExternalFreq (L4_ProcDesc_t * p)
{
    return p->X.ExternalFreq;
}
L4_INLINE L4_Word_t L4_ProcDescInternalFreq (L4_ProcDesc_t * p)
{
    return p->X.InternalFreq;
}
#if defined(__cplusplus)
L4_INLINE L4_Word_t L4_ExternalFreq (L4_ProcDesc_t * p)
{
    return L4_ProcDescExternalFreq (p);
}
L4_INLINE L4_Word_t L4_InternalFreq (L4_ProcDesc_t * p)
{
    return L4_ProcDescInternalFreq (p);
}
#endif 
#undef __PAD32
#undef __PLUS32
#endif