⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcmem.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
字号:
/* $Id: pcmem.c 24238 2006-09-23 16:50:39Z fireball $
 *
 *  FreeLoader
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * Note: Most of this code comes from the old file "i386mem.c", which
 *       was Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
 */

#include <freeldr.h>

#define NDEBUG
#include <debug.h>

static ULONG
PcMemGetExtendedMemorySize(VOID)
{
  REGS RegsIn;
  REGS RegsOut;
  ULONG MemorySize;

  DbgPrint((DPRINT_MEMORY, "GetExtendedMemorySize()\n"));

  /* Int 15h AX=E801h
   * Phoenix BIOS v4.0 - GET MEMORY SIZE FOR >64M CONFIGURATIONS
   *
   * AX = E801h
   * Return:
   * CF clear if successful
   * AX = extended memory between 1M and 16M, in K (max 3C00h = 15MB)
   * BX = extended memory above 16M, in 64K blocks
   * CX = configured memory 1M to 16M, in K
   * DX = configured memory above 16M, in 64K blocks
   * CF set on error
   */
  RegsIn.w.ax = 0xE801;
  Int386(0x15, &RegsIn, &RegsOut);

  DbgPrint((DPRINT_MEMORY, "Int15h AX=E801h\n"));
  DbgPrint((DPRINT_MEMORY, "AX = 0x%x\n", RegsOut.w.ax));
  DbgPrint((DPRINT_MEMORY, "BX = 0x%x\n", RegsOut.w.bx));
  DbgPrint((DPRINT_MEMORY, "CX = 0x%x\n", RegsOut.w.cx));
  DbgPrint((DPRINT_MEMORY, "DX = 0x%x\n", RegsOut.w.dx));
  DbgPrint((DPRINT_MEMORY, "CF set = %s\n\n", (RegsOut.x.eflags & I386FLAG_CF) ? "TRUE" : "FALSE"));

  if (INT386_SUCCESS(RegsOut))
    {
      /* If AX=BX=0000h the use CX and DX */
      if (RegsOut.w.ax == 0)
        {
          /* Return extended memory size in K */
          MemorySize = RegsOut.w.dx * 64;
          MemorySize += RegsOut.w.cx;
          return MemorySize;
        }
      else
        {
          /* Return extended memory size in K */
          MemorySize = RegsOut.w.bx * 64;
          MemorySize += RegsOut.w.ax;
          return MemorySize;
        }
    }

  /* If we get here then Int15 Func E801h didn't work */
  /* So try Int15 Func 88h */

  /* Int 15h AH=88h
   * SYSTEM - GET EXTENDED MEMORY SIZE (286+)
   *
   * AH = 88h
   * Return:
   * CF clear if successful
   * AX = number of contiguous KB starting at absolute address 100000h
   * CF set on error
   * AH = status
   * 80h invalid command (PC,PCjr)
   * 86h unsupported function (XT,PS30)
   */
  RegsIn.b.ah = 0x88;
  Int386(0x15, &RegsIn, &RegsOut);

  DbgPrint((DPRINT_MEMORY, "Int15h AH=88h\n"));
  DbgPrint((DPRINT_MEMORY, "AX = 0x%x\n", RegsOut.w.ax));
  DbgPrint((DPRINT_MEMORY, "CF set = %s\n\n", (RegsOut.x.eflags & I386FLAG_CF) ? "TRUE" : "FALSE"));

  if (INT386_SUCCESS(RegsOut) && RegsOut.w.ax != 0)
    {
      MemorySize = RegsOut.w.ax;
      return MemorySize;
    }

  /* If we get here then Int15 Func 88h didn't work */
  /* So try reading the CMOS */
  WRITE_PORT_UCHAR((PUCHAR)0x70, 0x31);
  MemorySize = READ_PORT_UCHAR((PUCHAR)0x71);
  MemorySize = (MemorySize & 0xFFFF);
  MemorySize = (MemorySize << 8);

  DbgPrint((DPRINT_MEMORY, "Int15h Failed\n"));
  DbgPrint((DPRINT_MEMORY, "CMOS reports: 0x%x\n", MemorySize));

  return MemorySize;
}

static ULONG
PcMemGetConventionalMemorySize(VOID)
{
  REGS Regs;

  DbgPrint((DPRINT_MEMORY, "GetConventionalMemorySize()\n"));

  /* Int 12h
   * BIOS - GET MEMORY SIZE
   *
   * Return:
   * AX = kilobytes of contiguous memory starting at absolute address 00000h
   *
   * This call returns the contents of the word at 0040h:0013h;
   * in PC and XT, this value is set from the switches on the motherboard
   */
  Regs.w.ax = 0;
  Int386(0x12, &Regs, &Regs);

  DbgPrint((DPRINT_MEMORY, "Int12h\n"));
  DbgPrint((DPRINT_MEMORY, "AX = 0x%x\n\n", Regs.w.ax));

  return (ULONG)Regs.w.ax;
}

static ULONG
PcMemGetBiosMemoryMap(PBIOS_MEMORY_MAP BiosMemoryMap, ULONG MaxMemoryMapSize)
{
  REGS Regs;
  ULONG MapCount;

  DbgPrint((DPRINT_MEMORY, "GetBiosMemoryMap()\n"));

  /* Int 15h AX=E820h
   * Newer BIOSes - GET SYSTEM MEMORY MAP
   *
   * AX = E820h
   * EAX = 0000E820h
   * EDX = 534D4150h ('SMAP')
   * EBX = continuation value or 00000000h to start at beginning of map
   * ECX = size of buffer for result, in bytes (should be >= 20 bytes)
   * ES:DI -> buffer for result
   * Return:
   * CF clear if successful
   * EAX = 534D4150h ('SMAP')
   * ES:DI buffer filled
   * EBX = next offset from which to copy or 00000000h if all done
   * ECX = actual length returned in bytes
   * CF set on error
   * AH = error code (86h)
   */
  Regs.x.eax = 0x0000E820;
  Regs.x.edx = 0x534D4150; /* ('SMAP') */
  Regs.x.ebx = 0x00000000;
  Regs.x.ecx = sizeof(BIOS_MEMORY_MAP);
  Regs.w.es = BIOSCALLBUFSEGMENT;
  Regs.w.di = BIOSCALLBUFOFFSET;
  for (MapCount = 0; MapCount < MaxMemoryMapSize; MapCount++)
    {
      Int386(0x15, &Regs, &Regs);

      DbgPrint((DPRINT_MEMORY, "Memory Map Entry %d\n", MapCount));
      DbgPrint((DPRINT_MEMORY, "Int15h AX=E820h\n"));
      DbgPrint((DPRINT_MEMORY, "EAX = 0x%x\n", Regs.x.eax));
      DbgPrint((DPRINT_MEMORY, "EBX = 0x%x\n", Regs.x.ebx));
      DbgPrint((DPRINT_MEMORY, "ECX = 0x%x\n", Regs.x.ecx));
      DbgPrint((DPRINT_MEMORY, "CF set = %s\n", (Regs.x.eflags & I386FLAG_CF) ? "TRUE" : "FALSE"));

      /* If the BIOS didn't return 'SMAP' in EAX then
       * it doesn't support this call */
      if (Regs.x.eax != 0x534D4150)
        {
          break;
        }

      /* Copy data to caller's buffer */
      RtlCopyMemory(&BiosMemoryMap[MapCount], (PVOID)BIOSCALLBUFFER, Regs.x.ecx);

      DbgPrint((DPRINT_MEMORY, "BaseAddress: 0x%x%x\n", BiosMemoryMap[MapCount].BaseAddress));
      DbgPrint((DPRINT_MEMORY, "Length: 0x%x%x\n", BiosMemoryMap[MapCount].Length));
      DbgPrint((DPRINT_MEMORY, "Type: 0x%x\n", BiosMemoryMap[MapCount].Type));
      DbgPrint((DPRINT_MEMORY, "Reserved: 0x%x\n", BiosMemoryMap[MapCount].Reserved));
      DbgPrint((DPRINT_MEMORY, "\n"));

      /* If the continuation value is zero or the
       * carry flag is set then this was
       * the last entry so we're done */
      if (Regs.x.ebx == 0x00000000 || !INT386_SUCCESS(Regs))
        {
          MapCount++;
          DbgPrint((DPRINT_MEMORY, "End Of System Memory Map!\n\n"));
          break;
        }

      /* Setup the registers for the next call */
      Regs.x.eax = 0x0000E820;
      Regs.x.edx = 0x534D4150; /* ('SMAP') */
      /* Regs.x.ebx = 0x00000001;  Continuation value already set by the BIOS */
      Regs.x.ecx = sizeof(BIOS_MEMORY_MAP);
      Regs.w.es = BIOSCALLBUFSEGMENT;
      Regs.w.di = BIOSCALLBUFOFFSET;
    }

  return MapCount;
}

ULONG
PcMemGetMemoryMap(PBIOS_MEMORY_MAP BiosMemoryMap, ULONG MaxMemoryMapSize)
{
  ULONG EntryCount;

  EntryCount = PcMemGetBiosMemoryMap(BiosMemoryMap, MaxMemoryMapSize);

  /* If the BIOS didn't provide a memory map, synthesize one */
  if (0 == EntryCount && 2 <= MaxMemoryMapSize)
    {
      /* Conventional memory */
      BiosMemoryMap[0].BaseAddress = 0;
      BiosMemoryMap[0].Length = PcMemGetConventionalMemorySize() * 1024;
      BiosMemoryMap[0].Type = BiosMemoryUsable;
      /* Extended memory */
      BiosMemoryMap[1].BaseAddress = 1024 * 1024;
      BiosMemoryMap[1].Length = PcMemGetExtendedMemorySize() * 1024;
      BiosMemoryMap[1].Type = BiosMemoryUsable;
      EntryCount = 2;
    }

  return EntryCount;
}

/* EOF */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -