ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

pcmem.c
Go to the documentation of this file.
00001 /*
00002  *  FreeLoader
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License along
00015  *  with this program; if not, write to the Free Software Foundation, Inc.,
00016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00017  *
00018  * Note: Most of this code comes from the old file "i386mem.c", which
00019  *       was Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
00020  */
00021 
00022 #include <freeldr.h>
00023 #include <arch/pc/x86common.h>
00024 
00025 #define NDEBUG
00026 #include <debug.h>
00027 
00028 DBG_DEFAULT_CHANNEL(MEMORY);
00029 
00030 #define MAX_BIOS_DESCRIPTORS 32
00031 #define FREELDR_BASE_PAGE  (FREELDR_BASE / PAGE_SIZE)
00032 #define FILEBUF_BASE_PAGE  (FILESYSBUFFER / PAGE_SIZE)
00033 #define DISKBUF_BASE_PAGE  (DISKREADBUFFER / PAGE_SIZE)
00034 #define STACK_BASE_PAGE    (DISKBUF_BASE_PAGE + 1)
00035 #define STACK_END_PAGE     (STACK32ADDR / PAGE_SIZE)
00036 #define BIOSBUF_BASE_PAGE  (BIOSCALLBUFFER / PAGE_SIZE)
00037 
00038 #define FREELDR_PAGE_COUNT (FILEBUF_BASE_PAGE - FREELDR_BASE_PAGE)
00039 #define FILEBUF_PAGE_COUNT (DISKBUF_BASE_PAGE - FILEBUF_BASE_PAGE)
00040 #define DISKBUF_PAGE_COUNT (1)
00041 #define STACK_PAGE_COUNT   (STACK_END_PAGE - STACK_BASE_PAGE)
00042 #define BIOSBUF_PAGE_COUNT (1)
00043 
00044 BIOS_MEMORY_MAP PcBiosMemoryMap[MAX_BIOS_DESCRIPTORS];
00045 ULONG PcBiosMapCount;
00046 
00047 FREELDR_MEMORY_DESCRIPTOR PcMemoryMap[MAX_BIOS_DESCRIPTORS + 1] =
00048 {
00049  { LoaderFirmwarePermanent, 0x00,               1 }, // realmode int vectors
00050  { LoaderFirmwareTemporary, 0x01,               FREELDR_BASE_PAGE - 1 }, // freeldr stack + cmdline
00051  { LoaderLoadedProgram,     FREELDR_BASE_PAGE,  FREELDR_PAGE_COUNT }, // freeldr image
00052  { LoaderFirmwareTemporary, FILEBUF_BASE_PAGE,  FILEBUF_PAGE_COUNT }, // File system read buffer. FILESYSBUFFER
00053  { LoaderFirmwareTemporary, DISKBUF_BASE_PAGE,  DISKBUF_PAGE_COUNT }, // Disk read buffer for int 13h. DISKREADBUFFER
00054  { LoaderOsloaderStack,     STACK_BASE_PAGE,    STACK_PAGE_COUNT }, // prot mode stack.
00055  { LoaderFirmwareTemporary, BIOSBUF_BASE_PAGE,  BIOSBUF_PAGE_COUNT }, // BIOSCALLBUFFER
00056  { LoaderFirmwarePermanent, 0xA0,               0x50 }, // ROM / Video
00057  { LoaderSpecialMemory,     0xF0,               0x10 }, // ROM / Video
00058  { LoaderSpecialMemory,     0xFFF,              1 }, // unusable memory
00059  { 0, 0, 0 }, // end of map
00060 };
00061 
00062 ULONG
00063 AddMemoryDescriptor(
00064     IN OUT PFREELDR_MEMORY_DESCRIPTOR List,
00065     IN ULONG MaxCount,
00066     IN PFN_NUMBER BasePage,
00067     IN PFN_NUMBER PageCount,
00068     IN TYPE_OF_MEMORY MemoryType);
00069 
00070 static
00071 BOOLEAN
00072 GetExtendedMemoryConfiguration(ULONG* pMemoryAtOneMB /* in KB */, ULONG* pMemoryAtSixteenMB /* in 64KB */)
00073 {
00074     REGS     RegsIn;
00075     REGS     RegsOut;
00076 
00077     TRACE("GetExtendedMemoryConfiguration()\n");
00078 
00079     *pMemoryAtOneMB = 0;
00080     *pMemoryAtSixteenMB = 0;
00081 
00082     // Int 15h AX=E801h
00083     // Phoenix BIOS v4.0 - GET MEMORY SIZE FOR >64M CONFIGURATIONS
00084     //
00085     // AX = E801h
00086     // Return:
00087     // CF clear if successful
00088     // AX = extended memory between 1M and 16M, in K (max 3C00h = 15MB)
00089     // BX = extended memory above 16M, in 64K blocks
00090     // CX = configured memory 1M to 16M, in K
00091     // DX = configured memory above 16M, in 64K blocks
00092     // CF set on error
00093     RegsIn.w.ax = 0xE801;
00094     Int386(0x15, &RegsIn, &RegsOut);
00095 
00096     TRACE("Int15h AX=E801h\n");
00097     TRACE("AX = 0x%x\n", RegsOut.w.ax);
00098     TRACE("BX = 0x%x\n", RegsOut.w.bx);
00099     TRACE("CX = 0x%x\n", RegsOut.w.cx);
00100     TRACE("DX = 0x%x\n", RegsOut.w.dx);
00101     TRACE("CF set = %s\n\n", (RegsOut.x.eflags & EFLAGS_CF) ? "TRUE" : "FALSE");
00102 
00103     if (INT386_SUCCESS(RegsOut))
00104     {
00105         // If AX=BX=0000h the use CX and DX
00106         if (RegsOut.w.ax == 0)
00107         {
00108             // Return extended memory size in K
00109             *pMemoryAtSixteenMB = RegsOut.w.dx;
00110             *pMemoryAtOneMB = RegsOut.w.cx;
00111             return TRUE;
00112         }
00113         else
00114         {
00115             // Return extended memory size in K
00116             *pMemoryAtSixteenMB = RegsOut.w.bx;
00117             *pMemoryAtOneMB = RegsOut.w.ax;
00118             return TRUE;
00119         }
00120     }
00121 
00122     // If we get here then Int15 Func E801h didn't work
00123     // So try Int15 Func 88h
00124     // Int 15h AH=88h
00125     // SYSTEM - GET EXTENDED MEMORY SIZE (286+)
00126     //
00127     // AH = 88h
00128     // Return:
00129     // CF clear if successful
00130     // AX = number of contiguous KB starting at absolute address 100000h
00131     // CF set on error
00132     // AH = status
00133     // 80h invalid command (PC,PCjr)
00134     // 86h unsupported function (XT,PS30)
00135     RegsIn.b.ah = 0x88;
00136     Int386(0x15, &RegsIn, &RegsOut);
00137 
00138     TRACE("Int15h AH=88h\n");
00139     TRACE("AX = 0x%x\n", RegsOut.w.ax);
00140     TRACE("CF set = %s\n\n", (RegsOut.x.eflags & EFLAGS_CF) ? "TRUE" : "FALSE");
00141 
00142     if (INT386_SUCCESS(RegsOut) && RegsOut.w.ax != 0)
00143     {
00144         *pMemoryAtOneMB = RegsOut.w.ax;
00145         return TRUE;
00146     }
00147 
00148     // If we get here then Int15 Func 88h didn't work
00149     // So try reading the CMOS
00150     WRITE_PORT_UCHAR((PUCHAR)0x70, 0x31);
00151     *pMemoryAtOneMB = READ_PORT_UCHAR((PUCHAR)0x71);
00152     *pMemoryAtOneMB = (*pMemoryAtOneMB & 0xFFFF);
00153     *pMemoryAtOneMB = (*pMemoryAtOneMB << 8);
00154 
00155     TRACE("Int15h Failed\n");
00156     TRACE("CMOS reports: 0x%x\n", *pMemoryAtOneMB);
00157 
00158     if (*pMemoryAtOneMB != 0)
00159     {
00160         return TRUE;
00161     }
00162 
00163     return FALSE;
00164 }
00165 
00166 static ULONG
00167 PcMemGetConventionalMemorySize(VOID)
00168 {
00169   REGS Regs;
00170 
00171   TRACE("GetConventionalMemorySize()\n");
00172 
00173   /* Int 12h
00174    * BIOS - GET MEMORY SIZE
00175    *
00176    * Return:
00177    * AX = kilobytes of contiguous memory starting at absolute address 00000h
00178    *
00179    * This call returns the contents of the word at 0040h:0013h;
00180    * in PC and XT, this value is set from the switches on the motherboard
00181    */
00182   Regs.w.ax = 0;
00183   Int386(0x12, &Regs, &Regs);
00184 
00185   TRACE("Int12h\n");
00186   TRACE("AX = 0x%x\n\n", Regs.w.ax);
00187 
00188   return (ULONG)Regs.w.ax;
00189 }
00190 
00191 static
00192 ULONG
00193 PcMemGetBiosMemoryMap(PFREELDR_MEMORY_DESCRIPTOR MemoryMap, ULONG MaxMemoryMapSize)
00194 {
00195   REGS Regs;
00196   ULONG MapCount = 0;
00197   ULONGLONG RealBaseAddress, RealSize;
00198   TYPE_OF_MEMORY MemoryType;
00199   ASSERT(PcBiosMapCount == 0);
00200 
00201   TRACE("GetBiosMemoryMap()\n");
00202 
00203   /* Int 15h AX=E820h
00204    * Newer BIOSes - GET SYSTEM MEMORY MAP
00205    *
00206    * AX = E820h
00207    * EAX = 0000E820h
00208    * EDX = 534D4150h ('SMAP')
00209    * EBX = continuation value or 00000000h to start at beginning of map
00210    * ECX = size of buffer for result, in bytes (should be >= 20 bytes)
00211    * ES:DI -> buffer for result
00212    * Return:
00213    * CF clear if successful
00214    * EAX = 534D4150h ('SMAP')
00215    * ES:DI buffer filled
00216    * EBX = next offset from which to copy or 00000000h if all done
00217    * ECX = actual length returned in bytes
00218    * CF set on error
00219    * AH = error code (86h)
00220    */
00221   Regs.x.ebx = 0x00000000;
00222 
00223   while (PcBiosMapCount < MAX_BIOS_DESCRIPTORS)
00224     {
00225       /* Setup the registers for the BIOS call */
00226       Regs.x.eax = 0x0000E820;
00227       Regs.x.edx = 0x534D4150; /* ('SMAP') */
00228       /* Regs.x.ebx = 0x00000001;  Continuation value already set */
00229       Regs.x.ecx = sizeof(BIOS_MEMORY_MAP);
00230       Regs.w.es = BIOSCALLBUFSEGMENT;
00231       Regs.w.di = BIOSCALLBUFOFFSET;
00232       Int386(0x15, &Regs, &Regs);
00233 
00234       TRACE("Memory Map Entry %d\n", PcBiosMapCount);
00235       TRACE("Int15h AX=E820h\n");
00236       TRACE("EAX = 0x%x\n", Regs.x.eax);
00237       TRACE("EBX = 0x%x\n", Regs.x.ebx);
00238       TRACE("ECX = 0x%x\n", Regs.x.ecx);
00239       TRACE("CF set = %s\n", (Regs.x.eflags & EFLAGS_CF) ? "TRUE" : "FALSE");
00240 
00241       /* If the BIOS didn't return 'SMAP' in EAX then
00242        * it doesn't support this call. If CF is set, we're done */
00243       if (Regs.x.eax != 0x534D4150 || !INT386_SUCCESS(Regs))
00244         {
00245           break;
00246         }
00247 
00248       /* Copy data to global buffer */
00249       RtlCopyMemory(&PcBiosMemoryMap[PcBiosMapCount], (PVOID)BIOSCALLBUFFER, Regs.x.ecx);
00250 
00251       TRACE("BaseAddress: 0x%llx\n", PcBiosMemoryMap[PcBiosMapCount].BaseAddress);
00252       TRACE("Length: 0x%llx\n", PcBiosMemoryMap[PcBiosMapCount].Length);
00253       TRACE("Type: 0x%lx\n", PcBiosMemoryMap[PcBiosMapCount].Type);
00254       TRACE("Reserved: 0x%lx\n", PcBiosMemoryMap[PcBiosMapCount].Reserved);
00255       TRACE("\n");
00256 
00257       /* Check if this is free memory */
00258       if (PcBiosMemoryMap[PcBiosMapCount].Type == BiosMemoryUsable)
00259       {
00260           MemoryType = LoaderFree;
00261 
00262           /* Align up base of memory area */
00263           RealBaseAddress = PcBiosMemoryMap[PcBiosMapCount].BaseAddress & ~(MM_PAGE_SIZE - 1ULL);
00264 
00265           /* Calculate the length after aligning the base */
00266           RealSize = PcBiosMemoryMap[PcBiosMapCount].BaseAddress +
00267                      PcBiosMemoryMap[PcBiosMapCount].Length - RealBaseAddress;
00268           RealSize = (RealSize + MM_PAGE_SIZE - 1) & ~(MM_PAGE_SIZE - 1ULL);
00269       }
00270       else
00271       {
00272           if (PcBiosMemoryMap[PcBiosMapCount].Type == BiosMemoryReserved)
00273              MemoryType = LoaderFirmwarePermanent;
00274           else
00275              MemoryType = LoaderSpecialMemory;
00276 
00277           /* Align down base of memory area */
00278           RealBaseAddress = PcBiosMemoryMap[PcBiosMapCount].BaseAddress & ~(MM_PAGE_SIZE - 1ULL);
00279           /* Calculate the length after aligning the base */
00280           RealSize = PcBiosMemoryMap[PcBiosMapCount].BaseAddress +
00281                      PcBiosMemoryMap[PcBiosMapCount].Length - RealBaseAddress;
00282           RealSize = (RealSize + MM_PAGE_SIZE - 1) & ~(MM_PAGE_SIZE - 1ULL);
00283       }
00284 
00285       /* Check if we can add this descriptor */
00286       if ((RealSize >= MM_PAGE_SIZE) && (MapCount < MaxMemoryMapSize))
00287       {
00288         /* Add the descriptor */
00289         MapCount = AddMemoryDescriptor(PcMemoryMap,
00290                                        MAX_BIOS_DESCRIPTORS,
00291                                        RealBaseAddress / MM_PAGE_SIZE,
00292                                        RealSize / MM_PAGE_SIZE,
00293                                        MemoryType);
00294       }
00295 
00296       PcBiosMapCount++;
00297 
00298       /* If the continuation value is zero or the
00299        * carry flag is set then this was
00300        * the last entry so we're done */
00301       if (Regs.x.ebx == 0x00000000)
00302         {
00303           TRACE("End Of System Memory Map!\n\n");
00304           break;
00305         }
00306 
00307     }
00308 
00309   return MapCount;
00310 }
00311 
00312 
00313 PFREELDR_MEMORY_DESCRIPTOR
00314 PcMemGetMemoryMap(ULONG *MemoryMapSize)
00315 {
00316   ULONG i, EntryCount;
00317   ULONG ExtendedMemorySizeAtOneMB;
00318   ULONG ExtendedMemorySizeAtSixteenMB;
00319 
00320   EntryCount = PcMemGetBiosMemoryMap(PcMemoryMap, MAX_BIOS_DESCRIPTORS);
00321 
00322   /* If the BIOS didn't provide a memory map, synthesize one */
00323   if (0 == EntryCount)
00324     {
00325       GetExtendedMemoryConfiguration(&ExtendedMemorySizeAtOneMB, &ExtendedMemorySizeAtSixteenMB);
00326 
00327       /* Conventional memory */
00328       AddMemoryDescriptor(PcMemoryMap,
00329                           MAX_BIOS_DESCRIPTORS,
00330                           0,
00331                           PcMemGetConventionalMemorySize() * 1024 / PAGE_SIZE,
00332                           LoaderFree);
00333 
00334       /* Extended memory */
00335       EntryCount = AddMemoryDescriptor(PcMemoryMap,
00336                           MAX_BIOS_DESCRIPTORS,
00337                           1024 * 1024 / PAGE_SIZE,
00338                           ExtendedMemorySizeAtOneMB * 1024 / PAGE_SIZE,
00339                           LoaderFree);
00340 
00341       if (ExtendedMemorySizeAtSixteenMB != 0)
00342       {
00343         /* Extended memory at 16MB */
00344         EntryCount = AddMemoryDescriptor(PcMemoryMap,
00345                           MAX_BIOS_DESCRIPTORS,
00346                           0x1000000 / PAGE_SIZE,
00347                           ExtendedMemorySizeAtSixteenMB * 64 * 1024 / PAGE_SIZE,
00348                           LoaderFree);
00349       }
00350     }
00351 
00352     TRACE("Dumping resulting memory map:\n");
00353     for (i = 0; i < EntryCount; i++)
00354     {
00355         TRACE("BasePage=0x%lx, PageCount=0x%lx, Type=%s\n",
00356               PcMemoryMap[i].BasePage,
00357               PcMemoryMap[i].PageCount,
00358               MmGetSystemMemoryMapTypeString(PcMemoryMap[i].MemoryType));
00359     }
00360 
00361   *MemoryMapSize = EntryCount;
00362 
00363   return PcMemoryMap;
00364 }
00365 
00366 /* EOF */

Generated on Sat May 26 2012 04:17:53 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.