/** @file
  Initialize GDT for Linux.

  Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include "LoadLinuxLib.h"


//
// Local structure definitions
//

#pragma pack (1)

//
// Global Descriptor Entry structures
//

typedef struct _GDT_ENTRY {
  UINT16 Limit15_0;
  UINT16 Base15_0;
  UINT8  Base23_16;
  UINT8  Type;
  UINT8  Limit19_16_and_flags;
  UINT8  Base31_24;
} GDT_ENTRY;

typedef
struct _GDT_ENTRIES {
  GDT_ENTRY Null;
  GDT_ENTRY Null2;
  GDT_ENTRY Linear;
  GDT_ENTRY LinearCode;
  GDT_ENTRY TaskSegment;
  GDT_ENTRY Spare4;
  GDT_ENTRY Spare5;
} GDT_ENTRIES;

#pragma pack ()

STATIC GDT_ENTRIES *mGdt = NULL;

//
// Global descriptor table (GDT) Template
//
STATIC GDT_ENTRIES GdtTemplate = {
  //
  // Null
  //
  {
    0x0,            // limit 15:0
    0x0,            // base 15:0
    0x0,            // base 23:16
    0x0,            // type
    0x0,            // limit 19:16, flags
    0x0,            // base 31:24
  },
  //
  // Null2
  //
  {
    0x0,            // limit 15:0
    0x0,            // base 15:0
    0x0,            // base 23:16
    0x0,            // type
    0x0,            // limit 19:16, flags
    0x0,            // base 31:24
  },
  //
  // Linear
  //
  {
    0x0FFFF,        // limit 0xFFFFF
    0x0,            // base 0
    0x0,
    0x09A,          // present, ring 0, data, expand-up, writable
    0x0CF,          // page-granular, 32-bit
    0x0,
  },
  //
  // LinearCode
  //
  {
    0x0FFFF,        // limit 0xFFFFF
    0x0,            // base 0
    0x0,
    0x092,          // present, ring 0, data, expand-up, writable
    0x0CF,          // page-granular, 32-bit
    0x0,
  },
  //
  // TaskSegment
  //
  {
    0x0,            // limit 0
    0x0,            // base 0
    0x0,
    0x089,          // ?
    0x080,          // ?
    0x0,
  },
  //
  // Spare4
  //
  {
    0x0,            // limit 0
    0x0,            // base 0
    0x0,
    0x0,            // present, ring 0, data, expand-up, writable
    0x0,            // page-granular, 32-bit
    0x0,
  },
  //
  // Spare5
  //
  {
    0x0,            // limit 0
    0x0,            // base 0
    0x0,
    0x0,            // present, ring 0, data, expand-up, writable
    0x0,            // page-granular, 32-bit
    0x0,
  },
};

/**
  Initialize Global Descriptor Table.

**/
VOID
InitLinuxDescriptorTables (
  VOID
  )
{
  //
  // Allocate Runtime Data for the GDT
  //
  mGdt = AllocateRuntimePool (sizeof (GdtTemplate) + 8);
  ASSERT (mGdt != NULL);
  mGdt = ALIGN_POINTER (mGdt, 8);

  //
  // Initialize all GDT entries
  //
  CopyMem (mGdt, &GdtTemplate, sizeof (GdtTemplate));

}

/**
  Initialize Global Descriptor Table.

**/
VOID
SetLinuxDescriptorTables (
  VOID
  )
{
  IA32_DESCRIPTOR GdtPtr;
  IA32_DESCRIPTOR IdtPtr;

  //
  // Write GDT register
  //
  GdtPtr.Base = (UINT32)(UINTN)(VOID*) mGdt;
  GdtPtr.Limit = (UINT16) (sizeof (GdtTemplate) - 1);
  AsmWriteGdtr (&GdtPtr);

  IdtPtr.Base = (UINT32) 0;
  IdtPtr.Limit = (UINT16) 0;
  AsmWriteIdtr (&IdtPtr);
}

