/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
//   Copyright (c) 2007-2009 Stanislav Shwartsman
//          Written by Stanislav Shwartsman [sshwarts at sourceforge net]
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library 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
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////

#ifndef BX_DESCRIPTOR_H
#define BX_DESCRIPTOR_H

//
// |---------------------------------------------|
// |             Segment Descriptor              |
// |---------------------------------------------|
// |33222222|2|2|2|2| 11 11 |1|11|1|11  |        |
// |10987654|3|2|1|0| 98 76 |5|43|2|1098|76543210|
// |--------|-|-|-|-|-------|-|--|-|----|--------|
// |Base    |G|D|L|A|Limit  |P|D |S|Type|Base    |
// |[31-24] | |/| |V|[19-16]| |P | |    |[23-16] |
// |        | |B| |L|       | |L | |    |        |
// |------------------------|--------------------|
// |       Base [15-0]      |    Limit [15-0]    |
// |------------------------|--------------------|
//

typedef struct { /* bx_selector_t */
  Bit16u value;   /* the 16bit value of the selector */
  /* the following fields are extracted from the value field in protected
     mode only.  They're used for sake of efficiency */
  Bit16u index;   /* 13bit index extracted from value in protected mode */
  Bit8u  ti;      /* table indicator bit extracted from value */
  Bit8u  rpl;     /* RPL extracted from value */
} bx_selector_t;

#define BX_SELECTOR_RPL(selector) ((selector) & 0x03)
#define BX_SELECTOR_RPL_MASK (0xfffc)

typedef struct
{

// do not go above 4 bits !
#define SegValidCache  (0x01)
#define SegAccessROK   (0x02)
#define SegAccessWOK   (0x04)

  unsigned valid;        // Holds above values, Or'd together.  Used to
                         // hold only 0 or 1.

  bx_bool p;             /* present */
  Bit8u   dpl;           /* descriptor privilege level 0..3 */
  bx_bool segment;       /* 0 = system/gate, 1 = data/code segment */
  Bit8u   type;          /* For system & gate descriptors:
                          *  0 = invalid descriptor (reserved)
                          *  1 = 286 available Task State Segment (TSS)
                          *  2 = LDT descriptor
                          *  3 = 286 busy Task State Segment (TSS)
                          *  4 = 286 call gate
                          *  5 = task gate
                          *  6 = 286 interrupt gate
                          *  7 = 286 trap gate
                          *  8 = (reserved)
                          *  9 = 386 available TSS
                          * 10 = (reserved)
                          * 11 = 386 busy TSS
                          * 12 = 386 call gate
                          * 13 = (reserved)
                          * 14 = 386 interrupt gate
                          * 15 = 386 trap gate */

// For system & gate descriptors:

#define BX_GATE_TYPE_NONE                       (0x0)
#define BX_SYS_SEGMENT_AVAIL_286_TSS            (0x1)
#define BX_SYS_SEGMENT_LDT                      (0x2)
#define BX_SYS_SEGMENT_BUSY_286_TSS             (0x3)
#define BX_286_CALL_GATE                        (0x4)
#define BX_TASK_GATE                            (0x5)
#define BX_286_INTERRUPT_GATE                   (0x6)
#define BX_286_TRAP_GATE                        (0x7)
                                              /* 0x8 reserved */
#define BX_SYS_SEGMENT_AVAIL_386_TSS            (0x9)
                                              /* 0xa reserved */
#define BX_SYS_SEGMENT_BUSY_386_TSS             (0xb)
#define BX_386_CALL_GATE                        (0xc)
                                              /* 0xd reserved */
#define BX_386_INTERRUPT_GATE                   (0xe)
#define BX_386_TRAP_GATE                        (0xf)

// For data/code descriptors:

#define BX_DATA_READ_ONLY                       (0x0)
#define BX_DATA_READ_ONLY_ACCESSED              (0x1)
#define BX_DATA_READ_WRITE                      (0x2)
#define BX_DATA_READ_WRITE_ACCESSED             (0x3)
#define BX_DATA_READ_ONLY_EXPAND_DOWN           (0x4)
#define BX_DATA_READ_ONLY_EXPAND_DOWN_ACCESSED  (0x5)
#define BX_DATA_READ_WRITE_EXPAND_DOWN          (0x6)
#define BX_DATA_READ_WRITE_EXPAND_DOWN_ACCESSED (0x7)
#define BX_CODE_EXEC_ONLY                       (0x8)
#define BX_CODE_EXEC_ONLY_ACCESSED              (0x9)
#define BX_CODE_EXEC_READ                       (0xa)
#define BX_CODE_EXEC_READ_ACCESSED              (0xb)
#define BX_CODE_EXEC_ONLY_CONFORMING            (0xc)
#define BX_CODE_EXEC_ONLY_CONFORMING_ACCESSED   (0xd)
#define BX_CODE_EXEC_READ_CONFORMING            (0xe)
#define BX_CODE_EXEC_READ_CONFORMING_ACCESSED   (0xf)

union {
  struct {
    bx_address base;       /* base address: 286=24bits, 386=32bits, long=64 */
    Bit32u  limit_scaled;  /* for efficiency, this contrived field is set to
                            * limit for byte granular, and
                            * (limit << 12) | 0xfff for page granular seg's
                            */
    bx_bool g;             /* granularity: 0=byte, 1=4K (page) */
    bx_bool d_b;           /* default size: 0=16bit, 1=32bit */
#if BX_SUPPORT_X86_64
    bx_bool l;             /* long mode: 0=compat, 1=64 bit */
#endif
    bx_bool avl;           /* available for use by system */
  } segment;
  struct {
    Bit8u   param_count;   /* 5bits (0..31) #words/dword to copy from caller's
                            * stack to called procedure's stack. */
    Bit16u  dest_selector;
    Bit32u  dest_offset;
  } gate;
  struct {                 /* type 5: Task Gate Descriptor */
    Bit16u  tss_selector;  /* TSS segment selector */
  } taskgate;
} u;

} bx_descriptor_t;

#define IS_PRESENT(descriptor) (descriptor.p)

#if BX_SUPPORT_X86_64
  #define IS_LONG64_SEGMENT(descriptor)   (descriptor.u.segment.l)
#else
  #define IS_LONG64_SEGMENT(descriptor)   (0)
#endif

#define IS_CODE_SEGMENT(type)             (((type) >> 3) & 0x1)
#define IS_CODE_SEGMENT_CONFORMING(type)  (((type) >> 2) & 0x1)
#define IS_DATA_SEGMENT_EXPAND_DOWN(type) (((type) >> 2) & 0x1)
#define IS_CODE_SEGMENT_READABLE(type)    (((type) >> 1) & 0x1)
#define IS_DATA_SEGMENT_WRITEABLE(type)   (((type) >> 1) & 0x1)

#define IS_SEGMENT_ACCESSED(type)         ((type) & 0x1)

#define BX_SEGMENT_CODE                   (0x8)
#define BX_SEGMENT_DATA_EXPAND_DOWN       (0x4)
#define BX_SEGMENT_CODE_CONFORMING        (0x4)
#define BX_SEGMENT_DATA_WRITE             (0x2)
#define BX_SEGMENT_CODE_READ              (0x2)
#define BX_SEGMENT_ACCESSED               (0x1)

#define IS_DATA_SEGMENT(type) (! IS_CODE_SEGMENT(type))
#define IS_CODE_SEGMENT_NON_CONFORMING(type) \
            (! IS_CODE_SEGMENT_CONFORMING(type))

typedef struct {
  bx_selector_t    selector;
  bx_descriptor_t  cache;
} bx_segment_reg_t;

typedef struct {
  bx_address       base;   /* base address: 24bits=286,32bits=386,64bits=x86-64 */
  Bit16u           limit;  /* limit, 16bits */
} bx_global_segment_reg_t;

void  parse_selector(Bit16u raw_selector, bx_selector_t *selector);
Bit8u get_ar_byte(const bx_descriptor_t *d);
void  set_ar_byte(bx_descriptor_t *d, Bit8u ar_byte);
void  parse_descriptor(Bit32u dword1, Bit32u dword2, bx_descriptor_t *temp);

#endif
