/* ----------------------------------------------------------------------- *
 *
 *   Copyright 2001-2008 rPath, Inc. - All Rights Reserved
 *
 *   Permission is hereby granted, free of charge, to any person
 *   obtaining a copy of this software and associated documentation
 *   files (the "Software"), to deal in the Software without
 *   restriction, including without limitation the rights to use,
 *   copy, modify, merge, publish, distribute, sublicense, and/or
 *   sell copies of the Software, and to permit persons to whom
 *   the Software is furnished to do so, subject to the following
 *   conditions:
 *
 *   The above copyright notice and this permission notice shall
 *   be included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 *
 * ----------------------------------------------------------------------- */

#ifndef RELOC_H
#define RELOC_H

#include <stdint.h>
#include <stddef.h>

void memmove(void *, void *, size_t);

void jump_to_kernel(uint32_t rm_segment, uint32_t esp);

static inline void memset(void *dst, int c, size_t len)
{
	uint32_t ecx = len >> 2;

	asm volatile("rep; stosl; "
		     "movl %3,%%ecx; "
		     "rep; stosb"
		     : "+D" (dst), "+c" (ecx)
		     : "a" ((uint8_t)c*0x01010101), "bdS" (len & 3)
		     : "memory");
}

/*
 * This structure defines the register frame used by the
 * system call interface.
 *
 * The syscall interface is:
 *
 * intcall(interrupt_#, source_regs, return_regs)
 */
typedef union {
	uint32_t l;
	uint16_t w[2];
	uint8_t  b[4];
} reg32_t;

typedef struct {
	uint16_t gs;			/* Offset  0 */
	uint16_t fs;			/* Offset  2 */
	uint16_t es;			/* Offset  4 */
	uint16_t ds;			/* Offset  6 */

	reg32_t edi;			/* Offset  8 */
	reg32_t esi;			/* Offset 12 */
	reg32_t ebp;			/* Offset 16 */
	reg32_t _unused_esp;		/* Offset 20 */
	reg32_t ebx;			/* Offset 24 */
	reg32_t edx;			/* Offset 28 */
	reg32_t ecx;			/* Offset 32 */
	reg32_t eax;			/* Offset 36 */

	reg32_t eflags;			/* Offset 40 */
} com32sys_t;

/* EFLAGS definitions */
#define EFLAGS_CF		0x00000001
#define EFLAGS_PF		0x00000004
#define EFLAGS_AF		0x00000010
#define EFLAGS_ZF		0x00000040
#define EFLAGS_SF		0x00000080
#define EFLAGS_TF		0x00000100
#define EFLAGS_IF		0x00000200
#define EFLAGS_DF		0x00000400
#define EFLAGS_OF		0x00000800
#define EFLAGS_IOPL		0x00003000
#define EFLAGS_NT		0x00004000
#define EFLAGS_RF		0x00010000
#define EFLAGS_VM		0x00020000
#define EFLAGS_AC		0x00040000
#define EFLAGS_VIF		0x00080000
#define EFLAGS_VIP		0x00100000
#define EFLAGS_ID		0x00200000

static inline uint16_t SEG(const volatile void *__p)
{
  return (uint16_t)(((uintptr_t)__p) >> 4);
}

static inline uint16_t OFFS(const volatile void *__p)
{
  /* The double cast here is to shut up gcc */
  return (uint16_t)(uintptr_t)__p & 0x000F;
}

void intcall(uint8_t intr, const com32sys_t *ireg, com32sys_t *oreg);

#endif /* RELOC_H */
