#ifndef REGISTERS_H
#define REGISTERS_H

/** @file
 *
 * i386 registers.
 *
 * This file defines data structures that allow easy access to i386
 * register dumps.
 *
 */

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );

#include <stdint.h>

/**
 * A 16-bit general register.
 *
 * This type encapsulates a 16-bit register such as %ax, %bx, %cx,
 * %dx, %si, %di, %bp or %sp.
 *
 */
typedef union {
	struct {
		union {
			uint8_t l;
			uint8_t byte;
		};
		uint8_t h;
	} __attribute__ (( packed ));
	uint16_t word;
} __attribute__ (( packed )) reg16_t;

/**
 * A 32-bit general register.
 *
 * This type encapsulates a 32-bit register such as %eax, %ebx, %ecx,
 * %edx, %esi, %edi, %ebp or %esp.
 *
 */
typedef union {
	struct {
		union {
			uint8_t l;
			uint8_t byte;
		};
		uint8_t h;
	} __attribute__ (( packed ));
	uint16_t word;
	uint32_t dword;
} __attribute__ (( packed )) reg32_t;

/**
 * A 32-bit general register dump.
 *
 * This is the data structure that is created on the stack by the @c
 * pushal instruction, and can be read back using the @c popal
 * instruction.
 *
 */
struct i386_regs {
	union {
		uint16_t di;
		uint32_t edi;
	};
	union {
		uint16_t si;
		uint32_t esi;
	};
	union {
		uint16_t bp;
		uint32_t ebp;
	};
	union {
		uint16_t sp;
		uint32_t esp;
	};
	union {
		struct {
			uint8_t bl;
			uint8_t bh;
		} __attribute__ (( packed ));
		uint16_t bx;
		uint32_t ebx;
	};
	union {
		struct {
			uint8_t dl;
			uint8_t dh;
		} __attribute__ (( packed ));
		uint16_t dx;
		uint32_t edx;
	};
	union {
		struct {
			uint8_t cl;
			uint8_t ch;
		} __attribute__ (( packed ));
		uint16_t cx;
		uint32_t ecx;
	};
	union {
		struct {
			uint8_t al;
			uint8_t ah;
		} __attribute__ (( packed ));
		uint16_t ax;
		uint32_t eax;
	};
} __attribute__ (( packed ));

/**
 * A segment register dump.
 *
 * The i386 has no equivalent of the @c pushal or @c popal
 * instructions for the segment registers.  We adopt the convention of
 * always using the sequences
 *
 * @code
 *
 *   pushw %gs ; pushw %fs ; pushw %es ; pushw %ds ; pushw %ss ; pushw %cs
 *
 * @endcode
 *
 * and
 *
 * @code
 *
 *   addw $4, %sp ; popw %ds ; popw %es ; popw %fs ; popw %gs
 *
 * @endcode
 *
 * This is the data structure that is created and read back by these
 * instruction sequences.
 *
 */
struct i386_seg_regs {
	uint16_t cs;
	uint16_t ss;
	uint16_t ds;
	uint16_t es;
	uint16_t fs;
	uint16_t gs;
} __attribute__ (( packed ));

/**
 * A full register dump.
 *
 * This data structure is created by the instructions
 *
 * @code
 *
 *   pushfl
 *   pushal
 *   pushw %gs ; pushw %fs ; pushw %es ; pushw %ds ; pushw %ss ; pushw %cs
 *
 * @endcode
 *
 * and can be read back using the instructions
 *
 * @code
 *
 *   addw $4, %sp ; popw %ds ; popw %es ; popw %fs ; popw %gs
 *   popal
 *   popfl
 *
 * @endcode
 *
 * virt_call() and kir_call() create this data structure on the stack
 * and pass in a pointer to this structure.
 *
 */
struct i386_all_regs {
	struct i386_seg_regs segs;
	struct i386_regs regs;
	uint32_t flags;
} __attribute__ (( packed ));

/* Flags */
#define CF ( 1 <<  0 )
#define PF ( 1 <<  2 )
#define AF ( 1 <<  4 )
#define ZF ( 1 <<  6 )
#define SF ( 1 <<  7 )
#define OF ( 1 << 11 )

/* Segment:offset structure.  Note that the order within the structure
 * is offset:segment.
 */
struct segoff {
	uint16_t offset;
	uint16_t segment;
} __attribute__ (( packed ));

typedef struct segoff segoff_t;

#endif /* REGISTERS_H */
