#ifndef COMPILER_H
#define COMPILER_H

/*
 * Doxygen can't cope with some of the more esoteric areas of C, so we
 * make its life simpler.
 *
 */
#ifdef DOXYGEN
#define __attribute__(x)
#endif

/** @file
 *
 * Global compiler definitions.
 *
 * This file is implicitly included by every @c .c file in Etherboot.
 * It defines global macros such as DBG().
 *
 * We arrange for each object to export the symbol @c obj_OBJECT
 * (where @c OBJECT is the object name, e.g. @c rtl8139) as a global
 * symbol, so that the linker can drag in selected object files from
 * the library using <tt> -u obj_OBJECT </tt>.
 *
 */

/* Force visibility of all symbols to "hidden", i.e. inform gcc that
 * all symbol references resolve strictly within our final binary.
 * This avoids unnecessary PLT/GOT entries on x86_64.
 *
 * This is a stronger claim than specifying "-fvisibility=hidden",
 * since it also affects symbols marked with "extern".
 */
#ifndef ASSEMBLY
#if __GNUC__ >= 4
#pragma GCC visibility push(hidden)
#endif
#endif /* ASSEMBLY */

#undef _S1
#undef _S2
#undef _C1
#undef _C2

/** Concatenate non-expanded arguments */
#define _C1( x, y ) x ## y
/** Concatenate expanded arguments */
#define _C2( x, y ) _C1 ( x, y )

/** Stringify non-expanded argument */
#define _S1( x ) #x
/** Stringify expanded argument */
#define _S2( x ) _S1 ( x )

/* Assembler section types */
#ifdef ASSEMBLY
#define PROGBITS _C2 ( ASM_TCHAR, progbits )
#define NOBITS _C2 ( ASM_TCHAR, nobits )
#else
#define PROGBITS_OPS _S2 ( ASM_TCHAR_OPS ) "progbits"
#define PROGBITS _S2 ( ASM_TCHAR ) "progbits"
#define NOBITS_OPS _S2 ( ASM_TCHAR_OPS ) "nobits"
#define NOBITS _S2 ( ASM_TCHAR ) "nobits"
#endif

/**
 * @defgroup symmacros Macros to provide or require explicit symbols
 * @{
 */

/**
 * Provide a symbol within this object file
 *
 * @v symbol		Symbol name
 */
#ifdef ASSEMBLY
#define PROVIDE_SYMBOL( symbol )				\
	.section ".provided", "a", NOBITS ;			\
	.hidden symbol ;					\
	.globl	symbol ;					\
	symbol: ;						\
	.previous
#else
#define PROVIDE_SYMBOL( symbol )				\
	char symbol[0]						\
	  __attribute__ (( section ( ".provided" ) ))
#endif

/**
 * Request a symbol
 *
 * @v symbol		Symbol name
 *
 * Request a symbol to be included within the link.  If the symbol
 * cannot be found, the link will succeed anyway.
 */
#ifdef ASSEMBLY
#define REQUEST_SYMBOL( symbol )				\
	.equ __request_ ## symbol, symbol
#else
#define REQUEST_SYMBOL( symbol )				\
	__asm__ ( ".equ __request_" #symbol ", " #symbol )
#endif

/**
 * Require a symbol
 *
 * @v symbol		Symbol name
 *
 * Require a symbol to be included within the link.  If the symbol
 * cannot be found, the link will fail.
 *
 * To use this macro within a file, you must also specify the file's
 * "requiring symbol" using the REQUIRING_SYMBOL() or
 * PROVIDE_REQUIRING_SYMBOL() macros.
 */
#ifdef ASSEMBLY
#define REQUIRE_SYMBOL( symbol )				\
	.reloc __requiring_symbol__, RELOC_TYPE_NONE, symbol
#else
#define REQUIRE_SYMBOL( symbol )				\
	__asm__ ( ".reloc __requiring_symbol__, "		\
		  _S2 ( RELOC_TYPE_NONE ) ", " #symbol )
#endif

/**
 * Specify the file's requiring symbol
 *
 * @v symbol		Symbol name
 *
 * REQUIRE_SYMBOL() works by defining a dummy relocation record
 * against a nominated "requiring symbol".  The presence of the
 * nominated requiring symbol will drag in all of the symbols
 * specified using REQUIRE_SYMBOL().
 */
#ifdef ASSEMBLY
#define REQUIRING_SYMBOL( symbol )				\
	.equ __requiring_symbol__, symbol
#else
#define REQUIRING_SYMBOL( symbol )				\
	__asm__ ( ".equ __requiring_symbol__, " #symbol )
#endif

/**
 * Provide a file's requiring symbol
 *
 * If the file contains no symbols that can be used as the requiring
 * symbol, you can provide a dummy one-byte-long symbol using
 * PROVIDE_REQUIRING_SYMBOL().
 */
#ifdef ASSEMBLY
#define PROVIDE_REQUIRING_SYMBOL()				\
	.section ".tbl.requiring_symbols", "a", PROGBITS ;	\
	__requiring_symbol__:	.byte 0 ;			\
	.size __requiring_symbol__, . - __requiring_symbol__ ;	\
	.previous
#else
#define PROVIDE_REQUIRING_SYMBOL()				\
	__asm__ ( ".section \".tbl.requiring_symbols\", "	\
		  "         \"a\", " PROGBITS "\n"		\
		  "__requiring_symbol__:\t.byte 0\n"		\
		  ".size __requiring_symbol__, "		\
		  "      . - __requiring_symbol__\n"		\
		  ".previous" )
#endif

/** @} */

/**
 * @defgroup objmacros Macros to provide or require explicit objects
 * @{
 */

#define PREFIX_OBJECT( _prefix ) _C2 ( _prefix, OBJECT )
#define OBJECT_SYMBOL PREFIX_OBJECT ( obj_ )

/** Always provide the symbol for the current object (defined by -DOBJECT) */
PROVIDE_SYMBOL ( OBJECT_SYMBOL );

/**
 * Request an object
 *
 * @v object		Object name
 *
 * Request an object to be included within the link.  If the object
 * cannot be found, the link will succeed anyway.
 */
#define REQUEST_OBJECT( object ) REQUEST_SYMBOL ( obj_ ## object )

/**
 * Require an object
 *
 * @v object		Object name
 *
 * Require an object to be included within the link.  If the object
 * cannot be found, the link will fail.
 *
 * To use this macro within a file, you must also specify the file's
 * "requiring symbol" using the REQUIRING_SYMBOL() or
 * PROVIDE_REQUIRING_SYMBOL() macros.
 */
#define REQUIRE_OBJECT( object ) REQUIRE_SYMBOL ( obj_ ## object )

/** @} */

/** Select file identifier for errno.h (if used) */
#define ERRFILE PREFIX_OBJECT ( ERRFILE_ )

#ifndef ASSEMBLY

/** Declare a function as weak (use *before* the definition)
 *
 * Due to a bug in at least GCC 4.4.4 and earlier, weak symbols may be
 * inlined if they have hidden visibility (see above for why hidden
 * visibility is used).  This results in the non-weak symbol never
 * being used, so explicitly mark the function as noinline to prevent
 * inlining.
 */
#define __weak		__attribute__ (( weak, noinline ))

#endif

/** @defgroup dbg Debugging infrastructure
 * @{
 */

/** @def DBG
 *
 * Print a debugging message.
 *
 * The debug level is set at build time by specifying the @c DEBUG=
 * parameter on the @c make command line.  For example, to enable
 * debugging for the PCI bus functions (in pci.c) in a @c .dsk image
 * for the @c rtl8139 card, you could use the command line
 *
 * @code
 *
 *   make bin/rtl8139.dsk DEBUG=pci
 *
 * @endcode
 *
 * This will enable the debugging statements (DBG()) in pci.c.  If
 * debugging is not enabled, DBG() statements will be ignored.
 *
 * You can enable debugging in several objects simultaneously by
 * separating them with commas, as in
 *
 * @code
 *
 *   make bin/rtl8139.dsk DEBUG=pci,buffer,heap
 *
 * @endcode
 *
 * You can increase the debugging level for an object by specifying it
 * with @c :N, where @c N is the level, as in
 *
 * @code
 *
 *   make bin/rtl8139.dsk DEBUG=pci,buffer:2,heap
 *
 * @endcode
 *
 * which would enable debugging for the PCI, buffer-handling and
 * heap-allocation code, with the buffer-handling code at level 2.
 *
 */

#ifndef DBGLVL_MAX
#define NDEBUG
#define DBGLVL_MAX 0
#endif

#ifndef DBGLVL_DFLT
#define DBGLVL_DFLT DBGLVL_MAX
#endif

#ifndef ASSEMBLY

/** printf() for debugging */
extern void __attribute__ (( format ( printf, 1, 2 ) ))
dbg_printf ( const char *fmt, ... );
extern void dbg_autocolourise ( unsigned long id );
extern void dbg_decolourise ( void );
extern void dbg_hex_dump_da ( unsigned long dispaddr,
			      const void *data, unsigned long len );
extern void dbg_md5_da ( unsigned long dispaddr,
			 const void *data, unsigned long len );
extern void dbg_pause ( void );
extern void dbg_more ( void );

/* Allow for selective disabling of enabled debug levels */
#define __debug_disable( object ) _C2 ( __debug_disable_, object )
char __debug_disable(OBJECT) = ( DBGLVL_MAX & ~DBGLVL_DFLT );
#define DBG_DISABLE_OBJECT( object, level ) do {		\
	extern char __debug_disable(object);			\
	__debug_disable(object) |= (level);			\
	} while ( 0 )
#define DBG_ENABLE_OBJECT( object, level ) do {			\
	extern char __debug_disable(object);			\
	__debug_disable(object) &= ~(level);			\
	} while ( 0 )
#if DBGLVL_MAX
#define DBGLVL ( DBGLVL_MAX & ~__debug_disable(OBJECT) )
#define DBG_DISABLE( level ) do {				\
	__debug_disable(OBJECT) |= ( (level) & DBGLVL_MAX );	\
	} while ( 0 )
#define DBG_ENABLE( level ) do {				\
	__debug_disable(OBJECT) &= ~( (level) & DBGLVL_MAX );	\
	} while ( 0 )
#else
#define DBGLVL 0
#define DBG_DISABLE( level ) do { } while ( 0 )
#define DBG_ENABLE( level ) do { } while ( 0 )
#endif

#define DBGLVL_LOG	1
#define DBG_LOG		( DBGLVL & DBGLVL_LOG )
#define DBGLVL_EXTRA	2
#define DBG_EXTRA	( DBGLVL & DBGLVL_EXTRA )
#define DBGLVL_PROFILE	4
#define DBG_PROFILE	( DBGLVL & DBGLVL_PROFILE )
#define DBGLVL_IO	8
#define DBG_IO		( DBGLVL & DBGLVL_IO )

/**
 * Print debugging message if we are at a certain debug level
 *
 * @v level		Debug level
 * @v ...		printf() argument list
 */
#define DBG_IF( level, ... ) do {				\
		if ( DBG_ ## level ) {				\
			dbg_printf ( __VA_ARGS__ );		\
		}						\
	} while ( 0 )

/**
 * Print a hex dump if we are at a certain debug level
 *
 * @v level		Debug level
 * @v dispaddr		Display address
 * @v data		Data to print
 * @v len		Length of data
 */
#define DBG_HDA_IF( level, dispaddr, data, len )  do {		\
		if ( DBG_ ## level ) {				\
			union {					\
				unsigned long ul;		\
				typeof ( dispaddr ) raw;	\
			} da;					\
			da.ul = 0;				\
			da.raw = dispaddr;			\
			dbg_hex_dump_da ( da.ul, data, len );	\
		}						\
	} while ( 0 )

/**
 * Print a hex dump if we are at a certain debug level
 *
 * @v level		Debug level
 * @v data		Data to print
 * @v len		Length of data
 */
#define DBG_HD_IF( level, data, len ) do {			\
		const void *_data = data;			\
		DBG_HDA_IF ( level, _data, _data, len );	\
	} while ( 0 )

/**
 * Print an MD5 checksum if we are at a certain debug level
 *
 * @v level		Debug level
 * @v dispaddr		Display address
 * @v data		Data to print
 * @v len		Length of data
 */
#define DBG_MD5A_IF( level, dispaddr, data, len )  do {		\
		if ( DBG_ ## level ) {				\
			union {					\
				unsigned long ul;		\
				typeof ( dispaddr ) raw;	\
			} da;					\
			da.ul = 0;				\
			da.raw = dispaddr;			\
			dbg_md5_da ( da.ul, data, len );	\
		}						\
	} while ( 0 )

/**
 * Print an MD5 checksum if we are at a certain debug level
 *
 * @v level		Debug level
 * @v data		Data to print
 * @v len		Length of data
 */
#define DBG_MD5_IF( level, data, len ) do {			\
		const void *_data = data;			\
		DBG_MD5A_IF ( level, _data, _data, len );	\
	} while ( 0 )

/**
 * Prompt for key press if we are at a certain debug level
 *
 * @v level		Debug level
 */
#define DBG_PAUSE_IF( level, ... ) do {				\
		if ( DBG_ ## level ) {				\
			dbg_pause();				\
		}						\
	} while ( 0 )

/**
 * Prompt for more output data if we are at a certain debug level
 *
 * @v level		Debug level
 */
#define DBG_MORE_IF( level, ... ) do {				\
		if ( DBG_ ## level ) {				\
			dbg_more();				\
		}						\
	} while ( 0 )

/**
 * Select colour for debug messages if we are at a certain debug level
 *
 * @v level		Debug level
 * @v id		Message stream ID
 */
#define DBG_AC_IF( level, id ) do {				\
		if ( DBG_ ## level ) {				\
			union {					\
				unsigned long ul;		\
				typeof ( id ) raw;		\
			} dbg_stream;				\
			dbg_stream.ul = 0;			\
			dbg_stream.raw = id;			\
			dbg_autocolourise ( dbg_stream.ul );	\
		}						\
	} while ( 0 )

/**
 * Revert colour for debug messages if we are at a certain debug level
 *
 * @v level		Debug level
 */
#define DBG_DC_IF( level ) do {					\
		if ( DBG_ ## level ) {				\
			dbg_decolourise();			\
		}						\
	} while ( 0 )

/* Autocolourising versions of the DBGxxx_IF() macros */

#define DBGC_IF( level, id, ... ) do {				\
		DBG_AC_IF ( level, id );			\
		DBG_IF ( level, __VA_ARGS__ );			\
		DBG_DC_IF ( level );				\
	} while ( 0 )

#define DBGC_HDA_IF( level, id, ... ) do {			\
		DBG_AC_IF ( level, id );			\
		DBG_HDA_IF ( level, __VA_ARGS__ );		\
		DBG_DC_IF ( level );				\
	} while ( 0 )

#define DBGC_HD_IF( level, id, ... ) do {			\
		DBG_AC_IF ( level, id );			\
		DBG_HD_IF ( level, __VA_ARGS__ );		\
		DBG_DC_IF ( level );				\
	} while ( 0 )

#define DBGC_MD5A_IF( level, id, ... ) do {			\
		DBG_AC_IF ( level, id );			\
		DBG_MD5A_IF ( level, __VA_ARGS__ );		\
		DBG_DC_IF ( level );				\
	} while ( 0 )

#define DBGC_MD5_IF( level, id, ... ) do {			\
		DBG_AC_IF ( level, id );			\
		DBG_MD5_IF ( level, __VA_ARGS__ );		\
		DBG_DC_IF ( level );				\
	} while ( 0 )

#define DBGC_PAUSE_IF( level, id ) do {				\
		DBG_AC_IF ( level, id );			\
		DBG_PAUSE_IF ( level );				\
		DBG_DC_IF ( level );				\
	} while ( 0 )

#define DBGC_MORE_IF( level, id ) do {				\
		DBG_AC_IF ( level, id );			\
		DBG_MORE_IF ( level );				\
		DBG_DC_IF ( level );				\
	} while ( 0 )

/* Versions of the DBGxxx_IF() macros that imply DBGxxx_IF( LOG, ... )*/

#define DBG( ... )		DBG_IF		( LOG, ##__VA_ARGS__ )
#define DBG_HDA( ... )		DBG_HDA_IF	( LOG, ##__VA_ARGS__ )
#define DBG_HD( ... )		DBG_HD_IF	( LOG, ##__VA_ARGS__ )
#define DBG_MD5A( ... )		DBG_MD5A_IF	( LOG, ##__VA_ARGS__ )
#define DBG_MD5( ... )		DBG_MD5_IF	( LOG, ##__VA_ARGS__ )
#define DBG_PAUSE( ... )	DBG_PAUSE_IF	( LOG, ##__VA_ARGS__ )
#define DBG_MORE( ... )		DBG_MORE_IF	( LOG, ##__VA_ARGS__ )
#define DBGC( ... )		DBGC_IF		( LOG, ##__VA_ARGS__ )
#define DBGC_HDA( ... )		DBGC_HDA_IF	( LOG, ##__VA_ARGS__ )
#define DBGC_HD( ... )		DBGC_HD_IF	( LOG, ##__VA_ARGS__ )
#define DBGC_MD5A( ... )	DBGC_MD5A_IF	( LOG, ##__VA_ARGS__ )
#define DBGC_MD5( ... )		DBGC_MD5_IF	( LOG, ##__VA_ARGS__ )
#define DBGC_PAUSE( ... )	DBGC_PAUSE_IF	( LOG, ##__VA_ARGS__ )
#define DBGC_MORE( ... )	DBGC_MORE_IF	( LOG, ##__VA_ARGS__ )

/* Versions of the DBGxxx_IF() macros that imply DBGxxx_IF( EXTRA, ... )*/

#define DBG2( ... )		DBG_IF		( EXTRA, ##__VA_ARGS__ )
#define DBG2_HDA( ... )		DBG_HDA_IF	( EXTRA, ##__VA_ARGS__ )
#define DBG2_HD( ... )		DBG_HD_IF	( EXTRA, ##__VA_ARGS__ )
#define DBG2_MD5A( ... )	DBG_MD5A_IF	( EXTRA, ##__VA_ARGS__ )
#define DBG2_MD5( ... )		DBG_MD5_IF	( EXTRA, ##__VA_ARGS__ )
#define DBG2_PAUSE( ... )	DBG_PAUSE_IF	( EXTRA, ##__VA_ARGS__ )
#define DBG2_MORE( ... )	DBG_MORE_IF	( EXTRA, ##__VA_ARGS__ )
#define DBGC2( ... )		DBGC_IF		( EXTRA, ##__VA_ARGS__ )
#define DBGC2_HDA( ... )	DBGC_HDA_IF	( EXTRA, ##__VA_ARGS__ )
#define DBGC2_HD( ... )		DBGC_HD_IF	( EXTRA, ##__VA_ARGS__ )
#define DBGC2_MD5A( ... )	DBGC_MD5A_IF	( EXTRA, ##__VA_ARGS__ )
#define DBGC2_MD5( ... )	DBGC_MD5_IF	( EXTRA, ##__VA_ARGS__ )
#define DBGC2_PAUSE( ... )	DBGC_PAUSE_IF	( EXTRA, ##__VA_ARGS__ )
#define DBGC2_MORE( ... )	DBGC_MORE_IF	( EXTRA, ##__VA_ARGS__ )

/* Versions of the DBGxxx_IF() macros that imply DBGxxx_IF( PROFILE, ... )*/

#define DBGP( ... )		DBG_IF		( PROFILE, ##__VA_ARGS__ )
#define DBGP_HDA( ... )		DBG_HDA_IF	( PROFILE, ##__VA_ARGS__ )
#define DBGP_HD( ... )		DBG_HD_IF	( PROFILE, ##__VA_ARGS__ )
#define DBGP_MD5A( ... )	DBG_MD5A_IF	( PROFILE, ##__VA_ARGS__ )
#define DBGP_MD5( ... )		DBG_MD5_IF	( PROFILE, ##__VA_ARGS__ )
#define DBGP_PAUSE( ... )	DBG_PAUSE_IF	( PROFILE, ##__VA_ARGS__ )
#define DBGP_MORE( ... )	DBG_MORE_IF	( PROFILE, ##__VA_ARGS__ )
#define DBGCP( ... )		DBGC_IF		( PROFILE, ##__VA_ARGS__ )
#define DBGCP_HDA( ... )	DBGC_HDA_IF	( PROFILE, ##__VA_ARGS__ )
#define DBGCP_HD( ... )		DBGC_HD_IF	( PROFILE, ##__VA_ARGS__ )
#define DBGCP_MD5A( ... )	DBGC_MD5A_IF	( PROFILE, ##__VA_ARGS__ )
#define DBGCP_MD5( ... )	DBGC_MD5_IF	( PROFILE, ##__VA_ARGS__ )
#define DBGCP_PAUSE( ... )	DBGC_PAUSE_IF	( PROFILE, ##__VA_ARGS__ )
#define DBGCP_MORE( ... )	DBGC_MORE_IF	( PROFILE, ##__VA_ARGS__ )

/* Versions of the DBGxxx_IF() macros that imply DBGxxx_IF( IO, ... )*/

#define DBGIO( ... )		DBG_IF		( IO, ##__VA_ARGS__ )
#define DBGIO_HDA( ... )	DBG_HDA_IF	( IO, ##__VA_ARGS__ )
#define DBGIO_HD( ... )		DBG_HD_IF	( IO, ##__VA_ARGS__ )
#define DBGIO_MD5A( ... )	DBG_MD5A_IF	( IO, ##__VA_ARGS__ )
#define DBGIO_MD5( ... )	DBG_MD5_IF	( IO, ##__VA_ARGS__ )
#define DBGIO_PAUSE( ... )	DBG_PAUSE_IF	( IO, ##__VA_ARGS__ )
#define DBGIO_MORE( ... )	DBG_MORE_IF	( IO, ##__VA_ARGS__ )
#define DBGCIO( ... )		DBGC_IF		( IO, ##__VA_ARGS__ )
#define DBGCIO_HDA( ... )	DBGC_HDA_IF	( IO, ##__VA_ARGS__ )
#define DBGCIO_HD( ... )	DBGC_HD_IF	( IO, ##__VA_ARGS__ )
#define DBGCIO_MD5A( ... )	DBGC_MD5A_IF	( IO, ##__VA_ARGS__ )
#define DBGCIO_MD5( ... )	DBGC_MD5_IF	( IO, ##__VA_ARGS__ )
#define DBGCIO_PAUSE( ... )	DBGC_PAUSE_IF	( IO, ##__VA_ARGS__ )
#define DBGCIO_MORE( ... )	DBGC_MORE_IF	( IO, ##__VA_ARGS__ )

#endif /* ASSEMBLY */
/** @} */

/** @defgroup attrs Miscellaneous attributes
 * @{
 */
#ifndef ASSEMBLY

/** Declare a variable or data structure as unused. */
#define __unused __attribute__ (( unused ))

/**
 * Declare a function as pure - i.e. without side effects
 */
#define __pure __attribute__ (( pure ))

/**
 * Declare a function as const - i.e. it does not access global memory
 * (including dereferencing pointers passed to it) at all.
 * Must also not call any non-const functions.
 */
#define __const __attribute__ (( const ))

/**
 * Declare a function's pointer parameters as non-null - i.e. force
 * compiler to check pointers at compile time and enable possible
 * optimizations based on that fact
 */
#define __nonnull __attribute__ (( nonnull ))

/**
 * Declare a pointer returned by a function as a unique memory address
 * as returned by malloc-type functions.
 */
#define __malloc __attribute__ (( malloc ))

/**
 * Declare a function as used.
 *
 * Necessary only if the function is called only from assembler code.
 */
#define __used __attribute__ (( used ))

/** Declare a data structure to be aligned with 16-byte alignment */
#define __aligned __attribute__ (( aligned ( 16 ) ))

/** Declare a function to be always inline */
#define __always_inline __attribute__ (( always_inline ))

/* Force all inline functions to not be instrumented
 *
 * This is required to cope with what seems to be a long-standing gcc
 * bug, in which -finstrument-functions will cause instances of
 * inlined functions to be reported as further calls to the
 * *containing* function.  This makes instrumentation very difficult
 * to use.
 *
 * Work around this problem by adding the no_instrument_function
 * attribute to all inlined functions.
 */
#define inline inline __attribute__ (( no_instrument_function ))

/**
 * Shared data.
 *
 * To save space in the binary when multiple-driver images are
 * compiled, uninitialised data areas can be shared between drivers.
 * This will typically be used to share statically-allocated receive
 * and transmit buffers between drivers.
 *
 * Use as e.g.
 *
 * @code
 *
 *   struct {
 *	char	rx_buf[NUM_RX_BUF][RX_BUF_SIZE];
 *	char	tx_buf[TX_BUF_SIZE];
 *   } my_static_data __shared;
 *
 * @endcode
 *
 */
#define __shared __asm__ ( "_shared_bss" ) __aligned

#endif /* ASSEMBLY */
/** @} */

/**
 * Optimisation barrier
 */
#ifndef ASSEMBLY
#define barrier() __asm__ __volatile__ ( "" : : : "memory" )
#endif /* ASSEMBLY */

/**
 * Array size
 */
#ifndef ASSEMBLY
#define ARRAY_SIZE(array) ( sizeof (array) / sizeof ( (array)[0] ) )
#endif /* ASSEMBLY */

/**
 * @defgroup licences Licence declarations
 *
 * For reasons that are partly historical, various different files
 * within the iPXE codebase have differing licences.
 *
 * @{
 */

/** Declare a file as being in the public domain
 *
 * This licence declaration is applicable when a file states itself to
 * be in the public domain.
 */
#define FILE_LICENCE_PUBLIC_DOMAIN \
	PROVIDE_SYMBOL ( PREFIX_OBJECT ( __licence__public_domain__ ) )

/** Declare a file as being under version 2 (or later) of the GNU GPL
 *
 * This licence declaration is applicable when a file states itself to
 * be licensed under the GNU GPL; "either version 2 of the License, or
 * (at your option) any later version".
 */
#define FILE_LICENCE_GPL2_OR_LATER \
	PROVIDE_SYMBOL ( PREFIX_OBJECT ( __licence__gpl2_or_later__ ) )

/** Declare a file as being under version 2 of the GNU GPL
 *
 * This licence declaration is applicable when a file states itself to
 * be licensed under version 2 of the GPL, and does not include the
 * "or, at your option, any later version" clause.
 */
#define FILE_LICENCE_GPL2_ONLY \
	PROVIDE_SYMBOL ( PREFIX_OBJECT ( __licence__gpl2_only__ ) )

/** Declare a file as being under any version of the GNU GPL
 *
 * This licence declaration is applicable when a file states itself to
 * be licensed under the GPL, but does not specify a version.
 *
 * According to section 9 of the GPLv2, "If the Program does not
 * specify a version number of this License, you may choose any
 * version ever published by the Free Software Foundation".
 */
#define FILE_LICENCE_GPL_ANY \
	PROVIDE_SYMBOL ( PREFIX_OBJECT ( __licence__gpl_any__ ) )

/** Declare a file as being under the three-clause BSD licence
 *
 * This licence declaration is applicable when a file states itself to
 * be licensed under terms allowing redistribution in source and
 * binary forms (with or without modification) provided that:
 *
 *     redistributions of source code retain the copyright notice,
 *     list of conditions and any attached disclaimers
 *
 *     redistributions in binary form reproduce the copyright notice,
 *     list of conditions and any attached disclaimers in the
 *     documentation and/or other materials provided with the
 *     distribution
 *
 *     the name of the author is not used to endorse or promote
 *     products derived from the software without specific prior
 *     written permission
 *
 * It is not necessary for the file to explicitly state that it is
 * under a "BSD" licence; only that the licensing terms be
 * functionally equivalent to the standard three-clause BSD licence.
 */
#define FILE_LICENCE_BSD3 \
	PROVIDE_SYMBOL ( PREFIX_OBJECT ( __licence__bsd3__ ) )

/** Declare a file as being under the two-clause BSD licence
 *
 * This licence declaration is applicable when a file states itself to
 * be licensed under terms allowing redistribution in source and
 * binary forms (with or without modification) provided that:
 *
 *     redistributions of source code retain the copyright notice,
 *     list of conditions and any attached disclaimers
 *
 *     redistributions in binary form reproduce the copyright notice,
 *     list of conditions and any attached disclaimers in the
 *     documentation and/or other materials provided with the
 *     distribution
 *
 * It is not necessary for the file to explicitly state that it is
 * under a "BSD" licence; only that the licensing terms be
 * functionally equivalent to the standard two-clause BSD licence.
 */
#define FILE_LICENCE_BSD2 \
	PROVIDE_SYMBOL ( PREFIX_OBJECT ( __licence__bsd2__ ) )

/** Declare a file as being under the two-clause BSD plus patent licence
 *
 * This licence declaration is applicable when a file states itself to
 * be licensed under terms allowing redistribution in source and
 * binary forms (with or without modification) provided that:
 *
 *     redistributions of source code retain the copyright notice,
 *     list of conditions and any attached disclaimers
 *
 *     redistributions in binary form reproduce the copyright notice,
 *     list of conditions and any attached disclaimers in the
 *     documentation and/or other materials provided with the
 *     distribution
 *
 * and in addition states that
 *
 *     Subject to the terms and conditions of this license, each
 *     copyright holder and contributor hereby grants to those
 *     receiving rights under this license a perpetual, worldwide,
 *     non-exclusive, no-charge, royalty-free, irrevocable (except for
 *     failure to satisfy the conditions of this license) patent
 *     license to make, have made, use, offer to sell, sell, import,
 *     and otherwise transfer this software, where such license
 *     applies only to those patent claims, already acquired or
 *     hereafter acquired, licensable by such copyright holder or
 *     contributor that are necessarily infringed by:
 *
 *       their Contribution(s) (the licensed copyrights of copyright
 *       holders and non-copyrightable additions of contributors, in
 *       source or binary form) alone; or
 *
 *       combination of their Contribution(s) with the work of
 *       authorship to which such Contribution(s) was added by such
 *       copyright holder or contributor, if, at the time the
 *       Contribution is added, such addition causes such combination
 *       to be necessarily infringed. The patent license shall not
 *       apply to any other combinations which include the
 *       Contribution.
 *
 * It is not necessary for the file to explicitly state that it is
 * under a "BSD" licence; only that the licensing terms be
 * functionally equivalent to the standard two-clause BSD licence with
 * patent grant.
 */
#define FILE_LICENCE_BSD2_PATENT \
	PROVIDE_SYMBOL ( PREFIX_OBJECT ( __licence__bsd2_patent__ ) )

/** Declare a file as being under the one-clause MIT-style licence
 *
 * This licence declaration is applicable when a file states itself to
 * be licensed under terms allowing redistribution for any purpose
 * with or without fee, provided that the copyright notice and
 * permission notice appear in all copies.
 */
#define FILE_LICENCE_MIT \
	PROVIDE_SYMBOL ( PREFIX_OBJECT ( __licence__mit__ ) )

/** Declare a file as being under GPLv2+ or UBDL
 *
 * This licence declaration is applicable when a file states itself to
 * be licensed under the GNU GPL; "either version 2 of the License, or
 * (at your option) any later version" and also states that it may be
 * distributed under the terms of the Unmodified Binary Distribution
 * Licence (as given in the file COPYING.UBDL).
 */
#define FILE_LICENCE_GPL2_OR_LATER_OR_UBDL \
	PROVIDE_SYMBOL ( PREFIX_OBJECT ( __licence__gpl2_or_later_or_ubdl__ ) )

/** Declare a particular licence as applying to a file */
#define FILE_LICENCE( _licence ) FILE_LICENCE_ ## _licence

/** @} */

/* This file itself is under GPLv2+/UBDL */
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );

#include <bits/compiler.h>

#endif /* COMPILER_H */
