ReactOS  0.4.13-dev-479-gec9c8fd
pxe.c
Go to the documentation of this file.
1 /*
2  * FreeLoader
3  * Copyright (C) 2011 Hervé Poussineau
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 
20 #include <freeldr.h>
21 
22 #include <debug.h>
23 
24 #define TAG_PXE_FILE 'FexP'
25 #define NO_FILE ((ULONG)-1)
26 
27 DBG_DEFAULT_CHANNEL(FILESYSTEM);
28 
29 static IP4 _ServerIP = { 0, };
31 static CHAR _OpenFileName[128];
32 static ULONG _FileSize = 0;
33 static ULONG _FilePosition = 0;
35 static UCHAR _Packet[1024]; // Should be a value which can be transferred well in one packet over the network
37 static ULONG _CachedLength = 0;
38 
39 static PPXE
41 {
42  PPXE Ptr;
43  UCHAR Checksum;
44  UCHAR i;
45 
46  /* Find the '!PXE' structure */
47  Ptr = (PPXE)0xA0000;
48  while ((ULONG_PTR)Ptr > 0x10000)
49  {
50  Ptr = (PPXE)((ULONG_PTR)Ptr - 0x10);
51 
52  /* Look for signature */
53  if (memcmp(Ptr, "!PXE", 4) != 0)
54  continue;
55 
56  /* Check size */
57  if (Ptr->StructLength != sizeof(PXE))
58  continue;
59 
60  /* Check checksum */
61  Checksum = 0;
62  for (i = 0; i < Ptr->StructLength; i++)
63  Checksum += *((PUCHAR)Ptr + i);
64  if (Checksum != 0)
65  continue;
66 
67  TRACE("!PXE structure found at %p\n", Ptr);
68  return Ptr;
69  }
70 
71  return NULL;
72 }
73 
75 {
76  static PPXE pPxe = NULL;
77  static BOOLEAN bPxeSearched = FALSE;
78  if (!bPxeSearched)
79  {
80  pPxe = FindPxeStructure();
81  bPxeSearched = TRUE;
82  }
83  return pPxe;
84 }
85 
88 {
89  PPXE pxe;
91 
92  pxe = GetPxeStructure();
93  if (!pxe)
94  return FALSE;
95 
96  if (Service != PXENV_TFTP_READ)
97  {
98  // HACK: this delay shouldn't be necessary
99  KeStallExecutionProcessor(100 * 1000); // 100 ms
100  TRACE("PxeCall(0x%x, %p)\n", Service, Parameter);
101  }
102 
104  if (exit != PXENV_EXIT_SUCCESS)
105  {
106  ERR("PxeCall(0x%x, %p) failed with exit=%d status=0x%x\n",
108  return FALSE;
109  }
111  {
112  ERR("PxeCall(0x%x, %p) succeeded, but returned error status 0x%x\n",
114  return FALSE;
115  }
116  return TRUE;
117 }
118 
119 static ARC_STATUS PxeClose(ULONG FileId)
120 {
121  t_PXENV_TFTP_CLOSE closeData;
122 
123  if (_OpenFile == NO_FILE || FileId != _OpenFile)
124  return EBADF;
125 
126  RtlZeroMemory(&closeData, sizeof(closeData));
127  if (!CallPxe(PXENV_TFTP_CLOSE, &closeData))
128  return EIO;
129 
130  _OpenFile = NO_FILE;
131  if (_CachedFile)
132  {
134  _CachedFile = NULL;
135  }
136  return ESUCCESS;
137 }
138 
140 {
141  if (_OpenFile == NO_FILE || FileId != _OpenFile)
142  return EBADF;
143 
145  Information->EndingAddress.LowPart = _FileSize;
146  Information->CurrentAddress.LowPart = _FilePosition;
147 
148  return ESUCCESS;
149 }
150 
151 static ARC_STATUS PxeOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
152 {
153  t_PXENV_TFTP_GET_FSIZE sizeData;
154  t_PXENV_TFTP_OPEN openData;
155  SIZE_T PathLen, i;
156 
157  if (_OpenFile != NO_FILE)
158  return EIO;
159  if (OpenMode != OpenReadOnly)
160  return EACCES;
161 
162  /* Retrieve the path length without NULL terminator */
163  PathLen = (Path ? min(strlen(Path), sizeof(_OpenFileName) - 1) : 0);
164 
165  /* Lowercase the path and always use slashes as separators */
166  for (i = 0; i < PathLen; i++)
167  {
168  if (Path[i] == '\\')
169  _OpenFileName[i] = '/';
170  else
172  }
173 
174  /* Zero out rest of the file name */
175  RtlZeroMemory(_OpenFileName + PathLen, sizeof(_OpenFileName) - PathLen);
176 
177  RtlZeroMemory(&sizeData, sizeof(sizeData));
178  sizeData.ServerIPAddress = _ServerIP;
180  if (!CallPxe(PXENV_TFTP_GET_FSIZE, &sizeData))
181  {
182  ERR("Failed to get '%s' size\n", Path);
183  return EIO;
184  }
185 
186  _FileSize = sizeData.FileSize;
187  if (_FileSize < 1024 * 1024)
188  {
190  // Don't check for allocation failure, we support _CachedFile == NULL
191  }
192  _CachedLength = 0;
193 
194  RtlZeroMemory(&openData, sizeof(openData));
195  openData.ServerIPAddress = _ServerIP;
197  openData.PacketSize = sizeof(_Packet);
198 
199  if (!CallPxe(PXENV_TFTP_OPEN, &openData))
200  {
201  if (_CachedFile)
202  {
204  _CachedFile = NULL;
205  }
206  return ENOENT;
207  }
208 
209  _FilePosition = 0;
210  _PacketPosition = 0;
211 
212  _OpenFile = *FileId;
213  return ESUCCESS;
214 }
215 
217 {
218  t_PXENV_TFTP_READ readData;
219  ULONG i;
220 
221  *Count = 0;
222 
223  if (_OpenFile == NO_FILE || FileId != _OpenFile)
224  return EBADF;
225 
226  RtlZeroMemory(&readData, sizeof(readData));
227  readData.Buffer.segment = ((ULONG_PTR)_Packet & 0xf0000) / 16;
228  readData.Buffer.offset = (ULONG_PTR)_Packet & 0xffff;
229 
230  // Get new packets as required
231  while (N > 0)
232  {
233  if (N < _CachedLength - _FilePosition)
234  i = N;
235  else
237  if (_CachedFile)
239  else
241  _FilePosition += i;
242  Buffer = (UCHAR*)Buffer + i;
243  *Count += i;
244  N -= i;
245  if (N == 0)
246  break;
247 
248  if (!CallPxe(PXENV_TFTP_READ, &readData))
249  return EIO;
250  if (_CachedFile)
253  _CachedLength += readData.BufferSize;
254  }
255 
256  return ESUCCESS;
257 }
258 
260 {
261  t_PXENV_TFTP_READ readData;
262 
263  if (_OpenFile == NO_FILE || FileId != _OpenFile)
264  return EBADF;
265 
266  if (Position->HighPart != 0 || SeekMode != SeekAbsolute)
267  return EINVAL;
268 
269  if (!_CachedFile && Position->LowPart < _FilePosition)
270  {
271  // Close and reopen the file to go to position 0
272  if (PxeClose(FileId) != ESUCCESS)
273  return EIO;
274  if (PxeOpen(_OpenFileName, OpenReadOnly, &FileId) != ESUCCESS)
275  return EIO;
276  }
277 
278  RtlZeroMemory(&readData, sizeof(readData));
279  readData.Buffer.segment = ((ULONG_PTR)_Packet & 0xf0000) / 16;
280  readData.Buffer.offset = (ULONG_PTR)_Packet & 0xffff;
281 
282  // Get new packets as required
283  while (Position->LowPart > _CachedLength)
284  {
285  if (!CallPxe(PXENV_TFTP_READ, &readData))
286  return EIO;
287  if (_CachedFile)
288  {
290  }
292  _CachedLength += readData.BufferSize;
293  }
294 
295  _FilePosition = Position->LowPart;
296  return ESUCCESS;
297 }
298 
299 static const DEVVTBL PxeVtbl = {
300  PxeClose,
302  PxeOpen,
303  PxeRead,
304  PxeSeek,
305 };
306 
307 const DEVVTBL* PxeMount(ULONG DeviceId)
308 {
309  if (GetPxeStructure() == NULL)
310  return NULL;
311  return &PxeVtbl;
312 }
313 
315 {
316  // Nothing to do
317  return ESUCCESS;
318 }
319 
321 {
322  // No disk access in PXE mode
323  return EINVAL;
324 }
325 
326 static ARC_STATUS PxeDiskOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
327 {
328  // Nothing to do
329  return ESUCCESS;
330 }
331 
333 {
334  // No disk access in PXE mode
335  return EINVAL;
336 }
337 
339 {
340  // No disk access in PXE mode
341  return EINVAL;
342 }
343 
344 static const DEVVTBL PxeDiskVtbl = {
345  PxeDiskClose,
347  PxeDiskOpen,
348  PxeDiskRead,
349  PxeDiskSeek,
350 };
351 
353 {
355  BOOLEAN res;
356  UCHAR* Packet;
357 
358  RtlZeroMemory(&Data, sizeof(Data));
360 
362  if (!res)
363  return FALSE;
364  if (Data.BufferSize < 36)
365  return FALSE;
366  Packet = (UCHAR*)((ULONG_PTR)(Data.Buffer.segment << 4) + Data.Buffer.offset);
367  RtlCopyMemory(&_ServerIP, Packet + 20, sizeof(IP4));
368  return TRUE;
369 }
370 
372 {
373  static BOOLEAN Initialized = FALSE;
374  static BOOLEAN Success = FALSE;
375 
376  // Do initialization only once
377  if (Initialized)
378  return Success;
379  Initialized = TRUE;
380 
381  // Check if PXE is available
382  if (GetPxeStructure() && GetCachedInfo())
383  {
384  FsRegisterDevice("net(0)", &PxeDiskVtbl);
385  Success = TRUE;
386  }
387 
388  return Success;
389 }
390 
SEGOFF16 EntryPointSP
Definition: pxe.h:47
static ULONG _CachedLength
Definition: pxe.c:37
#define PXENV_TFTP_GET_FSIZE
Definition: pxe.h:591
static ARC_STATUS PxeSeek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
Definition: pxe.c:259
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
_In_ NDIS_HANDLE _In_ PNDIS_PACKET Packet
Definition: ndis.h:1548
Definition: pxe.h:16
#define __cdecl
Definition: accygwin.h:79
#define TAG_PXE_FILE
Definition: pxe.c:24
#define PXENV_PACKET_TYPE_CACHED_REPLY
Definition: pxe.h:403
Definition: arc.h:32
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
DBG_DEFAULT_CHANNEL(FILESYSTEM)
static const DEVVTBL PxeVtbl
Definition: pxe.c:299
Definition: arc.h:39
static COORD Position
Definition: mouse.c:34
unsigned char * PUCHAR
Definition: retypes.h:3
char CHAR
Definition: xmlstorage.h:175
_Must_inspect_result_ _In_ PFSRTL_PER_STREAM_CONTEXT Ptr
Definition: fsrtlfuncs.h:898
Definition: fs.h:22
const DEVVTBL * PxeMount(ULONG DeviceId)
Definition: pxe.c:307
static ARC_STATUS PxeRead(ULONG FileId, VOID *Buffer, ULONG N, ULONG *Count)
Definition: pxe.c:216
_Inout_ __drv_aliasesMem PSLIST_ENTRY _Inout_ PSLIST_ENTRY _In_ ULONG Count
Definition: exfuncs.h:1015
static ULONG _OpenFile
Definition: pxe.c:30
static ULONG _PacketPosition
Definition: pxe.c:34
static const DEVVTBL PxeDiskVtbl
Definition: pxe.c:344
ULONG ARC_STATUS
Definition: arc.h:4
static ARC_STATUS PxeDiskSeek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
Definition: pxe.c:338
_In_ PVOID Parameter
Definition: ldrtypes.h:240
static ARC_STATUS PxeDiskGetFileInformation(ULONG FileId, FILEINFORMATION *Information)
Definition: pxe.c:320
static BOOLEAN GetCachedInfo(VOID)
Definition: pxe.c:352
Definition: arc.h:36
static ULONG _FilePosition
Definition: pxe.c:33
#define PXENV_GET_CACHED_INFO
Definition: pxe.h:597
BOOLEAN PxeInit(VOID)
Definition: pxe.c:371
OFF16 offset
Definition: pxe.h:34
uint32_t ULONG_PTR
Definition: typedefs.h:63
UINT16 BufferSize
Definition: pxe.h:330
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
static UCHAR * _CachedFile
Definition: pxe.c:36
UINT8 FileName[128]
Definition: pxe.h:354
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
static CHAR _OpenFileName[128]
Definition: pxe.c:31
#define PXENV_TFTP_OPEN
Definition: pxe.h:587
FORCEINLINE PVOID FrLdrTempAlloc(_In_ SIZE_T Size, _In_ ULONG Tag)
Definition: mm.h:177
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
#define PXENV_TFTP_CLOSE
Definition: pxe.h:588
SEGOFF16 Buffer
Definition: pxe.h:331
static ARC_STATUS PxeClose(ULONG FileId)
Definition: pxe.c:119
_In_ LPGUID _In_ PVOID Data
Definition: classpnp.h:778
enum _SEEKMODE SEEKMODE
Definition: bufpool.h:45
#define PXENV_EXIT_SUCCESS
Definition: pxe.h:457
IP4 ServerIPAddress
Definition: pxe.h:314
_Inout_ PVOID Segment
Definition: exfuncs.h:893
static ARC_STATUS PxeDiskRead(ULONG FileId, VOID *Buffer, ULONG N, ULONG *Count)
Definition: pxe.c:332
UINT8 FileName[128]
Definition: pxe.h:316
#define TRACE(s)
Definition: solgame.cpp:4
static UCHAR _Packet[1024]
Definition: pxe.c:35
#define NO_FILE
Definition: pxe.c:25
static ARC_STATUS PxeDiskOpen(CHAR *Path, OPENMODE OpenMode, ULONG *FileId)
Definition: pxe.c:326
unsigned char UCHAR
Definition: xmlstorage.h:181
Definition: arc.h:34
VOID FsRegisterDevice(CHAR *Prefix, const DEVVTBL *FuncTable)
Definition: fs.c:441
SEGSEL segment
Definition: pxe.h:35
UINT16 PacketSize
Definition: pxe.h:318
static ARC_STATUS PxeDiskClose(ULONG FileId)
Definition: pxe.c:314
Definition: pxe.h:38
UINT16 PXENV_EXIT
Definition: pxe.h:7
#define ERR(fmt,...)
Definition: debug.h:109
ULONG_PTR SIZE_T
Definition: typedefs.h:78
BOOLEAN CallPxe(UINT16 Service, PVOID Parameter)
Definition: pxe.c:87
PRTL_UNICODE_STRING_BUFFER Path
static ULONG _FileSize
Definition: pxe.c:32
#define PXENV_TFTP_READ
Definition: pxe.h:589
#define PXENV_STATUS_SUCCESS
Definition: pxe.h:461
static ARC_STATUS PxeGetFileInformation(ULONG FileId, FILEINFORMATION *Information)
Definition: pxe.c:139
unsigned short UINT16
#define min(a, b)
Definition: monoChain.cc:55
Definition: arc.h:46
Definition: arc.h:40
static PPXE FindPxeStructure(VOID)
Definition: pxe.c:40
struct s_PXE * PPXE
GLuint res
Definition: glext.h:9613
unsigned int ULONG
Definition: retypes.h:1
PXENV_EXIT __cdecl PxeCallApi(UINT16 Segment, UINT16 Offset, UINT16 Service, VOID *Parameter)
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define ULONG_PTR
Definition: config.h:101
UINT16 PXENV_STATUS
Definition: pxe.h:8
static ARC_STATUS PxeOpen(CHAR *Path, OPENMODE OpenMode, ULONG *FileId)
Definition: pxe.c:151
void exit(int exitcode)
Definition: _exit.c:33
enum _OPENMODE OPENMODE
int tolower(int c)
Definition: utclib.c:902
VOID NTAPI KeStallExecutionProcessor(IN ULONG MicroSeconds)
Definition: ntoskrnl.c:99
Iosb Information
Definition: create.c:4377
static PPXE GetPxeStructure(VOID)
Definition: pxe.c:74
static IP4 _ServerIP
Definition: pxe.c:29
FORCEINLINE VOID FrLdrTempFree(PVOID Allocation, ULONG Tag)
Definition: mm.h:186