
/**
 * @file vad-def.c
 *
 * Tento soubor se snazi nekolika rutinami skryvat rozdily v definici datovych
 * struktur VADu. Tyto rutiny prevadi obsah techto datovych struktur na obecnejsi
 * datove struktury definovane ovladacem vad.sys.
 */

#include <ntddk.h>
#include "version.h"
#include "vad-lib.h"
#include "vad-def.h"

// Uchovava cislo verze operacniho systemu, na kterem ovladac bezi
static ULONG VersionCode = VERSION_UNKNOWN;


/** Precte z daneho VADu informace nutne pro prochazeni stromu techto desktriptoru
 *  a zapise je do struktury MMADDRESS_NODE. Tato operace ja na Windows Server 2003
 *  a novejsich verzich OS jednoducha, protoze samotny VAD tuto strukturu jiz
 *  obsahuje. Na Windows 2000/XP x86 je to jinak.
 *
 *  @param Vad Cilovy VAD.
 *  @param Node Struktura MMADDRESS_NODE, kam ma procedura ulozit prislusne
 *  informace.
 */
VOID VDFillAddressNode(PVOID Vad, PMMADDRESS_NODE Node)
{
  PMMVAD_SHORT_WXP VadXP = (PMMVAD_SHORT_WXP)Vad;
  PMMVAD_SHORT_W2K3 Vad2k3 = (PMMVAD_SHORT_W2K3)Vad;
  PMMVAD_SHORT_VISTA VadVista = (PMMVAD_SHORT_VISTA)Vad;
  PMMVAD_SHORT_W7 Vad7 = (PMMVAD_SHORT_W7)Vad;
  KdPrint(("vad-def.c: VDFillAddressNode(Vad=0x%p; Node=0x%p)\n", Vad, Node));

  switch (VersionCode) {
    case VERSION_WXP:
      Node->u1.Parent = (PMMADDRESS_NODE)VadXP->Parent;
      Node->LeftChild =  (PMMADDRESS_NODE)VadXP->LeftChild;
      Node->RightChild = (PMMADDRESS_NODE)VadXP->RightChild;
      Node->StartingVPN = VadXP->StartingVpn;
      Node->EdningVPN = VadXP->EndingVpn;
      break;
    case VERSION_W2K3:
      *Node = Vad2k3->Node;
      break;
    case VERSION_VISTA:
      *Node = VadVista->Node;
      break;
    case VERSION_W7:
      *Node = Vad7->Node;
      break;
    default:
      KdPrint(("vad-def.c: VDFillAddressNode(): ERROR: Unsupported OS\n"));
      ASSERT(FALSE);
      break;
  }

  KdPrint(("vad-def.c: VDFillAddressNode(-)\n"));
  return;
}


/** Vrati prvni skupinu priznaku zadaneho VADu v obecnem formatu.
 *
 *  @param Vad Adresa VADu.
 *
 *  @return Vraci prvni skupinu priznaku daneho VADu ve formatu MMVAD_FLAGS.
 */
MMVAD_FLAGS VDGetVadFlags(PVOID Vad) 
{
  PMMVAD_SHORT_WXP VadXP = (PMMVAD_SHORT_WXP)Vad;
  PMMVAD_SHORT_W2K3 Vad2k3 = (PMMVAD_SHORT_W2K3)Vad;
  PMMVAD_SHORT_VISTA VadVista = (PMMVAD_SHORT_VISTA)Vad;
  PMMVAD_SHORT_W7 Vad7 = (PMMVAD_SHORT_W7)Vad;
  MMVAD_FLAGS Ret;
  KdPrint(("vad-def.c: VDGetVadFlags(Vad=0x%p)\n", Vad));

  Ret.VadType = VadNone;
  Ret.Spare = 0;
  switch (VersionCode) {
    case VERSION_WXP:
      Ret.CommitCharge = VadXP->u.VadFlags.CommitCharge;
      Ret.MemCommit = VadXP->u.VadFlags.MemCommit;
      Ret.NoChange = VadXP->u.VadFlags.NoChange;
      Ret.Protection = VadXP->u.VadFlags.Protection;
      Ret.PrivateMemory = VadXP->u.VadFlags.PrivateMemory;
      break;
    case VERSION_W2K3:
      Ret.CommitCharge = Vad2k3->u.VadFlags.CommitCharge;
      Ret.MemCommit = Vad2k3->u.VadFlags.MemCommit;
      Ret.NoChange = Vad2k3->u.VadFlags.NoChange;
      Ret.PrivateMemory = Vad2k3->u.VadFlags.PrivateMemory;
      Ret.Protection = Vad2k3->u.VadFlags.Protection;
      Ret.VadType = Vad2k3->u.VadFlags.VadType;
      break;
	case VERSION_VISTA:
      Ret.CommitCharge = VadVista->u.VadFlags.CommitCharge;
      Ret.MemCommit = VadVista->u.VadFlags.MemCommit;
      Ret.NoChange = VadVista->u.VadFlags.NoChange;
      Ret.PrivateMemory = VadVista->u.VadFlags.PrivateMemory;
      Ret.Protection = VadVista->u.VadFlags.Protection;
      Ret.VadType = VadVista->u.VadFlags.VadType;
      break;
	case VERSION_W7:
      Ret.CommitCharge = Vad7->u.VadFlags.CommitCharge;
      Ret.MemCommit = Vad7->u.VadFlags.MemCommit;
      Ret.NoChange = Vad7->u.VadFlags.NoChange;
      Ret.PrivateMemory = Vad7->u.VadFlags.PrivateMemory;
      Ret.Protection = Vad7->u.VadFlags.Protection;
      Ret.VadType = Vad7->u.VadFlags.VadType;
      break;
    default:
      KdPrint(("vad-def.c: VDGetVadFlags(): ERROR: Unsupported OS\n"));
      ASSERT(FALSE);
      break;
  }

  KdPrint(("vad-def.c: VDGetVadFlags(-):0x%x\n", Ret));
  return Ret;
}


/** Vrati druhou skupinu priznaku zadaneho VADu v obecnem formatu.
 *
 *  Rutina neprovadi zadne kontroly, zda se nahodou (v pripade 2000/XP/2003) nejedna
 *  o kratky VAD, ktery tyto priznaky neobsahuje.
 *
 *  @param Vad Adresa VADu.
 *
 *  @return Vraci druhou skupinu priznaku daneho VADu ve formatu MMVAD_FLAGS2.
 */
MMVAD_FLAGS2 VDGetVadFlags2(PVOID Vad) 
{
  PMMVAD_WXP VadXP = (PMMVAD_WXP)Vad;
  PMMVAD_W2K3 Vad2k3 = (PMMVAD_W2K3)Vad;
  PMMVAD_VISTA VadVista = (PMMVAD_VISTA)Vad;
  PMMVAD_W7 Vad7 = (PMMVAD_W7)Vad;
  MMVAD_FLAGS2 Ret;
  KdPrint(("vad-def.c: VDGetVadFlags2(Vad=0x%p)\n", Vad));

  switch (VersionCode) {
    case VERSION_WXP:
      Ret.CopyOnWrite = VadXP->u2.VadFlags2.CopyOnWrite;
      Ret.ExtendableFile = VadXP->u2.VadFlags2.ExtendableFile;
      Ret.FileOffset = VadXP->u2.VadFlags2.FileOffset;
      Ret.Inherit = VadXP->u2.VadFlags2.Inherit;
      Ret.LongVad = VadXP->u2.VadFlags2.LongVad;
      Ret.MultipleSecured = VadXP->u2.VadFlags2.MultipleSecured;
      Ret.OneSecured = VadXP->u2.VadFlags2.OneSecured;
      Ret.ReadOnly = VadXP->u2.VadFlags2.ReadOnly;
      Ret.SecNoChange = VadXP->u2.VadFlags2.SecNoChange;
      break;
	case VERSION_W2K3:
      Ret.CopyOnWrite = Vad2k3->u2.VadFlags2.CopyOnWrite;
      Ret.ExtendableFile = Vad2k3->u2.VadFlags2.ExtendableFile;
      Ret.FileOffset = Vad2k3->u2.VadFlags2.FileOffset;
      Ret.Inherit = Vad2k3->u2.VadFlags2.Inherit;
      Ret.LongVad = Vad2k3->u2.VadFlags2.LongVad;
      Ret.MultipleSecured = Vad2k3->u2.VadFlags2.MultipleSecured;
      Ret.OneSecured = Vad2k3->u2.VadFlags2.OneSecured;
      Ret.ReadOnly = Vad2k3->u2.VadFlags2.ReadOnly;
      Ret.SecNoChange = Vad2k3->u2.VadFlags2.SecNoChange;
      break;
    case VERSION_VISTA:
      Ret.CopyOnWrite = VadVista->u2.VadFlags2.CopyOnWrite;
      Ret.ExtendableFile = VadVista->u2.VadFlags2.ExtendableFile;
      Ret.FileOffset = VadVista->u2.VadFlags2.FileOffset;
      Ret.Inherit = VadVista->u2.VadFlags2.Inherit;
      Ret.LongVad = VadVista->u2.VadFlags2.LongVad;
      Ret.MultipleSecured = VadVista->u2.VadFlags2.MultipleSecured;
      Ret.OneSecured = VadVista->u2.VadFlags2.OneSecured;
      Ret.ReadOnly = VadVista->u2.VadFlags2.ReadOnly;
      Ret.SecNoChange = VadVista->u2.VadFlags2.SecNoChange;
      break;
    case VERSION_W7:
      Ret.CopyOnWrite = Vad7->u2.VadFlags2.CopyOnWrite;
      Ret.ExtendableFile = Vad7->u2.VadFlags2.ExtendableFile;
      Ret.FileOffset = Vad7->u2.VadFlags2.FileOffset;
      Ret.Inherit = Vad7->u2.VadFlags2.Inherit;
      Ret.LongVad = Vad7->u2.VadFlags2.LongVad;
      Ret.MultipleSecured = Vad7->u2.VadFlags2.MultipleSecured;
      Ret.OneSecured = Vad7->u2.VadFlags2.OneSecured;
      Ret.ReadOnly = Vad7->u2.VadFlags2.ReadOnly;
      Ret.SecNoChange = Vad7->u2.VadFlags2.SecNoChange;
      break;
    default:
      KdPrint(("vad-def.c: VDGetVadFlags2(): ERROR: Unsupported OS\n"));
      ASSERT(FALSE);
      break;
  }

  KdPrint(("vad-def.c: VDGetVadFlags2(-):0x%x\n", Ret));
  return Ret;
}


/** Vrati treti skupinu priznaku zadaneho VADu v obecnem formatu.
 *
 *  @param Vad Adresa VADu.
 *
 *  @return Vraci treti skupinu priznaku daneho VADu ve formatu MMVAD_FLAGS3.
 */
MMVAD_FLAGS3 VDGetVadFlags3(PVOID Vad) 
{
  PMMVAD_LONG_VISTA VadVista = (PMMVAD_LONG_VISTA)Vad;
  PMMVAD_LONG_W7 Vad7 = (PMMVAD_LONG_W7)Vad;
  MMVAD_FLAGS3 Ret;
  KdPrint(("vad-def.c: VDGetVadFlags3(Vad=0x%p)\n", Vad));

  Ret.Spare = 0;
  Ret.Spare2 = 0;
  switch (VersionCode) {
    case VERSION_WXP:
    case VERSION_W2K3:
      RtlZeroMemory(&Ret, sizeof(Ret));
      break;
    case VERSION_VISTA:
      Ret.LastSequentialTrim = VadVista->u5.VadFlags3.LastSequentialTrim;
      Ret.PreferredNode = VadVista->u5.VadFlags3.PreferredNode;
      Ret.SequentialAccess = VadVista->u5.VadFlags3.SequentialAccess;
      Ret.Teb = VadVista->u5.VadFlags3.Teb;
      break;
    case VERSION_W7:
      Ret.LastSequentialTrim = Vad7->u5.VadFlags3.LastSequentialTrim;
      Ret.PreferredNode = Vad7->u5.VadFlags3.PreferredNode;
      Ret.SequentialAccess = Vad7->u5.VadFlags3.SequentialAccess;
      Ret.Teb = Vad7->u5.VadFlags3.Teb;
      break;
    default:
      KdPrint(("vad-def.c: VDGetVadFlags3(): ERROR: Unsupported OS\n"));
      ASSERT(FALSE);
      break;
  }

  KdPrint(("vad-def.c: VDGetVadFlags3(-):0x%x\n", Ret));
  return Ret;
}


/** Vrati typ daneho deskriptoru. 
 *
 *  Pro Windows Server 2003/Vista/7 vrati hodnotu VadType z prvni skupiny priznaku.
 *  Na Windows 2000/XP x86 tuto hodnotu zkusi uhodnout z hodnot v prni skupine
 *  priznaku. Spravnost neni garantovana.
 *
 *  @param Vad Adresa ciloveho deskriptoru.
 *
 *  @return Vrati typ zadaneho VADu.
 */
MI_VAD_TYPE VDGetVadType(PVOID Vad)
{
  PMMVAD_SHORT_WXP VadXP = (PMMVAD_SHORT_WXP)Vad;
  MMVAD_FLAGS VadFlags;
  MMVAD_FLAGS_WXP VadFlagsXP = VadXP->u.VadFlags;
  MI_VAD_TYPE Ret = VadNone;
  KdPrint(("vad-def.c: VDGetVadType(Vad=0x%p)\n", Vad));

  VadFlags = VDGetVadFlags(Vad);
  switch (VersionCode) {
    case VERSION_WXP:
      Ret = VadNone;
      if (VadFlagsXP.ImageMap == 1)
        Ret = VadImageMap;
	  else if (VadFlagsXP.LargePages == 1) {
        Ret = VadLargePages;
        if (VadFlagsXP.PrivateMemory == 0)
          Ret = VadLargePageSection;
	  } else if (VadFlagsXP.PhysicalMapping == 1)
        Ret = VadDevicePhysicalMemory;
	  else if (VadFlagsXP.UserPhysicalPages == 1)
        Ret = VadAwe;
	  else if (VadFlagsXP.WriteWatch == 1)
        Ret = VadWriteWatch;
      break;
    case VERSION_W2K3:
    case VERSION_VISTA:
    case VERSION_W7:
      Ret = (MI_VAD_TYPE)VadFlags.VadType;
      break;
    default:
      KdPrint(("vad-def.c: VDGetVadType(): ERROR: Unsupported OS\n"));
      ASSERT(FALSE);
      break;
  }

  KdPrint(("vad-def.c: VDGetVadType(-):%u\n", Ret));
  return Ret;
}


/** Zjisti, jakou ma dany deskriptor strukturu (kratkou, normalni, dlouhou).
 *
 *  @param Vad Cilovy deskriptor.
 *
 *  @return Vraci hodnotu VAD_STRUCTURE_TYPE urcujici typ struktury ciloveho
 *  deskriptoru.
 */
VAD_STRUCTURE_TYPE VDGetVadStructureType(PVOID Vad)
{
  MMVAD_FLAGS VadFlags;
  MMVAD_FLAGS2 VadFlags2;
  VAD_STRUCTURE_TYPE Ret = VadStructureUnknown;
  KdPrint(("vad-def.c: VDGetVadStructureType(Vad=0x%p)\n", Vad));

  VadFlags = VDGetVadFlags(Vad);
  Ret = (VadFlags.PrivateMemory == 0 || VadFlags.NoChange == 1) ? VadStructureNormal : VadStructureShort;
  if (Ret == VadStructureNormal) {
    VadFlags2 = VDGetVadFlags2(Vad);
    Ret = (VadFlags2.LongVad == 1) ? VadStructureLong : VadStructureNormal;
  }

  KdPrint(("vad-def.c: VDGetVadStructureType(-):%u\n", Ret));
  return Ret;
}


/** Inicializuje modul skryvajici rozdily mezi datovymi strukturami virtualnich
 *  deskriptoru na ruznych verzich Windows.
 *
 *  @return Funkce vraci hodnotu NTSTATUS indikujici uspech ci neuspech operace.
 */
NTSTATUS VDInit(VOID)
{
  NTSTATUS Status = STATUS_UNSUCCESSFUL;
  KdPrint(("vad-def.c: VDInit()\n"));

  Status = STATUS_SUCCESS;
  VersionCode = GetVersionCode();
  if (VersionCode == VERSION_W2K)
    Status = STATUS_NOT_SUPPORTED;

  KdPrint(("vad-def.c: VDInit(-)\n", Status));
  return Status;
}


/** Provede uklid po modulu skryvajicim rozdily mezi jednotlivymi verzemi Windows
 *  co se tyce virtualnich deskriptoru (VAD). Protoze pri inicializaci nedochazi
 *  k zadnemu zasahu do datovych struktur jadra, tato rutina vlastne nedela nic.
 */
VOID VDFinit(VOID)
{
  KdPrint(("vad-def.c: VDFinit()\n"));

  KdPrint(("vad-def.c: VDFinit(-)\n"));
  return;
}
