/* vim: set filetype=c:
 *
 * rtcommon.h86  -  Common include file for MGL runtime module
 *
 * Copyright (C) 2003-2007 Gero Kuhlmann   <gero@gkminix.han.de>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Id: rtcommon.h86,v 1.17 2007/01/06 18:31:38 gkminix Exp $
 */

#ifndef RUNTIME_RTCOMMON_H86
#define RUNTIME_RTCOMMON_H86


#ifndef _ASSEMBLY_
# define __USE_STRING_INLINES 1
# include <common.h86>
# include <i386/ctype.h86>
# include <i386/string.h86>
# include <i386/conio.h86>
# include <i386/misc.h86>
# include <net/in.h86>
# include <net/bootp.h86>
# include "headers/runtime.h86"
#endif



/*
 *****************************************************************************
 *
 * Error codes returned by the load function
 */
#define LOADERR_NOERROR		0		/* no error */
#define LOADERR_UNSUPP		1		/* function unsupported */
#define LOADERR_PXE		2		/* PXE error */
#define LOADERR_DISK		3		/* disk error */
#define LOADERR_HEAP		4		/* not enough free heap */
#define LOADERR_COPY		5		/* extended memory copy error */
#define LOADERR_HEADER		6		/* invalid boot image header */
#define LOADERR_MEMORY		7		/* not enough space for image */



/*
 *****************************************************************************
 *
 * Error codes. The upper byte of each error code identifies the error
 * source.
 */

/* Special flag to avoid scanning through user exception handlers */
#define NOUSER_ERROR_FLAG	0x8000

/* Code range 0x00: general runtime errors */
#define ENOERROR		0x0000		/* no error */
#define EGENERROR		0x0001		/* general error */
#define EINTERNAL		0x0002		/* internal error */
#define EDIVZERO		0x0003		/* division by zero */
#define EOUTOFBOUNDS		0x0004		/* value out of bounds */
#define EOVERFLOW		0x0005		/* integer overflow */
#define ENOMEMORY		0x0006		/* not enough memory */
#define ESTKOVERFLOW		0x0007		/* stack overflow */
#define EINVPOINTER		0x0008		/* invalid pointer */

/* Code range 0x01: loader errors */
#define ELOADBASE		0x0100
#define ELOADUNSUPPORTED	(ELOADBASE + LOADERR_UNSUPP)
#define ELOADPXE		(ELOADBASE + LOADERR_PXE)
#define ELOADDISK		(ELOADBASE + LOADERR_DISK)
#define ELOADHEAP		(ELOADBASE + LOADERR_HEAP)
#define ELOADCOPY		(ELOADBASE + LOADERR_COPY)
#define ELOADHEADER		(ELOADBASE + LOADERR_HEADER)
#define ELOADMEMORY		(ELOADBASE + LOADERR_MEMORY)



/*
 *****************************************************************************
 *
 * Global definitions
 */
#define SECTSIZE	512		/* size of one disk sector */
#define MAX_HOST_NAME	128		/* max length of client host name */
#define MAX_DOMAIN_NAME	128		/* max length of client domain name */



/*
 *****************************************************************************
 *
 * Global variables
 */
#ifndef _ASSEMBLY_
extern __nptr atexit;			/* Routine to call at the end */
extern __fptr btpptr;			/* Pointer to bootrom BOOTP record */
extern __u16 btplen;			/* Size of bootrom BOOTP buffer */
extern bool_t canload;			/* Flag if we support RTERROR_LOAD */
extern bool_t canrun;			/* Flag if we support RTERROR_RUN */
extern bool_t canchange;		/* Flag if we accept BOOTP changes */
extern bool_t havepxe;			/* Flag if we have PXE support */

extern short exception;			/* Current exception number */
extern short selectnumber;		/* Entered number in select command */
extern char servername[];		/* Boot server name */
extern char hostname[];			/* Our own host name */
extern char domainname[];		/* Our own domain name */
extern char bootfile[];			/* Boot file name */
extern t_ipaddr tftpaddr;		/* TFTP server IP address */
extern t_ipaddr gatewayaddr;		/* Gateway IP address */
extern t_ipaddr dnsaddr;		/* DNS server IP address */

extern const unsigned char iso2pc_table[];	/* Convert ISO->PC charset */
extern const unsigned char pc2iso_table[];	/* Convert PC->ISO charset */
#endif



/*
 *****************************************************************************
 *
 * Global functions
 */
#ifndef _ASSEMBLY_
extern void rtint_exit(__u16 retval) __attribute__((noreturn));
extern void rtint_error(char *s) __attribute__((noreturn));
extern void rtint_raise(short val) __attribute__((noreturn));
extern void rtint_chkstk(unsigned short reqsize);
extern size_t rtint_ip2str(const __u8 *s, char *ret, size_t retsize);
extern bool_t rtint_str2ip(const char *s, __u8 *ret);

extern short loaddisk(size_t len, char *diskid) asm ("loaddisk");
#endif



/*
 *****************************************************************************
 *
 * Functions get called differently by code produced with the MGL compiler
 * compared to code produced by GCC. While MGL always pushes words, GCC
 * always pushes double-words. Also the order of the arguments is different,
 * and MGL expects the called routine to pop it's own arguments from the stack.
 * While some of these differences can be tuned with GCC attributes, it is
 * much easier to use wrapper routines (see __PUBLIC macro below).
 * Those wrapper routines provide the GCC routines with a pointer to the
 * arguments passed by the MGL program. This pointer points to an opaque
 * array of bytes. In order to make ordinary GCC arguments out of these bytes,
 * we use the following macro.
 */
#ifndef _ASSEMBLY_
# define __A(type, index)	(*((type *)&(_args[index*2])))
#endif



/*
 *****************************************************************************
 *
 * Macro to stringify a macro expansion value
 */
#ifndef _ASSEMBLY_
# define _xstr(x...)	_str(x)
# define _str(x...)	#x
#endif



/*
 *****************************************************************************
 *
 * Macros to help with generating values for the exports table
 */
#ifndef _ASSEMBLY_
# define MAKETYPE(type)		VALTYPE_##type
# define MAKECLASS(class)	VALCLASS_##class
# define MAKEEXP(exp, type)	RTEXP_##exp, VALTYPE_##type
#endif



/*
 *****************************************************************************
 *
 * Macros to generate argument lists
 */
#ifndef _ASSEMBLY_
# define __D(type, class)	MAKETYPE(type), MAKECLASS(class)
# define __ARGS(par...)		".byte\t" _str(par) "\n"
#endif



/*
 *****************************************************************************
 *
 * Macros to generate function definitions
 */
#ifndef _ASSEMBLY_

/*
 * Function to get argument array pointer. The equivalent internal GCC function
 * __builtin_stack_frame changed with various GCC versions, and the GCC docu-
 * mentation suggests not to use it except for debugging purposes. Therefore,
 * we define our own function here.
 */
__nb_inline__ __u8 *internal_args_address(void)
{
  register __u32 ret;

  __asm__ __volatile__ (
	"leal\t10(%%ebp),%%ebx"
	: "=&b" (ret)
	: /* no input */ );
  return((__u8 *)ret);
}


/*
 * Generate header for function body. The function body gets declared as
 * "internal_<funcname>" and as an inline function.
 */
# define __INTERNAL(name, type, par...)	\
		__attribute__((always_inline)) \
			static inline type internal_##name(par)


/*
 * Macro to generate exportable function code. This consists of some assembly
 * code which checks the stack pointer, and then calls an internal function
 * called "stub_<funcname>". GCC will then inline the appropriate internal
 * function into this stub. For passing args we construct a pointer to the
 * argument array, which is possible since SS always equals DS.
 */
# define __PUBLIC(name, num, par...)	\
		__attribute__((used_by_asm)) static __u16 stub_##name(void) \
		{ 							\
		  __attribute__((unused)) register __u8 *_args = 	\
					internal_args_address();	\
		  return((__u16)internal_##name(par));			\
		}							\
		asm("_rtproc_" #name ":\n\t"				\
		    "mov $64,%ax\n\t"					\
		    "call _rtint_chkstk\n\t"				\
		    "call _stub_" #name "\n\t"				\
		    "ret $" #num "*2")

#endif



/*
 *****************************************************************************
 *
 * Macros to generate export information
 */
#ifndef _ASSEMBLY_

/* Macros to generate export info */
# define __BEGIN_EXPORT(exp, type)					\
			".section\t.initext\n"				\
			".byte\t" _xstr(MAKEEXP(exp, type)) "\n"

# define __EXPORT_NAME(name)						\
			".asciz\t\"" #name "\"\n"

# define __END_EXPORT	".text"


/* Macros to generate the export info for various record types */
# define __EXPORT_END							\
		asm(	__BEGIN_EXPORT(END, NONE)			\
			".word\t0\n"					\
			".word\t0\n"					\
			__END_EXPORT)

# define __EXPORT_PROC(name, type, argnum, args...)			\
		asm(	__BEGIN_EXPORT(PROC, type)			\
			".word\t_rtproc_" #name "\n"			\
			".word\t" _xstr(argnum) "\n"			\
			__EXPORT_NAME(name)				\
			args						\
			__END_EXPORT)

# define __EXPORT_CONST(name, type, val)				\
		asm(	__BEGIN_EXPORT(CONST, type)			\
			".word\t" _xstr(val) "\n"			\
			".word\t0\n"					\
			__EXPORT_NAME(name)				\
			__END_EXPORT)

# define __EXPORT_VAR(name, type, size)					\
		asm(	__BEGIN_EXPORT(VAR, type)			\
			".word\t_" #name "\n"				\
			".word\t" _xstr(size) "\n"			\
			__EXPORT_NAME(name)				\
			__END_EXPORT)

# define __EXPORT_VARCONST(name, type, size)				\
		asm(	__BEGIN_EXPORT(VARCONST, type)			\
			".word\t_" #name "\n"				\
			".word\t" _xstr(size) "\n"			\
			__EXPORT_NAME(name)				\
			__END_EXPORT)

#endif



/*
 *****************************************************************************
 *
 * Call next exit function
 */
#ifndef _ASSEMBLY_
static inline short callnext(__nptr next, __u16 retval)
{
  __u16 d0 = next;
  __u16 d1 = retval;

  if (next != NNULL) {
	__asm__ __volatile__(
		"call *%0"
		: "=b" (d0), "=a" (d1)
		: "b" (d0), "a" (d1)
		: "memory", "cc");
  }
  return(d1);
}
#endif



/*
 *****************************************************************************
 *
 * Macros to convert characters to/from ISO-8859-1 character set.
 */
#ifndef _ASSEMBLY_
# define iso2pc(c)	(iso2pc_table[(int)(c)])
# define pc2iso(c)	(pc2iso_table[(int)(c)])
#endif

#endif

