ReactOS  0.4.14-dev-98-gb0d4763
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 DBG_DEFAULT_CHANNEL(FILESYSTEM);
24 
25 #define TAG_PXE_FILE 'FexP'
26 #define NO_FILE ((ULONG)-1)
27 
28 static IP4 _ServerIP = { 0, };
30 static CHAR _OpenFileName[128];
31 static ULONG _FileSize = 0;
32 static ULONG _FilePosition = 0;
34 static UCHAR _Packet[1024]; // Should be a value which can be transferred well in one packet over the network
36 static ULONG _CachedLength = 0;
37 
38 static PPXE
40 {
41  PPXE Ptr;
42  UCHAR Checksum;
43  UCHAR i;
44 
45  /* Find the '!PXE' structure */
46  Ptr = (PPXE)0xA0000;
47  while ((ULONG_PTR)Ptr > 0x10000)
48  {
49  Ptr = (PPXE)((ULONG_PTR)Ptr - 0x10);
50 
51  /* Look for signature */
52  if (memcmp(Ptr, "!PXE", 4) != 0)
53  continue;
54 
55  /* Check size */
56  if (Ptr->StructLength != sizeof(PXE))
57  continue;
58 
59  /* Check checksum */
60  Checksum = 0;
61  for (i = 0; i < Ptr->StructLength; i++)
62  Checksum += *((PUCHAR)Ptr + i);
63  if (Checksum != 0)
64  continue;
65 
66  TRACE("!PXE structure found at %p\n", Ptr);
67  return Ptr;
68  }
69 
70  return NULL;
71 }
72 
74 {
75  static PPXE pPxe = NULL;
76  static BOOLEAN bPxeSearched = FALSE;
77  if (!bPxeSearched)
78  {
79  pPxe = FindPxeStructure();
80  bPxeSearched = TRUE;
81  }
82  return pPxe;
83 }
84 
87 {
88  PPXE pxe;
90 
91  pxe = GetPxeStructure();
92  if (!pxe)
93  return FALSE;
94 
95  if (Service != PXENV_TFTP_READ)
96  {
97  // HACK: this delay shouldn't be necessary
98  KeStallExecutionProcessor(100 * 1000); // 100 ms
99  TRACE("PxeCall(0x%x, %p)\n", Service, Parameter);
100  }
101 
103  if (exit != PXENV_EXIT_SUCCESS)
104  {
105  ERR("PxeCall(0x%x, %p) failed with exit=%d status=0x%x\n",
107  return FALSE;
108  }
110  {
111  ERR("PxeCall(0x%x, %p) succeeded, but returned error status 0x%x\n",
113  return FALSE;
114  }
115  return TRUE;
116 }
117 
118 static ARC_STATUS PxeClose(ULONG FileId)
119 {
120  t_PXENV_TFTP_CLOSE closeData;
121 
122  if (_OpenFile == NO_FILE || FileId != _OpenFile)
123  return EBADF;
124 
125  RtlZeroMemory(&closeData, sizeof(closeData));
126  if (!CallPxe(PXENV_TFTP_CLOSE, &closeData))
127  return EIO;
128 
129  _OpenFile = NO_FILE;
130  if (_CachedFile)
131  {
133  _CachedFile = NULL;
134  }
135  return ESUCCESS;
136 }
137 
139 {
140  if (_OpenFile == NO_FILE || FileId != _OpenFile)
141  return EBADF;
142 
144  Information->EndingAddress.LowPart = _FileSize;
145  Information->CurrentAddress.LowPart = _FilePosition;
146 
147  TRACE("PxeGetFileInformation(%lu) -> FileSize = %lu, FilePointer = 0x%lx\n",
148  FileId, Information->EndingAddress.LowPart, Information->CurrentAddress.LowPart);
149 
150  return ESUCCESS;
151 }
152 
153 static ARC_STATUS PxeOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
154 {
155  t_PXENV_TFTP_GET_FSIZE sizeData;
156  t_PXENV_TFTP_OPEN openData;
157  SIZE_T PathLen, i;
158 
159  if (_OpenFile != NO_FILE)
160  return EIO;
161  if (OpenMode != OpenReadOnly)
162  return EACCES;
163 
164  /* Retrieve the path length without NULL terminator */
165  PathLen = (Path ? min(strlen(Path), sizeof(_OpenFileName) - 1) : 0);
166 
167  /* Lowercase the path and always use slashes as separators */
168  for (i = 0; i < PathLen; i++)
169  {
170  if (Path[i] == '\\')
171  _OpenFileName[i] = '/';
172  else
174  }
175 
176  /* Zero out rest of the file name */
177  RtlZeroMemory(_OpenFileName + PathLen, sizeof(_OpenFileName) - PathLen);
178 
179  RtlZeroMemory(&sizeData, sizeof(sizeData));
180  sizeData.ServerIPAddress = _ServerIP;
182  if (!CallPxe(PXENV_TFTP_GET_FSIZE, &sizeData))
183  {
184  ERR("Failed to get '%s' size\n", Path);
185  return EIO;
186  }
187 
188  _FileSize = sizeData.FileSize;
189  if (_FileSize < 1024 * 1024)
190  {
192  // Don't check for allocation failure, we support _CachedFile == NULL
193  }
194  _CachedLength = 0;
195 
196  RtlZeroMemory(&openData, sizeof(openData));
197  openData.ServerIPAddress = _ServerIP;
199  openData.PacketSize = sizeof(_Packet);
200 
201  if (!CallPxe(PXENV_TFTP_OPEN, &openData))
202  {
203  if (_CachedFile)
204  {
206  _CachedFile = NULL;
207  }
208  return ENOENT;
209  }
210 
211  _FilePosition = 0;
212  _PacketPosition = 0;
213 
214  _OpenFile = *FileId;
215  return ESUCCESS;
216 }
217 
219 {
220  t_PXENV_TFTP_READ readData;
221  ULONG i;
222 
223  *Count = 0;
224 
225  if (_OpenFile == NO_FILE || FileId != _OpenFile)
226  return EBADF;
227 
228  RtlZeroMemory(&readData, sizeof(readData));
229  readData.Buffer.segment = ((ULONG_PTR)_Packet & 0xf0000) / 16;
230  readData.Buffer.offset = (ULONG_PTR)_Packet & 0xffff;
231 
232  // Get new packets as required
233  while (N > 0)
234  {
235  if (N < _CachedLength - _FilePosition)
236  i = N;
237  else
239  if (_CachedFile)
241  else
243  _FilePosition += i;
244  Buffer = (UCHAR*)Buffer + i;
245  *Count += i;
246  N -= i;
247  if (N == 0)
248  break;
249 
250  if (!CallPxe(PXENV_TFTP_READ, &readData))
251  return EIO;
252  if (_CachedFile)
255  _CachedLength += readData.BufferSize;
256  }
257 
258  return ESUCCESS;
259 }
260 
262 {
263  t_PXENV_TFTP_READ readData;
264 
265  if (_OpenFile == NO_FILE || FileId != _OpenFile)
266  return EBADF;
267 
268  if (Position->HighPart != 0 || SeekMode != SeekAbsolute)
269  return EINVAL;
270 
271  if (!_CachedFile && Position->LowPart < _FilePosition)
272  {
273  // Close and reopen the file to go to position 0
274  if (PxeClose(FileId) != ESUCCESS)
275  return EIO;
276  if (PxeOpen(_OpenFileName, OpenReadOnly, &FileId) != ESUCCESS)
277  return EIO;
278  }
279 
280  RtlZeroMemory(&readData, sizeof(readData));
281  readData.Buffer.segment = ((ULONG_PTR)_Packet & 0xf0000) / 16;
282  readData.Buffer.offset = (ULONG_PTR)_Packet & 0xffff;
283 
284  // Get new packets as required
285  while (Position->LowPart > _CachedLength)
286  {
287  if (!CallPxe(PXENV_TFTP_READ, &readData))
288  return EIO;
289  if (_CachedFile)
290  {
292  }
294  _CachedLength += readData.BufferSize;
295  }
296 
297  _FilePosition = Position->LowPart;
298  return ESUCCESS;
299 }
300 
301 static const DEVVTBL PxeVtbl = {
302  PxeClose,
304  PxeOpen,
305  PxeRead,
306  PxeSeek,
307 };
308 
309 const DEVVTBL* PxeMount(ULONG DeviceId)
310 {
311  if (GetPxeStructure() == NULL)
312  return NULL;
313  return &PxeVtbl;
314 }
315 
317 {
318  // Nothing to do
319  return ESUCCESS;
320 }
321 
323 {
324  // No disk access in PXE mode
325  return EINVAL;
326 }
327 
328 static ARC_STATUS PxeDiskOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
329 {
330  // Nothing to do
331  return ESUCCESS;
332 }
333 
335 {
336  // No disk access in PXE mode
337  return EINVAL;
338 }
339 
341 {
342  // No disk access in PXE mode
343  return EINVAL;
344 }
345 
346 static const DEVVTBL PxeDiskVtbl = {
347  PxeDiskClose,
349  PxeDiskOpen,
350  PxeDiskRead,
351  PxeDiskSeek,
352 };
353 
355 {
357  BOOLEAN res;
358  UCHAR* Packet;
359 
360  RtlZeroMemory(&Data, sizeof(Data));
362 
364  if (!res)
365  return FALSE;
366  if (Data.BufferSize < 36)
367  return FALSE;
368  Packet = (UCHAR*)((ULONG_PTR)(Data.Buffer.segment << 4) + Data.Buffer.offset);
369  RtlCopyMemory(&_ServerIP, Packet + 20, sizeof(IP4));
370  return TRUE;
371 }
372 
374 {
375  static BOOLEAN Initialized = FALSE;
376  static BOOLEAN Success = FALSE;
377 
378  // Do initialization only once
379  if (Initialized)
380  return Success;
381  Initialized = TRUE;
382 
383  // Check if PXE is available
384  if (GetPxeStructure() && GetCachedInfo())
385  {
386  FsRegisterDevice("net(0)", &PxeDiskVtbl);
387  Success = TRUE;
388  }
389 
390  return Success;
391 }
392 
SEGOFF16 EntryPointSP
Definition: pxe.h:47
static ULONG _CachedLength
Definition: pxe.c:36
#define PXENV_TFTP_GET_FSIZE
Definition: pxe.h:591
static ARC_STATUS PxeSeek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
Definition: pxe.c:261
#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:25
#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:301
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:24
const DEVVTBL * PxeMount(ULONG DeviceId)
Definition: pxe.c:309
static ARC_STATUS PxeRead(ULONG FileId, VOID *Buffer, ULONG N, ULONG *Count)
Definition: pxe.c:218
_Inout_ __drv_aliasesMem PSLIST_ENTRY _Inout_ PSLIST_ENTRY _In_ ULONG Count
Definition: exfuncs.h:1015
static ULONG _OpenFile
Definition: pxe.c:29
static ULONG _PacketPosition
Definition: pxe.c:33
static const DEVVTBL PxeDiskVtbl
Definition: pxe.c:346
ULONG ARC_STATUS
Definition: arc.h:4
static ARC_STATUS PxeDiskSeek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
Definition: pxe.c:340
_In_ PVOID Parameter
Definition: ldrtypes.h:241
static ARC_STATUS PxeDiskGetFileInformation(ULONG FileId, FILEINFORMATION *Information)
Definition: pxe.c:322
static BOOLEAN GetCachedInfo(VOID)
Definition: pxe.c:354
Definition: arc.h:36
static ULONG _FilePosition
Definition: pxe.c:32
#define PXENV_GET_CACHED_INFO
Definition: pxe.h:597
BOOLEAN PxeInit(VOID)
Definition: pxe.c:373
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:35
UINT8 FileName[128]
Definition: pxe.h:354
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
static CHAR _OpenFileName[128]
Definition: pxe.c:30
#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:118
_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:334
UINT8 FileName[128]
Definition: pxe.h:316
#define TRACE(s)
Definition: solgame.cpp:4
static UCHAR _Packet[1024]
Definition: pxe.c:34
#define NO_FILE
Definition: pxe.c:26
static ARC_STATUS PxeDiskOpen(CHAR *Path, OPENMODE OpenMode, ULONG *FileId)
Definition: pxe.c:328
unsigned char UCHAR
Definition: xmlstorage.h:181
Definition: arc.h:34
VOID FsRegisterDevice(CHAR *Prefix, const DEVVTBL *FuncTable)
Definition: fs.c:383
SEGSEL segment
Definition: pxe.h:35
UINT16 PacketSize
Definition: pxe.h:318
static ARC_STATUS PxeDiskClose(ULONG FileId)
Definition: pxe.c:316
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:86
PRTL_UNICODE_STRING_BUFFER Path
static ULONG _FileSize
Definition: pxe.c:31
#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:138
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:39
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:153
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:73
static IP4 _ServerIP
Definition: pxe.c:28
FORCEINLINE VOID FrLdrTempFree(PVOID Allocation, ULONG Tag)
Definition: mm.h:186