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

pxe.c
Go to the documentation of this file.
00001 /*
00002  *  FreeLoader
00003  *  Copyright (C) 2011  Hervé Poussineau
00004  *
00005  *  This program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2 of the License, or
00008  *  (at your option) any later version.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018  */
00019 
00020 #include <freeldr.h>
00021 
00022 #define NDEBUG
00023 #include <debug.h>
00024 
00025 #define NO_FILE ((ULONG)-1)
00026 
00027 DBG_DEFAULT_CHANNEL(FILESYSTEM);
00028 
00029 static IP4 _ServerIP = { 0, };
00030 static ULONG _OpenFile = NO_FILE;
00031 static ULONG _FileSize = 0;
00032 static ULONG _FilePosition = 0;
00033 static ULONG _PacketPosition = 0;
00034 static UCHAR _Packet[4096];
00035 static UCHAR* _CachedFile = NULL;
00036 static ULONG _CachedLength = 0;
00037 
00038 static PPXE
00039 FindPxeStructure(VOID)
00040 {
00041     PPXE Ptr;
00042     UCHAR Checksum;
00043     UCHAR i;
00044 
00045     /* Find the '!PXE' structure */
00046     Ptr = (PPXE)0xA0000;
00047     while ((ULONG)Ptr > 0x10000)
00048     {
00049         Ptr = (PPXE)((ULONG)Ptr - 0x10);
00050 
00051         /* Look for signature */
00052         if (memcmp(Ptr, "!PXE", 4) != 0)
00053             continue;
00054 
00055         /* Check size */
00056         if (Ptr->StructLength != sizeof(PXE))
00057             continue;
00058 
00059         /* Check checksum */
00060         Checksum = 0;
00061         for (i = 0; i < Ptr->StructLength; i++)
00062             Checksum += *((PUCHAR)Ptr + i);
00063         if (Checksum != 0)
00064             continue;
00065 
00066         TRACE("!PXE structure found at %p\n", Ptr);
00067         return Ptr;
00068     }
00069 
00070     return NULL;
00071 }
00072 
00073 static PPXE GetPxeStructure(VOID)
00074 {
00075     static PPXE pPxe = NULL;
00076     static BOOLEAN bPxeSearched = FALSE;
00077     if (!bPxeSearched)
00078     {
00079         pPxe = FindPxeStructure();
00080         bPxeSearched = TRUE;
00081     }
00082     return pPxe;
00083 }
00084 
00085 extern PXENV_EXIT PxeCallApi(UINT16 Segment, UINT16 Offset, UINT16 Service, VOID *Parameter);
00086 BOOLEAN CallPxe(UINT16 Service, PVOID Parameter)
00087 {
00088     PPXE pxe;
00089     PXENV_EXIT exit;
00090 
00091     pxe = GetPxeStructure();
00092     if (!pxe)
00093         return FALSE;
00094 
00095     if (Service != PXENV_TFTP_READ)
00096     {
00097         // HACK: this delay shouldn't be necessary
00098         KeStallExecutionProcessor(100 * 1000); // 100 ms
00099         TRACE("PxeCall(0x%x, %p)\n", Service, Parameter);
00100     }
00101 
00102     exit = PxeCallApi(pxe->EntryPointSP.segment, pxe->EntryPointSP.offset, Service, Parameter);
00103     if (exit != PXENV_EXIT_SUCCESS)
00104     {
00105         ERR("PxeCall(0x%x, %p) failed with exit=%d status=0x%x\n",
00106                 Service, Parameter, exit, *(PXENV_STATUS*)Parameter);
00107         return FALSE;
00108     }
00109     if (*(PXENV_STATUS*)Parameter != PXENV_STATUS_SUCCESS)
00110     {
00111         ERR("PxeCall(0x%x, %p) succeeded, but returned error status 0x%x\n",
00112                 Service, Parameter, *(PXENV_STATUS*)Parameter);
00113         return FALSE;
00114     }
00115     return TRUE;
00116 }
00117 
00118 static LONG PxeClose(ULONG FileId)
00119 {
00120     t_PXENV_TFTP_CLOSE closeData;
00121 
00122     if (_OpenFile == NO_FILE || FileId != _OpenFile)
00123         return EBADF;
00124 
00125     RtlZeroMemory(&closeData, sizeof(closeData));
00126     if (!CallPxe(PXENV_TFTP_CLOSE, &closeData))
00127         return EIO;
00128 
00129     _OpenFile = NO_FILE;
00130     if (_CachedFile)
00131     {
00132         MmHeapFree(_CachedFile);
00133         _CachedFile = NULL;
00134     }
00135     return ESUCCESS;
00136 }
00137 
00138 static LONG PxeGetFileInformation(ULONG FileId, FILEINFORMATION* Information)
00139 {
00140     if (_OpenFile == NO_FILE || FileId != _OpenFile)
00141         return EBADF;
00142 
00143     RtlZeroMemory(Information, sizeof(FILEINFORMATION));
00144     Information->EndingAddress.LowPart = _FileSize;
00145     Information->CurrentAddress.LowPart = _FilePosition;
00146 
00147     return ESUCCESS;
00148 }
00149 
00150 static LONG PxeOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
00151 {
00152     t_PXENV_TFTP_GET_FSIZE sizeData;
00153     t_PXENV_TFTP_OPEN openData;
00154 
00155     if (_OpenFile != NO_FILE)
00156         return EIO;
00157     if (OpenMode != OpenReadOnly)
00158         return EACCES;
00159 
00160     RtlZeroMemory(&sizeData, sizeof(sizeData));
00161     sizeData.ServerIPAddress = _ServerIP;
00162     strncpy((CHAR*)sizeData.FileName, Path, sizeof(sizeData.FileName));
00163     if (!CallPxe(PXENV_TFTP_GET_FSIZE, &sizeData))
00164         return EIO;
00165     _FileSize = sizeData.FileSize;
00166     if (_FileSize < 1024 * 1024)
00167     {
00168         _CachedFile = MmHeapAlloc(_FileSize);
00169         // Don't check for allocation failure, we support _CachedFile = NULL
00170     }
00171     _CachedLength = 0;
00172 
00173     RtlZeroMemory(&openData, sizeof(openData));
00174     openData.ServerIPAddress = _ServerIP;
00175     strncpy((CHAR*)openData.FileName, Path, sizeof(openData.FileName));
00176     openData.PacketSize = sizeof(_Packet);
00177 
00178     if (!CallPxe(PXENV_TFTP_OPEN, &openData))
00179     {
00180         if (_CachedFile)
00181         {
00182             MmHeapFree(_CachedFile);
00183             _CachedFile = NULL;
00184         }
00185         return ENOENT;
00186     }
00187 
00188     _FilePosition = 0;
00189     _PacketPosition = 0;
00190 
00191     _OpenFile = *FileId;
00192     return ESUCCESS;
00193 }
00194 
00195 static LONG PxeRead(ULONG FileId, VOID* Buffer, ULONG N, ULONG* Count)
00196 {
00197     t_PXENV_TFTP_READ readData;
00198     ULONG i;
00199 
00200     *Count = 0;
00201 
00202     if (_OpenFile == NO_FILE || FileId != _OpenFile)
00203         return EBADF;
00204 
00205     RtlZeroMemory(&readData, sizeof(readData));
00206     readData.Buffer.segment = ((UINT32)_Packet & 0xf0000) / 16;
00207     readData.Buffer.offset = (UINT32)_Packet & 0xffff;
00208 
00209     // Get new packets as required
00210     while (N > 0)
00211     {
00212         if (N < _CachedLength - _FilePosition)
00213             i = N;
00214         else
00215             i = _CachedLength - _FilePosition;
00216         if (_CachedFile)
00217             RtlCopyMemory(Buffer, _CachedFile + _FilePosition, i);
00218         else
00219             RtlCopyMemory(Buffer, _Packet + _FilePosition - _PacketPosition, i);
00220         _FilePosition += i;
00221         Buffer = (UCHAR*)Buffer + i;
00222         *Count += i;
00223         N -= i;
00224         if (N == 0)
00225             break;
00226 
00227         if (!CallPxe(PXENV_TFTP_READ, &readData))
00228             return EIO;
00229         if (_CachedFile)
00230             RtlCopyMemory(_CachedFile + _CachedLength, _Packet, readData.BufferSize);
00231         _PacketPosition = _CachedLength;
00232         _CachedLength += readData.BufferSize;
00233     }
00234 
00235     return ESUCCESS;
00236 }
00237 
00238 static LONG PxeSeek(ULONG FileId, LARGE_INTEGER* Position, SEEKMODE SeekMode)
00239 {
00240     t_PXENV_TFTP_READ readData;
00241 
00242     if (_OpenFile == NO_FILE || FileId != _OpenFile)
00243         return EBADF;
00244 
00245     if (Position->HighPart != 0 || SeekMode != SeekAbsolute)
00246         return EINVAL;
00247 
00248     if (!_CachedFile && Position->LowPart < _FilePosition)
00249         // We don't support backward seek without caching
00250         return EINVAL;
00251 
00252     RtlZeroMemory(&readData, sizeof(readData));
00253     readData.Buffer.segment = ((UINT32)_Packet & 0xf0000) / 16;
00254     readData.Buffer.offset = (UINT32)_Packet & 0xffff;
00255 
00256     // Get new packets as required
00257     while (Position->LowPart > _CachedLength)
00258     {
00259         if (!CallPxe(PXENV_TFTP_READ, &readData))
00260             return EIO;
00261         if (_CachedFile)
00262         {
00263             RtlCopyMemory(_CachedFile + _CachedLength, _Packet, readData.BufferSize);
00264         }
00265         _PacketPosition = _CachedLength;
00266         _CachedLength += readData.BufferSize;
00267     }
00268 
00269     _FilePosition = Position->LowPart;
00270     return ESUCCESS;
00271 }
00272 
00273 static const DEVVTBL PxeVtbl = {
00274     PxeClose,
00275     PxeGetFileInformation,
00276     PxeOpen,
00277     PxeRead,
00278     PxeSeek,
00279 };
00280 
00281 const DEVVTBL* PxeMount(ULONG DeviceId)
00282 {
00283     if (GetPxeStructure() == NULL)
00284         return NULL;
00285     return &PxeVtbl;
00286 }
00287 
00288 static LONG PxeDiskClose(ULONG FileId)
00289 {
00290     // Nothing to do
00291     return ESUCCESS;
00292 }
00293 
00294 static LONG PxeDiskGetFileInformation(ULONG FileId, FILEINFORMATION* Information)
00295 {
00296     // No disk access in PXE mode
00297     return EINVAL;
00298 }
00299 
00300 static LONG PxeDiskOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
00301 {
00302     // Nothing to do
00303     return ESUCCESS;
00304 }
00305 
00306 static LONG PxeDiskRead(ULONG FileId, VOID* Buffer, ULONG N, ULONG* Count)
00307 {
00308     // No disk access in PXE mode
00309     return EINVAL;
00310 }
00311 
00312 static LONG PxeDiskSeek(ULONG FileId, LARGE_INTEGER* Position, SEEKMODE SeekMode)
00313 {
00314     // No disk access in PXE mode
00315     return EINVAL;
00316 }
00317 
00318 static const DEVVTBL PxeDiskVtbl = {
00319     PxeDiskClose,
00320     PxeDiskGetFileInformation,
00321     PxeDiskOpen,
00322     PxeDiskRead,
00323     PxeDiskSeek,
00324 };
00325 
00326 static BOOLEAN GetCachedInfo(VOID)
00327 {
00328     t_PXENV_GET_CACHED_INFO Data;
00329     BOOLEAN res;
00330     UCHAR* Packet;
00331 
00332     RtlZeroMemory(&Data, sizeof(Data));
00333     Data.PacketType = PXENV_PACKET_TYPE_CACHED_REPLY;
00334 
00335     res = CallPxe(PXENV_GET_CACHED_INFO, &Data);
00336     if (!res)
00337         return FALSE;
00338     if (Data.BufferSize < 36)
00339         return FALSE;
00340     Packet = (UCHAR*)((UINT32)(Data.Buffer.segment << 4) + Data.Buffer.offset);
00341     RtlCopyMemory(&_ServerIP, Packet + 20, sizeof(IP4));
00342     return TRUE;
00343 }
00344 
00345 BOOLEAN PxeInit(VOID)
00346 {
00347     static BOOLEAN Initialized = FALSE;
00348     static BOOLEAN Status = FALSE;
00349 
00350     // Do initialization only once
00351     if (Initialized)
00352         return Status;
00353     Initialized = TRUE;
00354 
00355     // Check if PXE is available
00356     if (GetPxeStructure() && GetCachedInfo())
00357     {
00358         FsRegisterDevice("net(0)", &PxeDiskVtbl);
00359         Status = TRUE;
00360     }
00361 
00362     return Status;
00363 }
00364 

Generated on Sun May 27 2012 04:19:13 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.